setup.ts is now UI-only: deletes all direct WASM orchestration (loadWasm,
the wasm binding, verifiedHandle, the SessionHandle import). Vault creation
and attach go through sendMessage({type:'create_vault'|'attach_vault'}) fired
from the device step (where the device name is known); the SW owns the entire
crypto+remote+device flow. The six renderStepN/attachStepN pairs collapse into
the SetupStep registry (mode/host/connection/vault/device/done). The done step
drops the now-redundant register-device + copy-JSON paths, keeping reference
download + recovery QR (off the SW session) + open-vault. clearWizardState
zero-fills sensitive Uint8Array fields on beforeunload and on goto('mode').
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same shape as create_vault: the SW owns the attach flow end to end -- fetch
salt/params/manifest from the remote, unlock with the user's reference image,
manifest_decrypt to verify the passphrase+image, register this device, persist
config + reference image, and transition the SW to the unlocked state. On
failure the handle is locked then freed; ownership transfers to the session
only on success.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lifts the full create-vault flow out of setup.ts into the SW: embed image
secret, unlock, encrypt empty manifest + default settings, push the vault
layout (create-only), register this device + write devices.json, persist
config + reference image locally, and transition the SW to the unlocked
state (handle becomes SW-owned, enabling recoveryQrAvailable). On failure
the handle is locked then freed per Plan A's .free() policy; ownership only
transfers to the session on success.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the request shapes + response interfaces. POPUP_ONLY_TYPES set grows
by three. SW handlers in service-worker/vault.ts land in the next tasks.
The new union members would make popup-only.ts's exhaustive handle() switch
non-total (TS2366), so a default case is added returning an explicit
"unhandled popup message" error. create_vault/attach_vault get real cases
in Tasks 3.2-3.3; get_vault_status in Dev-C's Phase 6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a "Release lifecycle" section to CLAUDE.md that makes the release
workflow the canonical way to develop, debug, verify, and tag — for both
single-agent (phone/remote) and multi-agent (supervised, tmux) modes.
Updates the planning section to route plan execution through the workflow
rather than directly to subagent-driven-development or executing-plans.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds dev-d, dev-e, dev-f to Role type, KNOWN_ROLES, RelayQueue map,
and all three MCP tool enums in server.ts. Updates the isRole test
to assert the new roles are valid and dev-g is still rejected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 commits landing 5 independent P2 fixes:
- ba5d218 inactivity timer resets on all non-passive messages (READ_ONLY_CONTENT_CALLABLE exclusion set in session-timer.ts; index.ts inverts the gate)
- 35444e0 state.gitHost cleared on session expiry (alongside state.manifest)
- e43f121 teardownSettingsCommon extracted; both settings.ts + settings-vault.ts call it (parameterized over each file's own activeKeyHandler module variable)
- 39fac68 Promise.allSettled with per-slot fallback in devices.ts (list_devices+list_revoked + sshFingerprint map). trash.ts is a no-op on this branch — it doesn't have a Promise.all to migrate (single list_trashed call); plan was written against a different snapshot.
- fce1962 MutationObserver scan() debounced to 200ms in content/detector.ts (no test harness on this branch — manual verification per plan note)
377/377 vitest tests pass (baseline 371 + 6 new tests in session-timer + devices). Zero regressions.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: SPA churn was re-running the full scan many times per second.
Trailing-edge debounce coalesces bursts so scan() runs at most once per
quiet 200ms window.
No test harness exists for content/detector.ts on this branch; relies
on manual verification on a real SPA page.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1.6 closed: shared/state.ts is type-checked end to end. StateHost
interface defines every field; double-registration throws; vitest gets
__resetHostForTests to break inter-test leakage. View + PopupState moved
to shared/popup-state.ts (broke the popup→shared circular-dep blocker).
PopupState widened to absorb VaultState's vault-tab-only fields (unlocked,
drawerOpen, typePanelOpen) with optional + commented justification, so the
two surfaces share one typed contract.
378/378 vitest tests pass (baseline 371 + 7 new state.test.ts cases).
Phase 5 still running in parallel. Cross-stream note from Phase 1 subagent:
settings.ts was not touched here, so Phase 5's teardownSettingsCommon
extraction rebases cleanly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: Promise.all meant one rejected RPC failed the whole render.
allSettled + per-slot fallback keeps the active-devices surface usable
when the revoked-list feed (or one bad ssh fingerprint) is down.
Two call sites converted in devices.ts:
1. list_devices + list_revoked pair — revoked failures now render an
inline "couldn't load" slot instead of failing the page.
2. sshFingerprint map — one bad public key falls back to '(unknown)'
instead of killing the whole device list.
trash.ts only has a single sendMessage in its load path on this branch,
so it has no Promise.all to migrate. Plan was written against a slightly
different snapshot; documented divergence in report.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Removes the re-export shim from popup/popup.ts now that all callers point
at the canonical shared/popup-state. No external callers were depending on
the popup.ts re-export, so this drop is a strict tightening.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the previously any-typed StateHost contract with a typed interface.
Adds double-registration guard and __resetHostForTests for vitest.
sendMessage wrapper is currently a pass-through; Phase 4 will fill its body
with the vault_locked intercept lifted from vault.ts.
Widens PopupState/View on shared/popup-state.ts to cover vault-tab-only
views (history, backup, import) and vault-tab-only fields (unlocked,
drawerOpen, typePanelOpen) so VaultState satisfies StateHost.getState()
without a cast. The popup surface ignores the new optional fields.
Drops the `any` annotations on vault.ts's registerHost callbacks now that
the typed StateHost contract infers them from PopupState.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1.9 dedup landed: loadDeviceSettings, saveDeviceSettings, loadBlacklist,
saveBlacklist all live in service-worker/storage.ts; itemToManifestEntry
in service-worker/vault.ts. Both router files import from one home each.
popup-only.ts shrank 727 → 690 LOC; content-callable.ts shrank 204 → 171.
376/376 vitest tests pass (baseline 371 + 5 new storage.test.ts cases).
Phases 1 + 5 still running in parallel in their own worktrees.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: settings.ts:56-65 and settings-vault.ts:15-22 had near-
identical cleanup paths. Single source for closeGeneratorPanel +
activeKeyHandler removal. Helper takes the handler as a parameter and
returns null so each caller still owns its own module-scoped handler
state.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1.9: loadDeviceSettings / loadBlacklist / saveBlacklist / saveDeviceSettings
+ itemToManifestEntry were duplicated across popup-only.ts and
content-callable.ts. Lifts the four storage helpers into service-worker/
storage.ts and itemToManifestEntry into service-worker/vault.ts.
Both router files now import from one home each. Adds storage.test.ts
covering round-trips and defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: expiry cleared manifest but left the cached git-host client.
The initializer rebuilds gitHost on demand, so clearing here is safe.
No new test: index.ts has top-level chrome.* side effects that make it
expensive to import in a unit test, and the change is a one-liner state
mutation in an inline callback. Manually verified by tracing call sites.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DEV-C P2: an active autofiller never opens the popup, so under the old
rule it got force-locked despite continuous use. Inverts the rule:
reset on all messages except a documented exclusion set (only
get_autofill_candidates today).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Foundation for Plan C Phase 1: shared/state.ts (next task) needs to import
PopupState without creating a popup->shared circular dep. popup.ts now
re-exports from the new location so existing callers don't break in this
task. Task 1.4 will sweep them onto the canonical import path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
24 tasks across 6 phases derived from the 2026-05-04 extension restructure
spec. Per-task bite-sized steps (TDD where new behavior, verify-existing-
tests where pure relocation) with explicit file/line citations and full
code snippets.
Phase 1 (StateHost typing, S-M, blocks 3+4): 5 tasks
Phase 2 (storage.ts + itemToManifestEntry, S): 3 tasks
Phase 3 (setup wizard SW migration + step registry, L): 7 tasks
Phase 4 (vault.ts split into 5 modules + vault_locked lift, M): 7 tasks
Phase 5 (P2 cluster: timer/gitHost/teardown/allSettled/debounce, M): 5 tasks
Phase 6 (get_vault_status + sidebar status indicator, S-M): 3 tasks
Task 7.1 (final verification sweep against spec Done criteria).
Recommended sequence: 1 → 2 → 5 → 4 → 6 → 3 (independents first, then
the typed-StateHost-dependent phases, then Phase 3 last because it's the
biggest single phase and benefits from all the supporting infra in
place). Max subagent parallelism: 3 streams.
Cross-plan: explicit out-of-scope notes for Plan A (security/docs polish,
already shipped) and Plan B (CLI restructure, already shipped). The
wasm.d.ts file is not touched by this plan (verify empty diff at done).
STATUS + ROADMAP updated to point at the plan.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Post-v0.6.0 spot-check of the three 2026-05-04 architecture-review
specs (per CLAUDE.md rule #4) confirms:
- CLI restructure: shipped as Plan B Cycles 1+2 (b9bd152, 3dd1e1b,
3759f6a, e69b347). Last gap (read-side refresh_groups_cache
callers) closed in d717f0d. Done-criteria all met.
- Security polish: shipped as Stream A Cycle 1 (89090a8) plus
follow-ups for start.sh fourth window (0c9387f) and recovery_qr.rs
docs (229e483). All four phases done.
- Extension restructure: genuinely outstanding. vault.ts is 1037 LOC
(criterion ~200); the five-module split has not happened; setup.ts
still imports relicario-wasm directly; shared/state.ts still has
any-typed StateHost; SW router helpers still duplicated; CLI parity
gap (relicario status) still open. Effort estimate: L.
Removes the incorrect "subcommand reorganization, interactive TUI
mode" descriptor — the original CLI restructure spec is about file
structure, not TUI or renames. The TUI descriptor was a roadmap
mis-paraphrase, not a real outstanding item.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Plan B Phase 4 wanted "every mutating handler must call
refresh_groups_cache" to be a compile-time invariant, with all
callers funneled through Vault::after_manifest_change. The
mutating-handler sweep happened, but two read-side callsites
(commands/list.rs and commands/get.rs) still called the public
helper directly for opportunistic shell-completion cache freshness.
Closes the gap:
- helpers::refresh_groups_cache demoted from pub to pub(crate).
- list.rs and get.rs drop their explicit calls. Cache freshness
between mutations is unaffected: every mutating handler still
funnels through after_manifest_change. The minor staleness
window (manifest changed externally via git pull, no local
mutation since) is the trade-off the spec accepts in exchange
for the compile-time invariant.
The Plan B done-criterion "grep refresh_groups_cache outside
session.rs returns zero" now passes apart from the function
definition itself, which lives in helpers.rs (the natural place
for a flat utility). The visibility scoping achieves the
architectural intent.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The router migrated from generate_device_keypair → register_device
(returns signing_public_key + deploy_public_key with private keys
staying internal to WASM). Test still mocked the old function under
the old return shape (public_key_hex / private_key_base64), so the
router's state.wasm.register_device() call failed with
"is not a function".
Updates the mock function name, response shape, and assertion to the
current contract. Test intent (treat the WASM return as a JS object,
not a JSON string) is preserved.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tests were written against the pre-Stream B flat settings page. After
the left-nav restructure (bd6a301) and the management-surfaces revamp,
the Display section's IDs are only in the DOM once the user navigates
there, and renderSettings makes additional sendMessage calls (is_unlocked,
per-section data) that the original mocks didn't cover.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tests predated the 2026-05-24 management-surfaces revamp (047df6e): popup
devices pane now shows SHA-256 fingerprint + added-by + inline two-step
revoke confirm, and the SW revokeDevice signature may have shifted to
match. Mocks + assertions updated accordingly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three commits landed since the prior sync (72a59c6) that should be
reflected here:
- cccb7d7 rule #4 + doc-structure plan ticks
- 39ae629 vault lock-screen logo
- (this commit)
Moves the doc-structure redesign from "in progress" to "complete"
(Task 5 verified clean), drops the lock-screen logo from in-flight,
and trims Up next to the four genuinely-outstanding items: tag cut,
CLI restructure, extension restructure, security polish.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors the logo-lockup treatment already used in the popup unlock view
(Phase 2B) and the setup wizard. Lock-screen rendering now shows the
relicario-logo.svg above the wordmark instead of just the wordmark.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rule #4 codifies the discipline that prevents the kind of drift the
2026-05-30 status-audit found: Phase 2B, v0.5.1 Streams A/B/C, and 1C-γ
all stealth-shipped 2-3 weeks earlier with their plan checkboxes never
ticked and STATUS.md still listing them as "Up next".
Two halves to the rule:
- Ship side: ticking the boxes is part of shipping. A commit that lands
plan work also ticks that plan's boxes (or an immediately-following
docs commit does).
- Execute side: before starting an unchecked plan, spot-check git log
for distinctive symbols/files — re-executing already-merged work is
the worst failure mode of the drift.
Also applies the rule retroactively to the doc-structure redesign plan:
all 37 sub-step checkboxes flipped to [x]. Tasks 1-4 (rename, scope
headers + Next: footers, link fixes, CLAUDE.md table) shipped in
36a59cd..bae3f7c. Task 5's six verification steps all pass (Step 3's
grep matches are false positives — they're correct new-path sibling
links from inside docs/ to docs/, not stale old-path uses).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The 2026-05-30 sync commit (fa659eb) only covered the vault-tab
management surfaces revamp. It missed three earlier merges that landed
2026-05-02..05-03 and have been on main since:
- Phase 2B polish foundation + form layout (5da1e52, 2026-05-02)
- v0.5.1 Stream A — 3-column vault layout + bottom sheet + toast +
GLYPH_VAULT_TAB + emoji sweep (c16adc4, 2026-05-03)
- v0.5.1 Stream B — left-nav settings (Autofill / Display / Security /
Generator / Retention / Backup / Import) (bd6a301, 2026-05-03)
- v0.5.1 Stream C — Recovery QR end-to-end (core + WASM + CLI +
settings-security.ts + setup wizard banner) + setup wizard Style C
redesign (934dfe0, 2026-05-03)
Also missing: 1C-γ (attachments + Document type + device registration
+ trash + history), Plan B multi-stream refactor (Cycles 1+2), and
the in-flight doc-structure redesign Tasks 1-4 (commits 36a59cd..bae3f7c
since spec 3209bfb).
STATUS now lists each train with merge SHA, spec/plan pointers, and
per-feature bullets. ROADMAP's "Up next" / "Medium-term" / "Long-term"
sections retrimmed: the only genuinely outstanding work is doc-structure
Task 5 verification, the lock-screen logo, the v0.5.x tag, and the
three 2026-05-04 architecture-review specs (CLI restructure, extension
restructure, security polish — none have plans yet).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Table row labels now reference DESIGN.md / docs/CRYPTO.md /
docs/FORMATS.md. Adds three new discipline rules attacking the
structural causes of the 2026-05-30 drift audit findings:
1. Scope-boundary check — content goes in the doc whose scope
header claims it; if it doesn't fit, move it instead of
stretching the header.
2. Code-constant pinning — docs that cite code constants must
cite source file + line; constant changes update doc and
code in the same commit.
3. New-doc rule — adding a tour doc also requires updating
DESIGN's code-map, the Next: footer chain, and this table.
Spec: docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md
Rewrites every markdown reference to the old paths:
- ARCHITECTURE.md → DESIGN.md
- docs/ARCHITECTURE.md → docs/CRYPTO.md
- FORMATS.md → docs/FORMATS.md
Touches CLAUDE.md (living-docs table + planning-references list),
per-crate ARCHITECTURE.md cross-refs, and any specs in
docs/superpowers/specs/ that referenced the old paths. Audit
history and test-run logs intentionally left untouched.
Spec: docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md
Each of the eight tour docs (README, DESIGN, docs/CRYPTO,
docs/FORMATS, docs/SECURITY, crates/relicario-core/ARCHITECTURE,
crates/relicario-cli/ARCHITECTURE, extension/ARCHITECTURE) now
declares its scope in a blockquote under its H1 and ends with a
single-line "Next:" pointer to the next doc in the canonical
reading order: README → DESIGN → CRYPTO → FORMATS → SECURITY →
core → cli → extension.
Also trimmed README's mid-section "Architecture" stub to a one-
paragraph pointer at DESIGN.md (was duplicating cross-codebase
content and referencing a non-existent docs/architecture/ tree).
Renamed docs/CRYPTO.md's H1 from "Relicario — Architecture" to
"Relicario — Crypto Pipeline" to match the file's renamed scope.
Spec: docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md
Five sequential tasks, one commit each, all mechanical:
1. git mv the three doc files
2. add scope headers + Next: footers to the eight tour docs
(also trim README architecture stub)
3. fix incoming links to old paths
4. update CLAUDE.md table + add 3 discipline rules
5. verification gate
Spec: docs/superpowers/specs/2026-05-30-doc-structure-redesign-design.md
Proposes renaming the three overlapping ARCHITECTURE.md files into
topic-named docs (top-level → DESIGN.md, docs/ARCHITECTURE.md →
docs/CRYPTO.md), moving FORMATS.md into docs/, and adding scope
headers + "Next:" footers to every tour doc so the reading order is
canonical: README → DESIGN → CRYPTO → FORMATS → SECURITY →
per-crate ARCHITECTURE → extension/ARCHITECTURE.
Direct response to the drift audit run earlier today (the audit's
content fixes already landed in 210232d, cf7478d, fa659eb). This
spec attacks the structural causes: name collisions, no scope
boundaries, no reading-order signposts, root/docs/ asymmetry.
Migration is mechanical — 5 sequential commits, no content rewrites:
rename, headers+footers, link-fixes, CLAUDE.md update, verification.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Punch items from doc audit:
- STATUS: "in progress" section was carrying ghost items (vault
container max-width, README name fix) with no matching commits or
working-tree changes; trimmed to the one real in-flight item.
- STATUS + ROADMAP: trash/history/devices/settings management-surfaces
revamp shipped 2026-05-24..05-30 (commits c943a06..88d7228) but was
still listed as "up next" / medium-term; moved to shipped with
per-commit SHAs.
- STATUS: v0.5.0 was described as the current tag, but only v0.2.0 and
four plan-1* tags exist; rephrased as "v0.5.0 train on main, untagged".
- ROADMAP: "Vault lock screen + container polish (in progress)"
collapsed to just the lock-screen logo (the only real in-flight item).
- extension/ARCHITECTURE: module map missing four shipped components —
popup/components/form-header.ts, popup/components/settings-security.ts,
vault/components/backup-panel.ts (#backup route),
vault/components/import-panel.ts (#import route); all added with
matching #backup / #import route entries.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Punch items from doc audit:
- relicario-core: module map missing 5 public modules (backup,
device, import_lastpass, recovery_qr, tar_safe); added with
1-2 sentence descriptions in the existing voice.
- relicario-core: "ed25519-dalek is a dependency placeholder" was
stale — device.rs now consumes it for signing/verify/keypair.
- relicario-cli: Rate (zxcvbn scoring) and RecoveryQr (generate/unwrap)
commands were absent from Key flows; added.
- relicario-cli: "Backup-passphrase-style commands (none yet)" rewritten
— Backup (export/restore .relbak) and Import (lastpass) both shipped.
- relicario-cli: module map refreshed — handlers moved out of main.rs
into commands/, plus prompt.rs/parse.rs/device.rs/gitea.rs surfaced.
Stale main.rs:NNNN line citations on individual flows are not fixed
here — those handlers now live in commands/*.rs and warrant a deeper
pass later.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Punch items from doc audit:
- docs/ARCHITECTURE.md: encrypted file format diagram said version byte
0x01; actual VERSION_BYTE is 0x02 (crypto.rs:59) and 0x01 is rejected
with UnsupportedFormatVersion.
- docs/ARCHITECTURE.md: DCT embedding diagram said "Repeat secret 20+
times" and "positions 4-15"; actual is MIN_COPIES (5) to 50 copies
chosen by capacity, embedded in zig-zag positions 6-17
(imgsecret.rs:78, 99-104, 530-537).
- FORMATS.md: AttachmentId table said 16 hex chars / 8 bytes; actual is
32 hex chars / first 16 bytes of SHA-256 (ids.rs:59-69).
- FORMATS.md: ManifestEntry schema missing r#type field; updated to list
all ten fields in declared order with serde decorations noted
(manifest.rs:21-38).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>