203 Commits
Author SHA1 Message Date
vitorpamplonaandgithub-actions[bot] 8678c88db6 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-29 20:15:13 +00:00
davotoulaandgithub-actions[bot] d504e43924 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-29 14:58:05 +00:00
vitorpamplonaandgithub-actions[bot] 8d877ea70d chore: sync Crowdin translations and seed translator npub placeholders 2026-07-29 12:33:41 +00:00
vitorpamplonaandgithub-actions[bot] b575f9078d chore: sync Crowdin translations and seed translator npub placeholders 2026-07-29 03:56:46 +00:00
Vitor Pamplona 1bda3ab31b v1.13.1 2026-07-28 23:17:02 -04:00
davotoulaandgithub-actions[bot] 8ce93f3700 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-28 18:15:15 +00:00
vitorpamplonaandgithub-actions[bot] 8145bedd15 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-28 17:36:46 +00:00
davotoulaandgithub-actions[bot] e149f935e1 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-28 08:08:23 +00:00
vitorpamplonaandgithub-actions[bot] 99f0443a98 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-28 01:37:22 +00:00
Vitor Pamplona 70646f4609 adds gigi to changelog 2026-07-27 19:05:55 -04:00
Vitor PamplonaandClaude Opus 5 f55b3cb6d9 docs(changelog): tighten v1.13.0 highlights and audit against commits
Highlights carried full feature descriptions that the sections below
already repeated. Reduce each to a single line and fold the detail down
into the section that owns it.

Audit the notes against all 1961 non-merge commits since v1.12.6:

- Drop the claim that WebSocket frame dispatch moved to a dedicated pool.
  It landed in a5c2a8b2c1's parent and was reverted 23 minutes later
  because the pool regressed. Replace it with the two receive-path wins
  that did ship (CachingEventDecoder, ParallelEventVerifier).
- Add the chat redesign, which had no section at all: bubbles,
  swipe-to-reply, name colors, jumbo emoji, day headers, the two-stage
  long-press sheet, and the new-conversation chooser.
- Add in-app podcast authoring, which the Podcasts section omitted in
  favour of consumption only.
- Promote the resource-usage ledger out of a single Wallet line into its
  own section, alongside the background-service master switch and
  memory-pressure trimming.
- Add large-screen support, NIP-85 nicknames, Birdstar and PS1 cards,
  compose signature, Marmot group icons, and other unreferenced work.

Remove the Upgrading section. No prior release has one, and all three of
its items were consequences of features documented further down, so they
now sit with the feature that causes them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 19:03:09 -04:00
Claude 9df51641ea docs(changelog): split v1.13.0 fold-in notes into shorter sentences
Break the newly added BOLT12, Buzz Agent Work board, Blossom, Cashu,
NWC, search-indexing, and geode bullets into short verb-first sentences,
removing em-dash run-ons to match the changelog house style.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017hmbpUJPxrsN4m85Kwemcw
2026-07-27 21:06:24 +00:00
Claude 6c1412b7c9 docs(changelog): fold post-2026-07-24 work into v1.13.0 notes
Adds the BOLT12 payments & zaps (NIP-B1) work, the Buzz Agent Work
board / workflow runner, Concord message editing, the Blossom gallery
+ importer, Cashu P2PK-token claiming, NWC NIP-44/deep-link/notify
improvements, wider NIP-50 search indexing, and the geode release
pipeline + pluggable event store, plus assorted fixes. Credits dergigi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017hmbpUJPxrsN4m85Kwemcw
2026-07-27 20:55:39 +00:00
vitorpamplonaandgithub-actions[bot] 9855abda64 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-27 12:59:14 +00:00
vitorpamplonaandgithub-actions[bot] 6bf3c11173 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-26 21:18:45 +00:00
vitorpamplonaandgithub-actions[bot] f088dade41 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-25 13:44:35 +00:00
Claude fa2179ac19 docs(changelog): fold post-2026-07-20 work into v1.13.0 notes
Adds Buzz agent workspaces, the push-notification redesign, notifications
tab paging, desktop moderation & safety plus NIP-88 polls, DM report
warnings, Concord cold-boot/rank-gating fixes, SQLite search/relay
performance, amy git NIP-34 parity and amy buzz, the Buzz quartz protocol
surface, geode index work, and JVM 17 / CI / bidi build items.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018o1pqCDfqqSu2UHRPuqTK1
2026-07-24 15:50:08 +00:00
vitorpamplonaandgithub-actions[bot] db0ff71432 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-21 14:00:35 +00:00
Vitor PamplonaandClaude Opus 4.8 8913af7a79 fix(concord)!: enforce CORD-04 rank gating on the Banlist fold
Closes the privilege escalation: any BAN holder could ban the authorities above
them — including the owner — because the Banlist gate checked only the BAN bit.
Once banned, a member loses all authority (`hasPermission` is `!isBanned && ..`)
and honest clients drop their events, so a single edition from the most junior
moderator permanently silenced every admin above them.

