157 lines
7.7 KiB
Markdown
157 lines
7.7 KiB
Markdown
---
|
|
phase: 01.1-matrix-restart-reconciliation-and-dev-reset-workflow
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- adapter/matrix/reconcile.py
|
|
- tests/adapter/matrix/test_reconcile.py
|
|
autonomous: true
|
|
requirements: []
|
|
|
|
must_haves:
|
|
truths:
|
|
- "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."
|
|
artifacts:
|
|
- path: "adapter/matrix/reconcile.py"
|
|
provides: "Matrix bootstrap reconciliation helpers and structured report objects."
|
|
- path: "tests/adapter/matrix/test_reconcile.py"
|
|
provides: "Regression coverage for startup and single-room reconciliation behavior."
|
|
key_links:
|
|
- from: "adapter/matrix/reconcile.py"
|
|
to: "adapter/matrix/store.py"
|
|
via: "set_user_meta and set_room_meta restore Matrix metadata"
|
|
pattern: "set_(user|room)_meta"
|
|
- from: "adapter/matrix/reconcile.py"
|
|
to: "core/chat.py"
|
|
via: "chat_mgr.get_or_create repairs missing `chat:*` rows"
|
|
pattern: "chat_mgr\\.get_or_create"
|
|
---
|
|
|
|
<objective>
|
|
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.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/Users/a/.codex/get-shit-done/workflows/execute-plan.md
|
|
@/Users/a/.codex/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<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
|
|
|
|
<interfaces>
|
|
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
|
|
```
|
|
|
|
From `core/chat.py`:
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
{
|
|
"room_type": "chat",
|
|
"chat_id": "C4",
|
|
"display_name": "Чат 4",
|
|
"matrix_user_id": "@alice:example.org",
|
|
"space_id": "!space:example.org",
|
|
}
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: Add reconciliation module for startup and single-room recovery</name>
|
|
<files>adapter/matrix/reconcile.py, tests/adapter/matrix/test_reconcile.py</files>
|
|
<read_first>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</read_first>
|
|
<behavior>
|
|
- 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.
|
|
</behavior>
|
|
<action>
|
|
Create `adapter/matrix/reconcile.py` as the authoritative recovery module for this phase. Implement a small, explicit API that Plan 02 can wire directly:
|
|
|
|
```python
|
|
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.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /Users/a/MAI/sem2/lambda/surfaces-bot && pytest tests/adapter/matrix/test_reconcile.py -q</automated>
|
|
</verify>
|
|
<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>
|
|
<done>The repository has an executable, tested reconciliation layer that can rebuild local Matrix metadata after dev-state loss without duplicating server-side rooms.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
Run `pytest tests/adapter/matrix/test_reconcile.py -q` and confirm startup and single-room reconciliation paths are covered.
|
|
</verification>
|
|
|
|
<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>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/01.1-matrix-restart-reconciliation-and-dev-reset-workflow/01.1-01-SUMMARY.md`
|
|
</output>
|