# Status — lane G (persistence & capsule, branch `lane/g-capsule`) ## Round 1 — 2026-07-17 — STATUS: ready_to_merge **Directives acknowledged:** Round 4 of plan/DIRECTIVES.md (phase 5 begins; foundation2 merged; worktree rule followed — this lane runs in its own git worktree). **Acceptance checklist** M16 — server-side camera paths: - [x] Routes implemented — by foundation2 (per the phase-5 ownership table); lane G deepened coverage only, per scope. - [x] `backend/tests/test_paths.py` — 30 tests: roundtrip deep-equal incl. float precision + a 500-keyframe path, multiple paths coexist / id-ordered listing / summary-only shape, duplicate + unicode + whitespace + 300-char names verbatim, ISO `created_at`, empty-keyframes path valid (director degrade must be saveable), extra JSON keys ride along, get/delete 404s, delete idempotence, an 18-case parametrized 422 matrix over the frozen camPath contract, 422 creates no row, missing/aliased request fields 422. Cleans up its rows (test_phase5_api runs later and asserts an empty table). - [x] `frontend/src/pathsStore.js` filled: 💾 save = name prompt + POST `camPath.toJSON()`; dropdown load = GET `/api/paths/{id}` + `camPath.fromJSON(data.json)`; 🗑 delete with confirm; dropdown refreshed after every mutation (new save left selected); controls unhidden + `ready = true`. Capsule mode: save/del hide via `write-ui`; the load dropdown stays (paths are baked read-only — below) and hides itself if the listing fetch fails. - [ ] Live save → reload page → load reproduces keyframes exactly — NEEDS LIVE BROWSER (list for coordinator below). The exact-roundtrip property is locked server-side by `test_roundtrip_preserves_float_precision` / `test_roundtrip_large_keyframe_list`. M17 — memory capsule: - [x] `backend/festival4d/capsule.py::build_capsule` per the frozen contract: copies `frontend/dist` (clear "run `cd frontend && npm run build`" error if missing), copies the manifest-referenced media to `media/`, bakes every read-only API response extension-less at the live API's relative paths (`api/manifest` with `capsule: true` + `has_capture: false`, `api/events`, `api/anchors`, `api/videos/{id}/poses`, `api/beats`/`api/pointcloud`/ `api/splat` when present, `api/audio/{id}` via the same lazy `ingest.extract_audio_hq` cache the live route uses), injects `` ahead of the app `