CORD-04 §3 requires the rank half: "One hard rule binds every action: the actor
must hold the required bit and strictly outrank its target — equal cannot act on
equal (an admin cannot ban a peer admin)", restated as §5 step 3. Only §4, which
defines the Banlist, states the bit half alone — which is why both this client
and Armada shipped the same rank-blind gate.

§3 is stated per TARGET while the Banlist is one whole-list document, so it is
enforced as a DELTA rule: an edition may only add or remove npubs its signer
strictly outranks, judged against the roster settled behind it; the owner is
never a valid target (position 0 is "supreme and unremovable"); and entries the
signer may not act on are IGNORED rather than rejecting the edition, so one bad
entry cannot discard the bulk-ban §4 recommends as the collision remedy, and a
rogue cannot grief the list by forcing rejections.

ConcordModeration.currentBanned now reads the honored banlist through the
resolver instead of decoding the raw head. Besides picking up the fork healing
it was missing, this closes a laundering path: our own next ban/unban would
otherwise re-publish an entry our fold refuses, under our signature.

BREAKING (consensus): Armada has not shipped this rule, so banlists can differ
between clients until it does — we now ignore a ban Armada honors whenever the
signer did not outrank the target. Shipping the spec-conformant behaviour was
judged better than continuing to honor an escalation. Write-up to send upstream
is docs/concord-banlist-rank-conformance.md.

The three tests added in 0ae6bc6698 as @Ignore-d documentation now pass and are
un-ignored; two companions (a moderator still bans a plain member, the owner
still bans anyone) passed throughout and pin what the fix had to preserve.
Full :quartz:jvmTest and :commons:jvmTest suites green.

Still open and documented, not addressed here: a banned BAN holder can lift
their own ban (a fixpoint-ordering question that needs a spec ruling), and a
forked ban survives an unban that does not chain onto it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 12:53:11 -04:00
Vitor PamplonaandClaude Opus 4.8 ea6762b137 docs(concord): Banlist rank gap is a conformance bug, not a spec gap
Correcting the previous commit's reasoning. It concluded from the two
implementations that CORD-04 does not rank-gate the Banlist and that enforcing
it would be a unilateral divergence. Reading the actual spec
(github.com/concord-protocol/concord, not in the Armada repo) shows the
opposite: §3 is normative and binds "every action" — "the actor must hold the
required bit and strictly outrank its target — equal cannot act on equal (an
admin cannot ban a peer admin)" — and §5 step 3 restates it. Banning is the
example the rule itself picks.

Only §4, the section defining the Banlist, states the bit half alone. Both
independent implementations read §4 in isolation and made the same mistake,
which is evidence about the section rather than about the readers.

So the fold fix is spec-mandated. It remains consensus-affecting (we would
ignore bans Armada honors until they ship), so it wants coordination rather
than a race, and the fold is still unchanged here.

Adds docs/concord-banlist-rank-conformance.md to share upstream: verbatim spec
citations, both implementations' gates, a delta-based rule that makes the
per-target requirement expressible against a whole-list entity, and two further
reproduced findings — a banned BAN-holder can lift their own ban (so bans do
not stick against any BAN holder), and a forked ban survives an unban that does
not chain onto it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 12:05:21 -04:00
Vitor PamplonaandClaude Opus 4.8 996b800da5 docs(changelog): correct claims the code does not support
An audit of the v1.13.0 notes against the implementation found several
claims that are wrong or overstated. These are user-facing release notes,
so a false claim changes what people believe about their own security.

