surfaces/.planning/phases/01.1-matrix-restart-reconciliation-and-dev-reset-workflow/01.1-01-PLAN.md

7.7 KiB

phase plan type wave depends_on files_modified autonomous requirements must_haves
01.1-matrix-restart-reconciliation-and-dev-reset-workflow 01 execute 1
adapter/matrix/reconcile.py
tests/adapter/matrix/test_reconcile.py
true
truths artifacts key_links
A normal Matrix restart can rebuild missing local metadata from already joined Space/chat rooms instead of requiring a destructive reset.
Reconciliation restores the minimal local state needed for routing and chat operations: `matrix_user:*`, `matrix_room:*`, and missing `chat:{user}:{chat_id}` rows.
Reconciliation never provisions new Matrix rooms or Spaces while repairing local state.
Recovered users get `next_chat_index` advanced past the highest recovered `C*` chat id.
path provides
adapter/matrix/reconcile.py Matrix bootstrap reconciliation helpers and structured report objects.
path provides
tests/adapter/matrix/test_reconcile.py Regression coverage for startup and single-room reconciliation behavior.
from to via pattern
adapter/matrix/reconcile.py adapter/matrix/store.py set_user_meta and set_room_meta restore Matrix metadata set_(user|room)_meta
from to via pattern
adapter/matrix/reconcile.py core/chat.py chat_mgr.get_or_create repairs missing `chat:*` rows chat_mgr.get_or_create
Create the non-destructive Matrix reconciliation layer that Phase 01.1 depends on.

Purpose: Per D-01 through D-07, the adapter must stop treating local SQLite state as the only truth in dev. Startup and recovery code need a single helper module that can rebuild local metadata from the homeserver room graph without creating duplicate Spaces or chats. Output: adapter/matrix/reconcile.py with full-run and single-room recovery helpers, plus targeted pytest coverage.

<execution_context> @/Users/a/.codex/get-shit-done/workflows/execute-plan.md @/Users/a/.codex/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01.1-matrix-restart-reconciliation-and-dev-reset-workflow/01.1-CONTEXT.md @.planning/phases/01.1-matrix-restart-reconciliation-and-dev-reset-workflow/01.1-RESEARCH.md @.planning/phases/01-matrix-qa-polish/01-01-SUMMARY.md @adapter/matrix/store.py @adapter/matrix/handlers/auth.py @core/chat.py @tests/adapter/matrix/test_invite_space.py From `adapter/matrix/store.py`:
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

From core/chat.py:

async def get_or_create(
    self,
    user_id: str,
    chat_id: str,
    platform: str,
    surface_ref: str,
    name: str | None = None,
) -> ChatContext

From Phase 01 room metadata shape:

{
    "room_type": "chat",
    "chat_id": "C4",
    "display_name": "Чат 4",
    "matrix_user_id": "@alice:example.org",
    "space_id": "!space:example.org",
}
Task 1: Add reconciliation module for startup and single-room recovery adapter/matrix/reconcile.py, tests/adapter/matrix/test_reconcile.py adapter/matrix/store.py, adapter/matrix/handlers/auth.py, core/chat.py, tests/adapter/matrix/test_invite_space.py, .planning/phases/01.1-matrix-restart-reconciliation-and-dev-reset-workflow/01.1-CONTEXT.md - Test 1: `reconcile_matrix_state(...)` recreates missing `matrix_user:*`, `matrix_room:*`, and `chat:*` entries from joined Matrix rooms without calling `room_create`. - Test 2: `reconcile_matrix_state(...)` leaves already-correct local metadata intact and reports restored vs skipped/conflicting rooms. - Test 3: `reconcile_single_room(...)` can repair one `unregistered:{room_id}` chat room on demand and recompute `next_chat_index` for that user. - Test 4: Space rooms or unrelated joined rooms are skipped, not converted into chat rows. Create `adapter/matrix/reconcile.py` as the authoritative recovery module for this phase. Implement a small, explicit API that Plan 02 can wire directly:
async def reconcile_matrix_state(client: Any, store: StateStore, chat_mgr: ChatManager) -> dict: ...
async def reconcile_single_room(
    client: Any, store: StateStore, chat_mgr: ChatManager, room_id: str, matrix_user_id: str
) -> dict: ...

Inside this module, add focused private helpers as needed for room classification, extracting room names, parsing C<number> ids, and recomputing next_chat_index. Keep the logic non-destructive per D-04:

  • never call room_create, room_invite, or provisioning code from handlers/auth.py
  • prefer already-hydrated room data from the post-sync client object, and only fall back to explicit room-state fetches if required for room classification
  • rebuild only the minimal metadata required by D-03: matrix_user:*, matrix_room:*, and missing chat:{user}:{chat_id} records
  • if chat:* exists but points at the wrong surface_ref, repair it from Matrix room metadata and include the fix in the returned report
  • derive next_chat_index from the highest recovered C<number> for that user instead of trusting stale local counters

Return a structured reconciliation report with stable keys such as: joined_rooms, restored_user_meta, restored_room_meta, restored_chat_rows, repaired_chat_rows, skipped_rooms, and conflicts.

Write tests/adapter/matrix/test_reconcile.py with lightweight SimpleNamespace/fake-client fixtures following the existing Matrix test style. Cover both full startup reconciliation and reconcile_single_room(...). Assert that no provisioning calls are made during reconciliation, because D-04 forbids creating new Space/room topology while recovering local state. cd /Users/a/MAI/sem2/lambda/surfaces-bot && pytest tests/adapter/matrix/test_reconcile.py -q <acceptance_criteria>

  • adapter/matrix/reconcile.py exports reconcile_matrix_state and reconcile_single_room.
  • Reconciliation restores missing matrix_user:*, matrix_room:*, and chat:* entries for already-joined Matrix chat rooms per D-02 and D-03.
  • Reconciliation does not call room_create or otherwise provision new server-side rooms per D-04.
  • The report returned by reconciliation clearly distinguishes restored items, skipped rooms, and conflicts.
  • tests/adapter/matrix/test_reconcile.py proves next_chat_index is recomputed from recovered chat ids rather than stale local state. </acceptance_criteria> The repository has an executable, tested reconciliation layer that can rebuild local Matrix metadata after dev-state loss without duplicating server-side rooms.
Run `pytest tests/adapter/matrix/test_reconcile.py -q` and confirm startup and single-room reconciliation paths are covered.

<success_criteria>

  • Matrix recovery logic exists as a dedicated module instead of being scattered through handlers.
  • Reconciliation is idempotent, non-destructive, and sufficient to restore routing/chat metadata from existing Matrix rooms.
  • Plan 02 can wire startup and first-access recovery by calling exported functions rather than inventing new recovery logic. </success_criteria>
After completion, create `.planning/phases/01.1-matrix-restart-reconciliation-and-dev-reset-workflow/01.1-01-SUMMARY.md`