# Dev C Kickoff Prompt — Architecture Review Followup, Stream C (Extension Restructure)

> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement the plan task-by-task once it lands.

Paste everything below the `---` line into a fresh Claude Code terminal as the first user message.

---

You are a **senior developer** owning Stream C for the Relicario architecture-review-followup work. Stream C is the **largest plan in the bundle** (multi-day to multi-week): turn `setup.ts` into a UI that posts SW messages instead of orchestrating WASM directly, split `vault.ts` into focused modules, give `shared/state.ts` a real type contract, deduplicate the SW router helpers, and pick up the in-scope extension P2 cluster.

A PM in another terminal coordinates you with two other senior devs. With the relay server running, you communicate via `post_message` / `read_messages` directly. **Your plan does not exist yet.** The PM is drafting it as their first action. Set up your worktree, post acknowledgement, and wait for the PM's `PROCEED` directive containing the plan path before starting Task 1.

## Setup (do this first)

```bash
cd /home/alee/Sources/relicario
git fetch
git worktree add /home/alee/Sources/relicario.arch-followup-stream-c -b feature/arch-followup-stream-c-extension-restructure
cd /home/alee/Sources/relicario.arch-followup-stream-c
pwd  # should print /home/alee/Sources/relicario.arch-followup-stream-c
```

**Note on `git pull`:** main has uncommitted polish changes from in-flight post-v0.5.1 work, including edits to `extension/src/vault/vault.ts`, `vault.css`, and `shared/glyphs.ts` — files Stream C will touch heavily. **Surface this to the PM as a Question before starting Phase 1** so the user can choose to commit/stash the in-flight work, defer Stream C, or proceed and merge at PR time. The setup above branches from local main HEAD without pulling, so your worktree starts clean of those uncommitted edits.

**ALL subsequent work happens in `/home/alee/Sources/relicario.arch-followup-stream-c`**. Every subagent prompt MUST begin with `cd /home/alee/Sources/relicario.arch-followup-stream-c` (project memory rule — without the force-cd, subagents may commit to main).

Today: 2026-05-04. Project rules in `CLAUDE.md` apply (Spanish flourish in replies, capitalize "Relicario", default to "yes"/recommended, never run git-destructive commands without asking).

## Required reading (in order)