Corrected:

- **Privacy Lock.** The notes said it gates Messages "behind a password or
  biometric" on "Android and Desktop", with inactivity auto-lock and
  optional preview redaction. It does not exist on Android at all — no
  code, no settings entry — and there is no biometric implementation on
  any platform (`CredentialPrompter` has no implementations). Preview
  redaction persists a setting nothing reads, and the auto-lock is a fixed
  timer, since the idle-reset modifier is never applied. It is also a
  screen gate rather than encryption at rest: the account stays live and
  messages keep syncing while locked. Now described as what ships — a
  password gate on the Desktop Messages and Wallet columns.
- **"Every signature, payment, or data read needs your explicit
  approval."** Only payments require per-use consent; everything else can
  be granted once and reused, and the default trust level auto-signs notes,
  reactions and encryption after a single tap.
- **Web of Trust (GrapeRank)** was listed under app features, but crawling
  and scoring exist only in the `amy` CLI — no app module references it.
  The app consumes NIP-85 cards published by an operator, which is what the
  entry now says.
- **"One-tap trust for your follows' relays"** described bulk-granting
  relays used by people you follow. What exists is category rules evaluated
  per challenge.
- **Pinned web apps "show the app's own icon"** — they render a generic
  placeholder.
- **PoW** contradicted itself: "all cores" in one entry, "half the device's
  cores" in another. The latter matches `PoWPolicy.minerWorkers`.
- **Onion-Location "through every HTTP client"** — the Android app's
  clients only; the desktop, CLI, geode and sandbox blob clients don't
  install it.
- **Relay hardening** claimed REQ refusals stop immediately and failures
  evict "on the first strike"; both take repeated failures, and the
  first-strike eviction applies only to crawls.
- **`bunker://` links cannot be pasted in** — Amethyst only emits them.
- **Git code browser** needs a repository with an http(s) clone URL.
- **Geohash anonymous identity** — the per-area identity is unlinkable, but
  the optional nickname is one global handle, so setting it links your
  posts across areas.
- **Concord ban** is read-time enforcement for everyone else; the banned
  member keeps the keys until a Refounding.

Adds an Upgrading section for the user-visible effects of the per-account
isolation work: sites signed out once, permissions re-asked per account,
and relay logins now prompting under the default remote-signer policy.

Contributor and translator credits are left as they are — several entries
are unresolved npubs and Crowdin-generated usernames, but correcting
attribution is not a call to make from the code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 19:52:52 -04:00
Claude fb730d7ea8 docs(changelog): add v1.13.0 release notes
Add docs/changelog/v1.13.00.md — the v1.13.0 "Web Apps, Communities & Git"
release notes — and link it at the top of the changelog index.

Covers the full v1.12.6..HEAD range: the in-app Browser and NIP-5D/5A web
clients, Concord communities, NIP-34 git collaboration, Location Channels, the
NIP-46 Remote Signer and Privacy Lock, NIP-42 relay login permissions, NIP-29
Groups, the redesigned Messages inbox, Blossom file sync, Podcasting 2.0,
proof-of-work (NIP-13), negentropy (NIP-77), GrapeRank, accent theming, and the
Desktop, amy CLI, Quartz, and Geode work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrPNt4FchqArpMtAHHfqGi
2026-07-19 19:06:03 +00:00
vitorpamplonaandgithub-actions[bot] 9fb3603ed6 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-18 14:24:00 +00:00
vitorpamplonaandgithub-actions[bot] cbcb8d42ba chore: sync Crowdin translations and seed translator npub placeholders 2026-07-17 21:49:24 +00:00
davotoulaandgithub-actions[bot] f28b6381e3 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-17 19:26:39 +00:00
davotoulaandgithub-actions[bot] c7d4a72a34 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-17 07:57:11 +00:00
vitorpamplonaandgithub-actions[bot] 9d0cc8ad56 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-16 13:40:26 +00:00
vitorpamplonaandgithub-actions[bot] 01fbc34e5e chore: sync Crowdin translations and seed translator npub placeholders 2026-07-16 01:32:20 +00:00
vitorpamplonaandgithub-actions[bot] 65d16d185b chore: sync Crowdin translations and seed translator npub placeholders 2026-07-15 21:25:50 +00:00
vitorpamplonaandgithub-actions[bot] 6139923561 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-15 20:10:21 +00:00
Vitor PamplonaandGitHub f59b1e5c52 Merge pull request #3567 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-07-15 09:20:12 -04:00
vitorpamplonaandgithub-actions[bot] 46f0a84f80 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-15 12:16:57 +00:00
nrobi144andClaude Opus 4.8 3f56d177d8 feat(desktop): note scheduling + NIP-37 opt-in draft sync
Adds note scheduling and NIP-37 opt-in encrypted draft sync to Amethyst
Desktop, and extracts the existing Android scheduled-post code into
`commons` so both platforms (and PowJobRestorer) share one implementation.

