--- phase: 05-mvp-deployment plan: 01 type: execute wave: 1 depends_on: [] files_modified: - adapter/matrix/reconciliation.py - adapter/matrix/bot.py - tests/adapter/matrix/test_reconciliation.py - tests/adapter/matrix/test_restart_persistence.py autonomous: true requirements: - PH05-01 - PH05-03 must_haves: truths: - "On restart, existing Matrix Space and child-room topology is rebuilt before live sync begins." - "Restart recovery preserves Space+rooms UX instead of creating duplicate DM-style working rooms." - "Recovered rooms regain user metadata, room metadata, and chat bindings needed for normal routing." - "Legacy working rooms missing `platform_chat_id` are backfilled deterministically during startup before strict routing handles traffic." artifacts: - path: "adapter/matrix/reconciliation.py" provides: "Authoritative restart reconciliation from Matrix topology into local metadata" - path: "adapter/matrix/bot.py" provides: "Startup wiring that runs reconciliation before sync_forever" - path: "tests/adapter/matrix/test_reconciliation.py" provides: "Regression coverage for startup recovery and idempotence" key_links: - from: "adapter/matrix/bot.py" to: "adapter/matrix/reconciliation.py" via: "startup bootstrap before sync_forever" pattern: "reconcil" - from: "adapter/matrix/reconciliation.py" to: "core/chat.py" via: "chat manager rebuild for recovered rooms" pattern: "get_or_create" --- Rebuild Matrix-local routing state from authoritative Space topology before the bot processes live traffic. Purpose: Preserve the Phase 01 Space+rooms contract after restart even if SQLite metadata is partial or missing. Output: A startup reconciliation module, bot wiring, and regression tests proving no DM-first duplication on restart. @/Users/a/.codex/get-shit-done/workflows/execute-plan.md @/Users/a/.codex/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/05-mvp-deployment/05-RESEARCH.md @.planning/phases/05-mvp-deployment/05-VALIDATION.md @.planning/phases/04-matrix-mvp-shared-agent-context-and-context-management-comma/04-02-SUMMARY.md @adapter/matrix/bot.py @adapter/matrix/store.py @adapter/matrix/handlers/auth.py @tests/adapter/matrix/test_invite_space.py @tests/adapter/matrix/test_chat_space.py @tests/adapter/matrix/test_restart_persistence.py From `adapter/matrix/bot.py`: ```python async def prepare_live_sync(client: AsyncClient) -> str | None: response = await client.sync(timeout=0, full_state=True) if isinstance(response, SyncResponse): return response.next_batch return None ``` ```python class MatrixBot: async def _bootstrap_unregistered_room( self, room: MatrixRoom, sender: str, ) -> list[OutgoingEvent] | None: ... ``` From `adapter/matrix/store.py`: ```python async def get_room_meta(store: StateStore, room_id: str) -> dict | None: ... async def set_room_meta(store: StateStore, room_id: str, meta: dict) -> None: ... async def get_user_meta(store: StateStore, matrix_user_id: str) -> dict | None: ... async def set_user_meta(store: StateStore, matrix_user_id: str, meta: dict) -> None: ... async def next_platform_chat_id(store: StateStore) -> str: ... ``` Task 1: Add restart reconciliation regression coverage tests/adapter/matrix/test_reconciliation.py, tests/adapter/matrix/test_restart_persistence.py tests/adapter/matrix/test_invite_space.py, tests/adapter/matrix/test_chat_space.py, tests/adapter/matrix/test_restart_persistence.py, adapter/matrix/bot.py, adapter/matrix/handlers/auth.py, .planning/phases/05-mvp-deployment/05-RESEARCH.md - Test 1: startup recovery rebuilds user space metadata, room metadata, and chat bindings from Matrix topology without creating new working rooms (per D-Phase05-reset and PH05-01). - Test 2: reconciliation is idempotent and safe when local SQLite state is already present. - Test 3: reconciliation happens before lazy `_bootstrap_unregistered_room()` would run for existing rooms (per PH05-03). - Test 4: legacy room metadata missing `platform_chat_id` is backfilled deterministically at startup and persisted before routed handling begins. - `tests/adapter/matrix/test_reconciliation.py` exists and names reconciliation entrypoints explicitly. - The new tests assert restored `space_id`, `chat_id`, `matrix_user_id`, and `platform_chat_id` values for recovered rooms. - The regression slice also proves existing Space onboarding behavior still passes by running `test_invite_space.py` and `test_chat_space.py`. - The automated command in `` fails before implementation or would fail if reconciliation is removed. Create a dedicated `tests/adapter/matrix/test_reconciliation.py` module and extend restart persistence coverage so Phase 05 has a real Wave 0 contract. Model the recovered topology after the Phase 01 Space+rooms onboarding tests, not a DM-first flow, and explicitly keep those onboarding regressions in the verification slice so restart hardening cannot break provisioning UX. Cover recovery of `user_meta`, `room_meta`, `ChatManager` bindings, and room-local routing fields from Matrix-side state before live callbacks begin, including deterministic backfill for legacy rooms that predate `platform_chat_id`. Keep temporary UX state out of scope, per research. pytest tests/adapter/matrix/test_invite_space.py tests/adapter/matrix/test_chat_space.py tests/adapter/matrix/test_reconciliation.py tests/adapter/matrix/test_restart_persistence.py -v Phase 05 has failing-or-red-before-code tests that define authoritative restart reconciliation behavior and exclude duplicate room provisioning. Task 2: Implement authoritative startup reconciliation and wire it before live sync adapter/matrix/reconciliation.py, adapter/matrix/bot.py adapter/matrix/bot.py, adapter/matrix/store.py, adapter/matrix/handlers/auth.py, tests/adapter/matrix/test_reconciliation.py, tests/adapter/matrix/test_restart_persistence.py, .planning/phases/05-mvp-deployment/05-RESEARCH.md - Test 1: startup rebuild runs after login and initial full-state fetch, but before `sync_forever()` processes live events. - Test 2: recovered rooms keep their existing Space+rooms identity and do not trigger `_bootstrap_unregistered_room()` unless the room is genuinely new. - Test 3: local metadata can be rebuilt from Matrix topology when SQLite entries are missing, while existing valid metadata remains stable. - Test 4: startup repair assigns a deterministic `platform_chat_id` to legacy rooms missing that field and persists it before routed platform calls can occur. - `adapter/matrix/reconciliation.py` exports a focused reconciliation entrypoint used by startup code. - `adapter/matrix/bot.py` invokes reconciliation before `client.sync_forever(...)`. - Recovered room metadata includes `room_type`, `chat_id`, `space_id`, `matrix_user_id`, and `platform_chat_id` where available or rebuildable. - Legacy rooms missing `platform_chat_id` follow one documented startup backfill path rather than ad hoc routing fallbacks. Implement a restart recovery module that treats Matrix topology as authoritative, per the Phase 05 reset and research notes. Rebuild missing local metadata for Space-owned working rooms, deterministically backfill missing `platform_chat_id` values for legacy rooms, and re-create `ChatManager` entries needed by routing, while keeping SQLite as a rebuildable cache rather than the source of truth. Wire the new reconciliation step into startup after the initial full-state sync and before live sync begins, and keep the onboarding regression slice green while doing it. Do not widen into timeline scraping, new storage backends, or DM-first fallbacks. pytest tests/adapter/matrix/test_invite_space.py tests/adapter/matrix/test_chat_space.py tests/adapter/matrix/test_reconciliation.py tests/adapter/matrix/test_restart_persistence.py tests/adapter/matrix/test_dispatcher.py -v Restart recovery restores the minimum durable state for existing Space rooms before live traffic, and the guarded regression suite passes. Run the onboarding, reconciliation, restart-persistence, and Matrix dispatcher slices together. Confirm startup now has a deterministic pre-sync recovery and legacy-room backfill step instead of relying on lazy room bootstrap or routing-time fallbacks for existing topology. The bot can restart with partial or empty local room metadata, rebuild managed Space rooms before live sync, and continue handling those rooms without creating duplicate onboarding rooms. After completion, create `.planning/phases/05-mvp-deployment/05-01-SUMMARY.md`