# FC Backlog Mega Plan — close 7 streams on the FreshCards lane **Session**: 404981936394548 (id 11, freshcards-mavis) **Repo**: avidtech6/freshcards @ origin/main HEAD 6bc4609 (F 45 SHIPPED) **Plan ID**: (assigned by HQ after upload) **Created**: 2026-09-21 13:42 Europe/Paris ## Goal Execute 7 backlog streams on the FreshCards lane in one mega-dispatch. Each phase commits independently to a single `feat/id11-fc-backlog-mega` branch. Operator reviews branch before merge to main. ## Streams (in execution order) ### Phase 1 — Subscribe hook (StorageAdapter v1.0 → v1.1) - **What**: Optional `subscribe(callback): () => void` interface method on FilesystemStorageAdapter - **Why**: Per VC 156 §5 (flagged for operator review in F 40). v1 contract stays read-only; v1.1 adds opt-in file watching - **Files**: - `src/core/adapters/filesystem/subscribe.ts` (NEW, ~120 lines) — chokidar wrapper with `awaitWriteFinish: true` - `src/core/adapters/filesystem/filesystem-adapter.ts` (MODIFIED) — add `subscribe` method - `src/core/adapters/filesystem/__tests__/subscribe.spec.ts` (NEW, 4 cases) - `app-codex/filesystem-storage-adapter.md` §5 (NEW section) - `app-codex/app-codex.md` v1.0 → v1.1 status bump - `CHANGELOG.md` v1.1.0 entry - **Effort**: 1-2 days - **Acceptance**: 4 vitest cases pass (add/change/unlink fire + unsubscribe stops); index cache not invalidated spuriously (debounce 100ms); tsc 410 baseline unchanged - **Locked reflex** (Phase 1, NEW): subscribe must debounce index cache invalidation by ≥100ms to coalesce editor-save bursts ### Phase 2 — F 33 blocked primitives (documentation only) - **What**: Document the 3 BLOCKED primitives as future-work. NO implementation. - **Why**: Operator decision deferred for VIBE_CARD; architectural choice pending for WORKSPACE_SURFACES; mobile-hull depends on host chrome - **Files**: - `app-codex/f33-blocked-primitives.md` (NEW, ~200 lines) — 1 section per primitive (status, blockers, est-effort, owner) - `CHANGELOG.md` v1.1.1 entry (docs-only bump) - **Effort**: 0.5 day - **Acceptance**: 3 sections each with status/blockers/effort/owner; CHANGELOG bumped - **Locked reflex** (Phase 2, NEW): BLOCKED primitives documentation goes in `app-codex/` not `docs/` — app-codex is the canonical user-facing surface ### Phase 3 — F 43 follow-ups (VPS exiftool + streaming + IPTC enrichment) - **What**: Close §44 implementation gaps - **Why**: F 43 shipped with optional exiftool graceful fallback; real VPS test + streaming API + 5 IPTC fields missing - **Files**: - `scripts/f43-vps-exiftool-smoke.sh` (NEW, ~80 lines) — SSH-based live test on VPS - `src/core/adapters/filesystem/image-metadata-stream.ts` (NEW, ~200 lines) — async iterator via fs.opendir - `src/core/adapters/filesystem/image-metadata.ts` (MODIFIED) — extend READ_FIELDS with IPTC:City, IPTC:Country, IPTC:Source, IPTC:Headline, IPTC:Keywords - `src/core/adapters/filesystem/__tests__/image-metadata-stream.spec.ts` (NEW, 6 cases) - `CHANGELOG.md` v1.1.2 entry - **Effort**: 3-4 days - **Acceptance**: VPS exiftool returns real data for live JPEG; stream yields N entries without full array allocation; 5 new IPTC fields exposed; 6 stream tests pass - **Locked reflex** (Phase 3, NEW): for ≥1000-image libraries, default to streaming reads. Eager `readImageMetadata` is opt-in via `populateImageMetadata: true` ### Phase 4 — Fleet hygiene (PAT + Notion + VP test failures) - **What**: Close 3 hygiene gaps that affect every other phase - **Why**: Sandbox env var doesn't auto-refresh after operator rotation; Notion API key presence unverified; 15 VP test failures block CI signal - **Files**: - `/workspace/.home/scripts/refresh-pat.sh` (NEW, ~60 lines) — re-reads `GITHUB_PAT_FG_1` from user-scope memory + writes to local `.git/config` + env alias - `/workspace/.home/scripts/check-notion-key.sh` (NEW, ~30 lines) — verifies `NOTION_API_KEY` presence + parent-page id validity - `.mavis/dispatches/fc-vp-failures-baseline.json` (NEW) — diagnostic list of 15 pre-existing VP test failures with root-cause classification - `CHANGELOG.md` v1.1.3 entry - **Effort**: 1 day - **Acceptance**: refresh-pat.sh rotates token from user-scope memory; check-notion-key.sh reports MISSING with alert; VP failures baseline JSON enumerates 15 with classification (deprecated env / flaky / pre-existing-regression / needs-fix) - **Locked reflex** (Phase 4, NEW): every Mavis session that touches GitHub on a fresh sandbox should run refresh-pat.sh FIRST, NOT assume `GITHUB_PAT_FG_1` is current ### Phase 5 — Cloud sync (real PB backend) - **What**: Replace `sync-rules.ts` + `pb-client.ts` stubs with real implementation - **Why**: Cloud instance `/api/sync` + `/api/databases` return 404 today; sync config is DECLARED not EXECUTED; PB hash-chain pattern is the right model per VC 157 - **Files**: - `src/modules/fc-encryption/sync/pb-client.ts` (REWRITTEN, ~300 lines) — real PB calls, batch=100, hash-chain continuity - `src/modules/fc-encryption/sync/sync-rules.ts` (MODIFIED) — actual execution, not just config - `src/modules/fc-encryption/sync/__tests__/pb-client.spec.ts` (NEW, 8 cases) — pull/push/conflict/hash-break - VPS-side: cloud.freshcards.freshvibeapps.com/api/sync endpoint (need id 44 to deploy; out of scope if VPS locked) - `CHANGELOG.md` v1.2.0 entry - **Effort**: 2-3 weeks (incl. VPS backend if reachable) - **Acceptance**: 8 vitest cases pass (pull/push/conflict resolution/chain break); sync rules actually execute; conflict resolution uses last-write-wins + hash; CHANGELOG v1.2.0 - **Locked reflex** (Phase 5, NEW): hash-chain breaks are FATAL not silent — emit error + stop sync, require manual `resetChain(threadId)` to recover. Don't auto-merge on chain break (data loss risk) ### Phase 6 — Adapter v2 (writes + Windows + benchmarks) - **What**: StorageAdapter v2 feature-complete - **Why**: v1 is read-only + POSIX-only; v2 unlocks writes + cross-platform + perf signal - **Files**: - `src/core/adapters/filesystem/filesystem-adapter.ts` (MAJOR) — add `put`, `delete`, `loadStream`, `targetOS` support - `src/core/adapters/filesystem/path-windows.ts` (NEW, ~80 lines) — drive-letter + backslash normalization - `src/core/adapters/encrypted/index.ts` (NEW, ~250 lines) — EncryptedStorageAdapter (age + libsodium) - `src/bench/adapter.bench.ts` (NEW, ~150 lines) — vitest bench for read/write/stream/encrypted throughput - `src/core/adapters/filesystem/__tests__/v2-writes.spec.ts` (NEW, 6 cases) - `src/core/adapters/filesystem/__tests__/windows-paths.spec.ts` (NEW, 4 cases) - `src/core/adapters/filesystem/__tests__/encrypted.spec.ts` (NEW, 2 cases) - `CHANGELOG.md` v2.0.0 entry (MAJOR) - **Effort**: 2-3 weeks - **Acceptance**: put/delete/loadStream work; Windows drive-letter paths resolve; encrypted adapter round-trips; benchmark numbers published; 12 new vitest cases - **Locked reflex** (Phase 6, NEW): MAJOR version bump requires operator review of breaking changes. Default in v2: `writable: true` (breaking change from v1 default of false). Document migration path in app-codex ### Phase 7 — Adaptive bundles (v9 concept, gated) - **What**: Conditional on FvW v9 ratification. If not ratified by Phase 7 start → PARK and report. - **Why**: Concept only exists in v9 spec; can't implement against unspecified contract - **Files**: - `src/core/adaptive/context-detect.ts` (NEW, ~100 lines) — stub interface only - `src/core/adaptive/__tests__/context-detect.spec.ts` (NEW, 2 cases) — stub only - `CHANGELOG.md` entry: "Adaptive bundles: DESIGN, gated on FvW v9" - **Effort**: 0.5 day (stub only) - **Acceptance**: 2 stub cases; CHANGELOG entry; conditional report if FvW v9 not ratified - **Locked reflex** (Phase 7, NEW): never start implementation against a not-yet-ratified spec. Park with explicit "waiting on FvW v9" + recheck on next dispatch ### Phase 8 — Final consolidation - Run full verify: vitest + tsc --noEmit + check-alignment.sh + v5-drift-validator - Merge all 7 phase commits into feat/id11-fc-backlog-mega (--no-ff) - Push branch (NOT main) - USAGE line aggregate - Bulletin + doc + Notion mirror (final summary) - Footer: `[id11] | end PROMPT F 49` ## Constraints (locked across all phases) - Phase 0 VA probe per VC 177 bounded-retry (15/30/60s, ~105s cap) - USAGE line in every phase report per VC 178 - Per-phase bulletin + doc + Notion mirror - tsc --noEmit stays at 410 baseline (zero new errors) - vitest stays 86/86 baseline (only add new cases, never regress) - No commits to main; feat branch only - If any phase FAIL → STOP, do NOT continue to next phase - Footer: `[id11] | end PROMPT F 49` ## Risks + mitigations | Risk | Mitigation | |------|-----------| | Phase 5 VPS backend not reachable | Park Phase 5 sub-step, deliver client-only with documented VPS dependency | | Phase 6 v1→v2 breaks downstream consumers | v2 ships alongside v1 in separate export; consumers opt in via package.json bump | | Phase 7 v9 not ratified | Park with explicit note; no wasted work | | PAT rotation kills mid-dispatch push | Phase 4 ships refresh-pat.sh first; all subsequent phases can self-heal | | 15 VP test failures block CI | Phase 4 baseline-records them; Phase 8 re-runs to confirm no regression | ## Cross-references - F 40 (d934177) — StorageAdapter v1 base - F 43 (976b4cf) — §44 Image Metadata - F 45 (6bc4609) — §43 References - VC 156 (d000317) — FC_REQUIREMENTS spec - VC 178 (d000316) — USAGE line rule - VC 177 (b004133) — Phase 0 bounded retry - VC 164 (a1137) — multi-phase split pattern ## Estimated total wall time 7 working days of focused implementation + 2 days for VPS work + 1 day for final consolidation = ~10 days of work. Probably 2-3 mega-dispatches if operator splits per operator preference for multi-phase work.