- Compose → clock icon → date/time picker (presets + exact-minute); the
  note is pre-signed and stored locally, then published at its time.
- Publishes while the app is open (45s in-app tick + launch catch-up) AND
  while fully closed: an OS job (launchd / schtasks / systemd, registered
  only while the queue is non-empty) relaunches the binary in a headless,
  key-free `--publish-scheduled` mode that opens a websocket and pushes the
  pre-signed bytes.
- A "Scheduled" deck destination (tabs Scheduled / Drafts / Articles):
  status, cancel, publish-now, edit (cancel + reopen prefilled).
- Drafts: save-as-draft with a default-OFF "Sync across devices
  (encrypted)" toggle publishing a NIP-37 DraftWrapEvent (kind 31234,
  NIP-44 to self); drafts sync down on a fresh device.

Extraction / de-dup: ScheduledPost → commons/commonMain; ScheduledPostStore
+ ScheduledPostPublisher → commons/jvmAndroid (Jackson/java.io.File are
gate-forbidden in commonMain). The commons store is a strict superset of
upstream's parallel Android store (account-scoped claim, CLAIM_TTL crash
recovery, PUBLISHING-only status guards, reload-before-claim); upstream's
new ScheduledPostWorkGate gating is adopted to drive it. Single-writer file
lock + reload-before-claim so the in-app timer and headless process never
double-publish. Store file 0600, dir 0700.

macOS verified on the packaged app-image (compose+schedule, in-app publish,
app-closed launchd firing, Scheduled screen, NIP-37 draft round-trip).
Windows/Linux OS-integration authored but untested; headless has no Tor
routing yet — both documented in the PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 11:26:12 +03:00
davotoulaandgithub-actions[bot] 8e46714fca chore: sync Crowdin translations and seed translator npub placeholders 2026-07-12 20:06:46 +00:00
vitorpamplonaandgithub-actions[bot] 757f348a46 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 15:04:41 +00:00
davotoulaandgithub-actions[bot] 2edb22783c chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 14:32:20 +00:00
davotoulaandgithub-actions[bot] cc275ce62d chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 10:47:38 +00:00
vitorpamplonaandgithub-actions[bot] 835f1e5e85 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-11 03:16:54 +00:00
vitorpamplonaandgithub-actions[bot] 085b4d7dc0 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-10 17:06:25 +00:00
nrobi144andClaude Opus 4.8 fe96311d93 test: record 2026-07-09 live run results + fix macOS prefs path in sheet
- Correct the AUTH-approval persistence check: this JVM uses
  MacOSXPreferences (~/Library/Preferences/com.vitorpamplona.amethyst.plist),
  not ~/.java/.userPrefs. Updated T3.b/c/d to read it via plutil.
- Record session results (T1,T2,T3a,T3c,T6,T6b,T8,T12 pass) and the three
  bugs found+fixed during the run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 15:43:03 +03:00
nrobi144andClaude Opus 4.8 abe4668fd8 test: add T6b strict kind:10050 non-leak scenario; refresh sheet header
Covers the review fix — recipient with NIP-65 read relays but no
kind:10050 must be treated as unreachable, not routed to the read relays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 07:56:42 +03:00
nrobi144andClaude Opus 4.8 9e707da2b1 fix(desktop): use strict kind:10050 in DM inbox resolver LocalCache fast-path
The indexer fan-out already used lists.dmInbox (strict), but the
LocalCache fast-path in DmInboxRelayResolver.resolve() — and the
no-resolver fallback in DesktopIAccount — went through the lenient
User.dmInboxRelays(), which falls back to NIP-65 read relays (kind:10002)
when the recipient has no kind:10050.