1. `CLAUDE.md` — project rules
2. `docs/superpowers/reviews/2026-05-04-architecture-review.md` — synthesis (your scope is **P1.4, P1.5, P1.6, P1.9 + the in-scope extension P2 cluster only**)
3. `docs/superpowers/reviews/2026-05-04-dev-c-notes.md` — full DEV-C reviewer notes (your stream's primary source)
4. `docs/superpowers/reviews/2026-05-04-dev-b-notes.md` — read the **"Boundary notes for DEV-C"** section in particular (covers the parity-relevant cross-references, especially the new WASM surface that Plan B will produce)
5. `docs/superpowers/reviews/2026-05-04-dev-a-notes.md` — light skim for context only
6. **Your plan (will land at):** `docs/superpowers/specs/2026-05-04-extension-restructure-design.md` — read once the PM directs you to PROCEED

## Execution mode

Use **superpowers:subagent-driven-development**. Fresh subagent per task, two-stage review between tasks. Every subagent prompt MUST start with:
```
cd /home/alee/Sources/relicario.arch-followup-stream-c
```
…before any other instruction. This is non-negotiable per project memory.

## Your scope and boundaries

**In scope:**
- P1.4 — `extension/src/setup/setup.ts` (1220 LOC):
  - Add `create_vault` and `attach_vault` SW messages to `service-worker/router/popup-only.ts` + the message-type union in `shared/messages.ts`
  - Rewrite `setup.ts` as a UI that posts those messages with gathered config + image bytes (no direct `relicario-wasm` import)
  - Convert the 6-step procedural wizard into a step-registry pattern: `Array<{ id: StepId; render: (host) => void; attach: (host) => () => void }>`
  - `clearWizardState()` bound to `beforeunload` and to "return to step 0"
  - Target ~500 LOC after the rewrite (down from 1220)
- P1.5 — split `extension/src/vault/vault.ts` (1027 LOC) into:
  - `vault-shell.ts` (init, hash routing)
  - `vault-sidebar.ts` (sidebar render)
  - `vault-list.ts` (list pane render)
  - `vault-drawer.ts` (drawer state + render)
  - `vault-form-wrapper.ts` (form integration)
  - `vault.ts` keeps only routing + state coordination
  - **Lift the `vault_locked` RPC intercept into `shared/state.ts`** (or a wrapper around `sendMessage`) so popup and vault tab use the same channel — closes the synthesis P2 about RPC vs `session_expired` event divergence
  - Reset `state.drawerOpen` at the start of `renderPane` for non-list views
- P1.6 — concrete `StateHost` interface in `extension/src/shared/state.ts`:
  ```ts
  interface StateHost {
    state: PopupState;
    navigate: (view: View) => void;
    popOutToTab(): void;
    isInTab(): boolean;
    openVaultTab(hash?: string): void;
  }
  ```
  - Make `getState`/`setState` generic over `keyof PopupState`
  - Throw on `registerHost()` re-register
  - Export `__resetHostForTests()` helper
- P1.9 — extract from both router files:
  - `loadDeviceSettings`, `loadBlacklist`, `saveBlacklist` → `extension/src/service-worker/storage.ts`
  - `itemToManifestEntry` (17-line projection) → `extension/src/service-worker/vault.ts`
  - Import from both `popup-only.ts` and `content-callable.ts`
- In-scope extension P2 cluster:
  - Inactivity-timer reset on content-callable messages (`service-worker/index.ts:76-78`)
  - Null `state.gitHost` alongside `state.manifest` on session expiry (`service-worker/index.ts:51-58`)
  - Teardown helper extraction: `settings.ts:56-65` and `settings-vault.ts:15-22` → `teardownSettingsCommon()`
  - `Promise.allSettled` in `devices.ts:47-50` and `trash.ts:39-46`
  - MutationObserver debounce in `content/detector.ts:96-103` (`requestIdleCallback` or 200ms timer)
  - Vault-tab status indicator from new `get_vault_status` SW message returning `{ ahead, behind, lastSyncAt, pendingItems }` (closes the `relicario status` parity gap)

**Out of scope (other DEVs own these):**
- P1.1, JS free-swallow, P1.7, P1.8 — DEV-A (Stream A). **Note:** if A merges first, you'll inherit `impl Drop for SessionHandle`. That's expected and benign.
- P1.2, P1.3, P1.10 + the in-scope CLI P2s — DEV-B (Stream B). The new WASM exports (`parse_month_year`, `base32_*`, `guess_mime_for_extension`) that Plan B produces are NOT consumed in this round. Document the future consumer in your plan's "Out of scope" section; a later round wires them up.
- Other DEV-C P2/P3 not listed in your scope (e.g. shared-utilities response typing, group-autocomplete escaping, restore_backup payload extract, content-script `fillFields()` ack, content/icon outside-click leak) — explicitly deferred to a future round
- Setup-wizard manifest path constants (`VAULT_PATHS`) — folds into your P1.4 work; if convenient include it, else defer
- WASM JS-naming snake_case → camelCase rename — explicitly deferred
- Any of the 8 "Open architectural decisions" at the bottom of the synthesis

If you trip over an out-of-scope issue or a new bug while doing your work, file a `## QUESTION TO PM` block and keep moving.

**Hard rules:**
- **P1.6 (state.ts typing) MUST land first internally.** Both P1.4 and P1.5 push through the `StateHost` surface. Plan should call this out as Phase 1.
- **`setup.ts` MUST stop importing `relicario-wasm` directly after P1.4.** This is the architectural invariant the synthesis is fixing. After P1.4, the only file in `extension/src/` that imports `relicario-wasm` should be the service worker.
- **New SW message names are `create_vault` and `attach_vault`.** Use these exact names everywhere (`shared/messages.ts`, `service-worker/router/popup-only.ts`, `setup.ts`). The PM's coherence pass on the plans confirms naming consistency.
- **`vault_locked` unification goes in `shared/state.ts`** (or a wrapper around `sendMessage`). Popup AND vault tab use the same channel after this lands. Two channels for one outcome was the synthesis observation.
- **No emoji anywhere in `extension/src/`** (existing project rule from v0.5.1). If you see one while editing, replace with the monochrome glyph from `glyphs.ts`.
- **`glyphs.ts` is single source of truth** for icon characters. No inline Unicode literals at call sites.
- **Discriminated-union message contract is preserved.** New messages get added to `shared/messages.ts` and the appropriate capability set (`POPUP_ONLY_TYPES` or `CONTENT_CALLABLE_TYPES`). The boundary discipline holds.
- **WASM remains snake_case in JS** — no `#[wasm_bindgen(js_name = ...)]` renaming. That's a separate decision (DEV-B/DEV-C P3).
- **Test setup is vitest** for the extension (`extension/package.json: "test": "vitest run"`), `bun test` for `tools/relay/`. Do not change runners.
- **Synthetic test fixtures only.** No binary blobs.
- Do not merge your branch to main. The PM owns merges.
- Do not push `--force` or run `git reset --hard`. Per `CLAUDE.md`: ask first.

## Coordination with Stream B

Stream B will produce new `relicario-wasm` exports (`parse_month_year`, `base32_*`, `guess_mime_for_extension`). You do NOT consume these in this round — your plan's "Out of scope" section should explicitly call this out and reference the future consumer (likely a smart-input / QR-import / attachment-MIME round). If Stream B's WASM signature for any of these would NOT match what the extension would naturally consume, raise a `## QUESTION TO PM` so it can be reconciled before Stream B merges.

If Stream A merges first and you inherit `impl Drop for SessionHandle` plus the JS free-swallow removal: that's benign. Your `.free()` callsites should already be `wasm.lock(handle)` first per DEV-A's audit.

## Relay server

A message-bus MCP server is running on `localhost:7331`. You have three native tools:

- `post_message(from, to, kind, body)` — push a message; your `from` is always `"dev-c"`
- `read_messages(for)` — drain your inbox; call with `for="dev-c"` before each task
- `list_pending(for)` — check inbox count without consuming

Recipients: `pm, dev-a, dev-b, dev-c`. Use these instead of asking the user to copy-paste. Before starting each task: `read_messages(for="dev-c")`. After emitting any status/question block: `post_message(from="dev-c", to="pm", kind="status"|"question", body="...")`.

**Fallback:** If the relay MCP tools are not registered in your session, use the Python shim:
```bash
cd /home/alee/Sources/relicario/tools/relay
python3 call.py post_message '{"from":"dev-c","to":"pm","kind":"status","body":"..."}'
python3 call.py read_messages '{"for":"dev-c"}'
```

## Coordination protocol

You are one of four terminals. Before starting each task, call `read_messages(for="dev-c")` to drain your inbox.

When posting a status update, call `post_message(from="dev-c", to="pm", kind="status", body="...")` with the body:

```
## STATUS UPDATE — DEV-C
Time: <iso8601 like 2026-05-04T14:30:00-07:00>
Branch: feature/arch-followup-stream-c-extension-restructure
Task: <number / short name>
Status: STARTED | IN-PROGRESS | DONE | BLOCKED | REVIEW-READY
Last commit: <short sha + first line of message>
Tests: <green | red (which failed) | N/A>
Notes: <anything PM needs to know — keep to 3 sentences max>
```

**When you need PM input mid-task:**
```
## QUESTION TO PM — DEV-C
Time: <iso8601>
Context: <what task, what decision point>
Options: <A: ... / B: ... / C: ...>
Recommended: <your pick + one-sentence rationale>
Blocker: yes | no
```

**You'll receive:** `## DIRECTIVE TO DEV-C` blocks from the PM. The first one will say `Action: PROCEED` with the plan path once the PM has drafted it. Acknowledge and start Task 1.

## Authority within the plan

You don't need PM permission to:
- Execute task-to-task per the plan once you have it
- Make implementation decisions consistent with the plan and synthesis
- Write tests, refactor your own code, fix bugs you introduce
- Push commits to your feature branch

You **do** escalate to PM when:
- A scope question outside the plan
- A WASM signature mismatch with what Stream B is producing
- A test you can't make green after honest debugging (don't fudge — debug)
- A discovered bug not in your plan
- The in-flight uncommitted changes on `vault.ts`/`vault.css`/`glyphs.ts` need resolution before a merge
- Anything destructive (per CLAUDE.md)
- Before opening the PR for review

