diff --git a/plan/status/lane-G.md b/plan/status/lane-G.md
new file mode 100644
index 0000000..37eceaa
--- /dev/null
+++ b/plan/status/lane-G.md
@@ -0,0 +1,101 @@
+# 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 `