Because that fast-path returns first and short-circuits the strict
indexer lookup, a recipient with NIP-65 read relays but no published
DM-inbox would get gift wraps published to relays they never designated
for DMs — re-introducing the metadata leak (recipient pubkey + send
timing) the P0 fix was meant to close. LocalCache commonly holds
kind:10002 but not kind:10050, so this path fired often.

Switch both LocalCache lookups to dmInboxRelaysStrict().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 07:45:34 +03:00
nrobi144 33417d8a58 test: unpack testing sheet into linear playbook
Rewrites the manual testing sheet so every step is an executable action
or a specific observation:

- Numbered steps within each test — no jumping between reference
  sections. "Click X", "run Y in a terminal", "watch for Z".
- Each observation records YES/NO/SKIPPED for the sign-off matrix.
- Setup section spells out the wipe-preferences command and the
  post-restart smoke check.
- T3 broken into T3.a/b/c/d for each button and its persistence
  check separately (previously bundled T3.1–T3.10 was too dense).
- T6/T7 include exact tcpdump/tshark commands for the security
  observations that require packet capture.
- T13 shortened to a sanity re-check (already verified).
- Sign-off table lists every test with a checkbox.

Purpose: give the tester a self-contained document they can follow
top to bottom in ~40 min without cross-referencing other sheets.
2026-07-09 07:33:43 +03:00
nrobi144 0fc9b8a87d test: consolidate manual testing sheet, add T13 pre-send fix coverage
Updates the manual walkthrough to reflect the full state of the branch
after rebase + banner padding fix + pre-send validation fix:

- Marks what's already verified (T1 startup wiring, T5 lifecycle,
  T6 P0 security via upstream UI, T13 pre-send fix).
- Adds T13 covering the alignment + resolver-probe fix from
  a139c0fb17 with three sub-scenarios (strict alignment, resolver
  unblock, and the real 2-user bootstrap flow).
- Documents the known pre-existing issues surfaced during testing
  (RelayLatencyTracker CME, CompressionQuality stale-daemon) so
  they don't get filed as regressions of ours.
- Adds a summary table pointing to the automated sheet for the
  Phase A greens.
- Explicit out-of-scope list mirroring the deepening synthesis.

No code changes — documentation only.
2026-07-09 07:33:43 +03:00
nrobi144 68d1276b1a test: testing sheet for feat/desktop-dm-reliability
Captures every verification step for the 16-commit branch:
  §A  automated — compile + unit tests + spotless + package + branch
      integrity. All passing as of 2026-06-12.
  §B  manual desktop — AUTH end-to-end (tier-1 + tier-2), banner UX,
      NIP-17 send security, indexer fan-out, group DM rumor coherence,
      relay-hint placement, outbox AUTH carve-out, bunker concurrency
      cap, SigningOpState.Progress.
  §C  Android sanity — commons inheritance check.
  §D  security audit — code/git inspection (D1 all passing), threat
      walkthrough (D2).
  §E  sign-off matrix.

Includes a known-gap callout for D2.2 (logout does NOT clear AUTH
approvals — by design; account-delete is the trigger, follow-up
verification needed) and an out-of-scope list mirroring the
deepening synthesis (retry queue, per-message bubble UI, NIP-46
batch RPC, Android UI parity).
2026-07-09 07:33:42 +03:00
vitorpamplonaandgithub-actions[bot] 61507acdd7 chore: sync Crowdin translations and seed translator npub placeholders 2026-07-08 21:32:24 +00:00
Vitor PamplonaandGitHub 0ff48cfbe0 Merge pull request #3483 from nrobi144/feat/wot-shared-index-relays
feat(desktop): Web-of-Trust score badges + shared index relays + amy wot verbs
2026-07-08 12:53:08 -04:00
Vitor PamplonaandGitHub 50ce22e49e Merge pull request #3495 from nrobi144/feat/desktop-wallet-privacy-lock
feat(desktop): apply the privacy lock to the Wallet column
2026-07-08 12:52:54 -04:00
nrobi144 1e076c5cc2 feat(desktop): apply privacy lock to the Wallet column
Extends the messaging privacy lock to the Wallet deck column via the
same master `lockEnabled` flag (single toggle, single password) with
per-scope lock state so each route re-locks independently.