## Final steps before REVIEW-READY

Run the project's full validation:

```bash
cd /home/alee/Sources/relicario.arch-followup-stream-c
cd extension
bun run test
bun run build
bun run build:firefox
cd ..
cargo build -p relicario-wasm --target wasm32-unknown-unknown
```

All must be green. Vitest covers the new `StateHost` typing, the message-router dedup, and the wizard step registry.

Then sweep for emoji and in-flight collision:

```bash
grep -rn '\U0001F\|🔑\|📝\|🪪\|💳\|🗝\|📄\|⏱️\|🖥\|🔐\|📎' /home/alee/Sources/relicario.arch-followup-stream-c/extension/src/ 2>/dev/null
```

Expected: no output (project rule).

Then push and open the PR:

```bash
git push -u origin feature/arch-followup-stream-c-extension-restructure
gh pr create --base main --head feature/arch-followup-stream-c-extension-restructure \
  --title "refactor(ext): setup-via-SW + vault.ts split + state.ts typing + SW router dedup (Stream C)" \
  --body "$(cat <<'EOF'
## Summary

Stream C of the architecture-review-followup. The largest plan in the bundle — turns three "code lies about the architecture" surfaces into uniform readable modules:

- **P1.4** — `extension/src/setup/setup.ts` no longer imports `relicario-wasm` directly. New `create_vault` / `attach_vault` SW messages do the crypto orchestration. The 6-step wizard is now a step registry. ~500 LOC down from 1220.
- **P1.5** — `extension/src/vault/vault.ts` (1027 LOC) split into `vault-shell.ts` / `vault-sidebar.ts` / `vault-list.ts` / `vault-drawer.ts` / `vault-form-wrapper.ts`. `vault_locked` RPC intercept lifted into `shared/state.ts` so popup and vault tab share one channel.
- **P1.6** — `extension/src/shared/state.ts` has a concrete `StateHost` interface; `getState`/`setState` are generic over `keyof PopupState`; double-registration guard + `__resetHostForTests` helper.
- **P1.9** — duplicated SW router helpers extracted: `service-worker/storage.ts` for the three storage helpers, `service-worker/vault.ts` for `itemToManifestEntry`.
- **Extension P2 cluster** — inactivity-timer reset on content-callable messages, `state.gitHost` clear on session expiry, `teardownSettingsCommon()`, `Promise.allSettled` in devices/trash, MutationObserver debounce in content/detector, vault-tab status indicator (closes `relicario status` parity gap).

## Synthesis references

- `docs/superpowers/reviews/2026-05-04-architecture-review.md` — P1.4, P1.5, P1.6, P1.9 + DEV-C's extension P2 cluster
- `docs/superpowers/specs/2026-05-04-extension-restructure-design.md` — Plan C

## Future-round consumer (NOT in this PR)

Plan B produces new `relicario-wasm` exports (`parse_month_year`, `base32_*`, `guess_mime_for_extension`). A later round will wire them up via `wasm.d.ts` regeneration and add SW message handlers. Out of scope here.

## Test plan

- [x] `bun run test` green in `extension/`
- [x] `bun run build` green
- [x] `bun run build:firefox` green
- [x] `cargo build -p relicario-wasm --target wasm32-unknown-unknown` green
- [x] No emoji anywhere in `extension/src/` (grep clean)
- [x] `setup.ts` no longer imports `relicario-wasm`
- [x] `vault.ts` LOC dropped substantially; new modules each under ~300 LOC
- [x] Vault tab and popup both use one channel for `vault_locked` (no RPC intercept divergence)
- [x] StateHost interface concrete; tests cover double-registration guard and reset helper
EOF
)"
```

