Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Hc6Rvdz3DxLucqNtPE2iP
58 lines
6.8 KiB
Markdown
58 lines
6.8 KiB
Markdown
# Dev A — RESUME Prompt (v0.9.0 Plan A, org foundation)
|
|
|
|
Paste everything below the `---` into a **fresh** Claude Code terminal.
|
|
|
|
---
|
|
|
|
You are **RESUMING** Plan A (org foundation: SW + WASM) for v0.9.0. The lift paused ~21h ago; you are a fresh session with no relay history. Your worktree, branch, and commits **already exist** — do NOT recreate the worktree and do NOT restart from Task 1.
|
|
|
|
## Resume setup (replaces the original Setup block)
|
|
|
|
```bash
|
|
cd /home/alee/Sources/relicario.v0.9.0-dev-a
|
|
pwd # must print /home/alee/Sources/relicario.v0.9.0-dev-a
|
|
git status # expect your branch, clean-ish tree
|
|
git log --oneline -8 # confirm Tasks 1-4 are committed (down to f5336e3)
|
|
git fetch origin
|
|
git merge origin/main # main now has Dev-D's keyfile merge (d649203). EXPECT trivial additive
|
|
# conflicts in crates/relicario-wasm/src/lib.rs and extension/src/wasm.d.ts
|
|
# (D added keyfile_* / unlock_with_secret next to your org_* fns) — keep BOTH.
|
|
```
|
|
|
|
ALL work stays in `/home/alee/Sources/relicario.v0.9.0-dev-a`. Every subagent prompt MUST start with `cd /home/alee/Sources/relicario.v0.9.0-dev-a` (project memory — a header is not enough).
|
|
|
|
## Read for full context
|
|
|
|
- `docs/superpowers/coordination/v0.9.0-dev-a-prompt.md` — your ORIGINAL prompt: use it for ROLE, the RELAY protocol + shim, the STATUS/QUESTION block formats, polling cadence, specs/plan paths. **IGNORE its Setup block and its "begin Task 1."**
|
|
- `docs/superpowers/plans/2026-06-20-v0.9.0-org-a-foundation.md` — your plan.
|
|
- `CLAUDE.md`.
|
|
|
|
The relay is up on `localhost:7331` (shim: `cd /home/alee/Sources/relicario/tools/relay && python3 call.py read_messages '{"for":"dev-a"}'`). The PM (me) is live — poll before/after every subagent and at task boundaries.
|
|
|
|
## WHERE YOU ARE — already done, do NOT redo (commits, local-only, not pushed)
|
|
|
|
- **Task 1** `org_unwrap_key` — DONE. Device-key form resolved EMPIRICALLY = **OpenSSH PEM blob** (param `device_private_openssh`). zeroized `extract_ed25519_seed` helper lifted into `relicario-core::device`, reused by `sign()`. (NOTE: this signature changes in Task 4.5 below.)
|
|
- **Task 2** org manifest over WASM — DONE. The org manifest is a **dedicated `OrgManifest { schema_version, entries: OrgManifestEntry[] }}`** type (NOT the personal `ManifestEntry`). You exposed `org_manifest_decrypt` + `org_manifest_encrypt` over WASM (wrapping `vault::{decrypt,encrypt}_org_manifest`) and mirrored `OrgManifest`/`OrgManifestEntry` faithfully/LEAN into `shared/types.ts` (`{id, type, title, tags[], modified, trashed_at?, collection}` — `collection` REQUIRED; NO personal-only fields).
|
|
- **Task 3** multi-context session — DONE. `clearAll` is **best-effort** (each `handle.free()` in its own try/catch, null personal + clear orgs + reset context REGARDLESS, never throws); `setOrg` frees the displaced handle; lock + inactivity timer both zero ALL handles; `session.test.ts` updated to the best-effort contract with a WHY rationale comment + a multi-handle test. Org key NEVER persisted.
|
|
- **Task 4** org config + `org_list_configs` — DONE. Wired in all THREE places (PopupMessage union + POPUP_ONLY_TYPES + handler arm); `org_list_configs` returns `OrgConfigSummary {orgId, displayName}` ONLY (no token leak, asserted). Minor cleanup pending: `saveOrgConfigs()` is unused — remove-or-justify at your simplify pass.
|
|
|
|
## KEY PM DECISIONS during the lift (absorb — you have no relay history)
|
|
|
|
- **Grant filter (Task 5) = Option A, SOFT phase-1 filter.** Add a WASM `org_manifest_decrypt_filtered(handle, encrypted, granted[])` that decrypts AND grant-filters in core, so ungranted entries never cross to JS — used by the READ path only. Single-source the filter: extract a core helper `filter_by_collections(&[String])` that BOTH `OrgManifest::filter_for_member` AND the new WASM fn delegate to (no filter logic reimplemented in WASM/TS). **KEEP the full unfiltered `org_manifest_decrypt`** — Dev-C's writes need the FULL manifest (re-encrypting a filtered subset would wipe ungranted entries). Comment that phase-1 is a soft UX filter (the member holds the single org key), NOT crypto isolation — defense-in-depth only.
|
|
|
|
## YOUR REMAINING WORK (you are the org-track critical path — B and C wait on your merge)
|
|
|
|
- **Task 4.5 — NEW foundation prerequisite (Variant Y): device-key persist + restore.** DISCOVERED GAP: the extension never persists the device ed25519 private key — `DEVICE_STATE` (WASM `device.rs`) is in-memory only, wiped on every SW restart; `chrome.storage.local` stores only `vaultConfig`/`imageBase64`/`device_name`. So `org_unwrap_key` (and `sign_for_git` for Dev-C) have no key after a restart. Build (private key NEVER crosses to JS):
|
|
1. WASM: at register, encrypt the device private key under the current session **master key** and return CIPHERTEXT to JS; JS persists it as `device_key_enc` in `chrome.storage.local`.
|
|
2. WASM `restore_device_key(session_handle, encrypted)`: decrypt under the master key + repopulate `DEVICE_STATE` (decrypt INSIDE WASM). Wire it at unlock.
|
|
3. Refactor `org_unwrap_key` → `org_unwrap_key(keys_blob)` — read the seed from `DEVICE_STATE` internally; DROP the `device_private_openssh` param.
|
|
4. Migration: if `device_key_enc` is absent at unlock (existing installs), handle gracefully (re-register + persist).
|
|
5. Tests: persist→restore round-trip; survives-SW-restart simulation; `org_unwrap_key` works post-restore; `device_key_enc` in storage is NOT plaintext. (This ALSO unblocks Dev-C's production signing.)
|
|
- **Task 5 — org read core**: `openOrg` (read public `members.json`/`collections.json`, match this device by ed25519 fingerprint → grants, `org_unwrap_key`, fetch + `org_manifest_decrypt_filtered` to grants, cache); `getOrgItem` (`items/<collection>/<id>.enc` → `item_decrypt`); `listOrgCollections`. Offline: on git network error, serve last-cached manifest read-only + `offline: true`.
|
|
- **Task 6 — `org_switch` + read messages**: `org_switch {context}` (sets context, caches `OrgHandleState`, offline-aware), `org_list_items` (grant-filtered `OrgManifestEntry[]`), `org_get_item {id}` (`Item`), `org_list_collections` (`Collection {slug, display_name}`). Wire all in the three places.
|
|
- Then full validation (cargo test wasm/core, wasm32 build, clippy `-D warnings`, `cd extension && npx vitest run src/service-worker/ && npm run build:all`), simplify pass, **push** `feature/v0.9.0-dev-a-org-foundation`, post `Status: REVIEW-READY`. The PM merges you FIRST in the org track (your merge is Dev-B's green light).
|
|
|
|
## First action
|
|
|
|
`cd` into the worktree, run `git log --oneline -8` to confirm state, `read_messages(for="dev-a")` to get my resume directive, then post a `## STATUS UPDATE` with `Status: IN-PROGRESS`, `Task: 4.5 device-key persist`, confirming RESUMED + main merged. Then continue via `superpowers:subagent-driven-development`.
|