commons/ui/privacylock/
  LockScreen.kt        Shared internal composable (scope + copy)
  WalletLockGate.kt    Mirrors MessagesLockGate for scope=Wallet
  MessagesLockGate.kt  Shrunk to a 20-LOC wrapper delegating to LockScreen

desktopApp/security/
  DesktopLockScreen.kt         Shared password-input surface with optional
                               "No password set" deep-link (plan Q5).
  DesktopMessagesLockGate.kt   Now delegates to DesktopLockScreen
  DesktopWalletLockGate.kt     New; deep-links to Settings via
                               onNavigateToRelays when no password is set
  WalletFirstRunBanner.kt      Mirrors MessagesFirstRunBanner; both read
                               the single firstRunCardSeen flag (dismiss
                               once = dismissed everywhere)
  MessagesFirstRunBanner.kt    Copy updated: "Lock Messages and Wallet?"
  PrivacyLockBlurModifier.kt   Modifier.privacyLockBlurWhenUnfocused()
                               reads LocalWindowInfo.isWindowFocused;
                               applied to text nodes only (balance,
                               generated-invoice amount, QR code) — cards
                               and layout stay crisp (plan Q4).

desktopApp/ui/
  wallet/WalletColumnScreen.kt Inserts WalletFirstRunBanner at top;
                               wraps sensitive text with blur modifier.
  deck/DeckColumnContainer.kt  Wraps Wallet branch with
                               DesktopWalletLockGate; passes
                               onNavigateToRelays so the "No password"
                               branch deep-links to Settings.
  settings/PrivacyLockSettingsScreen.kt
                               Master-lock copy: "Enable privacy lock"
                               header; body mentions Messages AND Wallet
                               columns; auto-lock + caveat cards updated
                               to reference both routes.

Testing sheet: docs/plans/2026-07-07-wallet-lock-manual-testing.md
  12 manual scenarios covering cross-scope lockout, blur-on-unfocus,
  password-clear cascade, deep-link to Settings, and first-run banner
  parity across the two routes.

All existing PrivacyLockStateTest cases green + the 3 Wallet-reuse
tests from the previous commit. amethyst + desktopApp compile clean.
2026-07-07 13:33:32 +03:00
nrobi144 d0daf786b1 feat(commons): scope-parameterise PrivacyLockState for multi-route lock reuse
Genericises the messaging privacy-lock state holder so a single master
`lockEnabled` flag can drive multiple gated routes independently:

- `LockScope { Messages, Wallet }` enum added.
- `MessagesLockState` → `PrivacyLockState(scope, settings, coroutineScope)`.
  Each scope keeps its own StateFlow<LockState> + idle-timer Job; both
  scopes share the same `PrivacyLockSettings` so failed-attempt counters
  and lockout schedule stay device-global (brute-force protection).
- `LocalMessagesLockState` (single instance) → `LocalPrivacyLockState`
  (Map<LockScope, PrivacyLockState>) + `lockStateFor(scope)` accessor.
- `redactionLevel` → `dmRedactionLevel` (Kotlin-side rename; persisted
  prefs key `redaction_level_ordinal` unchanged).
- `setPasswordHashed(null)` cascades to `setLockEnabled(false)` so a
  master lock cannot stay armed without a credential to verify against.

MessagesLockGate, DesktopMessagesLockGate, MessagesFirstRunBanner,
SetPasswordDialog, and RedactionCard now read `lockStateFor(Messages)`
— behaviour-preserving. Ships 3 new PrivacyLockStateTest cases:
independent per-scope state, shared failed-attempt counter, and the
password-clear cascade.

Plan: docs/plans/2026-07-07-feat-wallet-privacy-lock-reuse-plan.md
2026-07-07 13:18:56 +03:00