Emit a `## STATUS UPDATE` with `Status: REVIEW-READY` and the PR URL.

## First action

After reading the required inputs and setting up the worktree:

1. Call `read_messages(for="dev-c")` to drain any early inbox messages.
2. Emit a `## STATUS UPDATE` confirming setup complete:
   ```
   ## STATUS UPDATE — DEV-C
   Time: <iso8601>
   Branch: feature/arch-followup-stream-c-extension-restructure
   Task: setup
   Status: DONE
   Last commit: <main HEAD sha + first line>
   Tests: N/A
   Notes: Worktree at /home/alee/Sources/relicario.arch-followup-stream-c. Synthesis + DEV-C notes + DEV-B boundary section absorbed. Awaiting Plan C at docs/superpowers/specs/2026-05-04-extension-restructure-design.md.
   ```
3. **Also emit a `## QUESTION TO PM`** about the in-flight uncommitted edits to `vault.ts` / `vault.css` / `glyphs.ts` on main:
   ```
   ## QUESTION TO PM — DEV-C
   Time: <iso8601>
   Context: setup, before Phase 1
   Options: A: PM/user commits or stashes the in-flight v0.5.x polish on main before I start, so my worktree has a stable baseline. B: I proceed and rebase/merge those changes at PR time. C: PM defers Stream C until the in-flight work is committed.
   Recommended: A — clean baseline avoids merge churn during the largest plan in the bundle.
   Blocker: no — I can read the plan and start Phase 1 (P1.6 state.ts typing) which doesn't touch the in-flight files. Resolution needed before Phase 2 (P1.5 vault.ts split).
   ```
4. **Wait** for the PM's `## DIRECTIVE TO DEV-C` with `Action: PROCEED` and the plan path.
5. Read the plan, then start Task 1 using `superpowers:subagent-driven-development`. Phase 1 is P1.6 (state.ts typing) — finish it cleanly before P1.4 / P1.5.
