Task 4: stale room blocking + agent_id binding
- MatrixBot._check_agent_routing: blocks normal messages when user has no
selected agent or room is bound to a different agent
- agent_routing_enabled flag on MatrixRuntime activates the check only
in real multi-agent mode (RoutedPlatformClient)
- make_handle_new_chat now writes agent_id into new room metadata when
user already has a selected agent
Task 5: durable restart state tests
- test_restart_persistence.py proves selected_agent_id, room agent_id,
platform_chat_id, and the sequence counter all survive SQLiteStore
close/reopen; also covers clean startup with no prior state
Users can now list available agents with !agent and select one by
number. Selection persists in user metadata (selected_agent_id). If the
current room has no agent binding yet, selecting an agent binds it
immediately so the user can start messaging without !new.
Also updates the dispatcher test to reflect that real-mode platform is
now RoutedPlatformClient, not a bare RealPlatformClient.
Instead of calling a /reset endpoint on platform-agent, !reset now
generates a new thread_id (platform_chat_id) for the room. The old
WebSocket connection is closed and the next message creates a fresh
context automatically. No platform changes required.
AgentApiWrapper._build_ws_url was building /v1/agent_ws/{chat_id}/
which does not exist in platform-agent. Fixed to /agent_ws/?thread_id={chat_id}
to match the actual endpoint and query-param isolation scheme.
Also simplify Matrix MVP settings handlers to MVP_UNAVAILABLE stubs
and add handle_unknown_command for unregistered !commands.
- harden Matrix onboarding/chat lifecycle after manual QA
- refresh README and Matrix docs to match current behavior
- add local ignores for runtime artifacts and include current planning/report docs
Closes#7Closes#9Closes#14
- Seed invite tests with explicit next_chat_index progression instead of C1 assumptions
- Separate Matrix room ids from logical chat ids in dispatcher coverage
- Verify the full Matrix adapter suite against the tightened assertions
- Assert skills text no longer includes reaction-era labels
- Require converter to drop reaction callback support
- Lock !settings dashboard to read-only snapshot copy