1717from loopx .capabilities .manager_context import pending
1818from loopx .capabilities .manager_context .inspection import ManagerInspection , CONTEXT_TOOL_NAME
1919from loopx .capabilities .manager_context .roundtrip import drain , reply_status
20+ from tests .control_plane .canonical_authority_fixture import (
21+ empty_todo_display ,
22+ initialize_canonical_source_fixture ,
23+ isolate_sqlite_runtime ,
24+ )
2025
2126
2227def test_failed_stop_keeps_active_claim_and_retry_preserves_unrelated_work (tmp_path ):
@@ -127,8 +132,9 @@ def stop():
127132 controller .close ()
128133
129134
130- @pytest .fixture
131- def project (tmp_path ):
135+ @pytest .fixture (params = ["file" , "sqlite" ])
136+ def project (tmp_path , monkeypatch , request ):
137+ isolate_sqlite_runtime (tmp_path , monkeypatch )
132138 root = tmp_path / "runtime"
133139 registry = tmp_path / "registry.json"
134140 goals = []
@@ -142,6 +148,10 @@ def project(tmp_path):
142148 goals .append ({"id" : goal_id , "domain" : title , "repo" : str (repo ),
143149 "state_file" : state .name , "status" : "active-read-only" ,
144150 "coordination" : {"registered_agents" : agents , "agent_model" : "peer_v1" }})
151+ if request .param is not None :
152+ initialize_canonical_source_fixture (root , goal_id , state_path = state , provider = request .param )
153+ # A stale display must not replace the canonical Todo source.
154+ empty_todo_display (state )
145155 registry .write_text (json .dumps ({"schema_version" : "0.1" , "common_runtime_root" : str (root ),
146156 "goals" : goals }), encoding = "utf-8" )
147157 return root , registry , tmp_path / "research"
@@ -170,11 +180,28 @@ def collect(**kwargs):
170180 assert [s ["source_id" ] for s in reader .sources ()] == ["local" ]
171181 result = reader .read (CONTEXT_TOOL_NAME , {"view" : "todos" , "goal_id" : "research" })
172182 assert result ["ok" ] and "Verify corrected source" in json .dumps (result )
183+ assert result ["source" ]["status" ] == "read" and not result ["unknown" ]
184+ assert [row ["title" ] for row in result ["rows" ]] == ["Verify corrected source" ]
173185 assert reader .read (CONTEXT_TOOL_NAME , {"view" : "todos" , "goal_id" : "other" })["ok" ] is False
174186 assert reader .read (CONTEXT_TOOL_NAME , {"view" : "sources" , "source_id" : "ssh:other" }) == {
175187 "ok" : False , "error" : "source_outside_available_scope" }
176188
177189
190+ @pytest .mark .parametrize ("project" , [None ], indirect = True , ids = ["unmigrated" ])
191+ def test_project_todo_read_refuses_unmigrated_markdown (project ):
192+ root , registry , repo = project
193+ state = repo / "ACTIVE_GOAL_STATE.md"
194+ before = state .read_bytes ()
195+ context = collect_manager_turn_context (registry ,
196+ {"channel_id" : "goal.research" , "goal_id" : "research" }, root )
197+ reader = ManagerInspection (context = context , registry_path = registry , runtime_root = root ,
198+ owner_scope = True , channel_id = "goal.research" , scope_valid = lambda : True , record = lambda _ : None )
199+ result = reader .read (CONTEXT_TOOL_NAME , {"view" : "todos" , "goal_id" : "research" })
200+ assert result ["source" ]["status" ] == "unavailable"
201+ assert result ["unknown" ] and result ["matched" ] is None and result ["rows" ] == []
202+ assert state .read_bytes () == before
203+
204+
178205def test_project_chat_nested_cli_handoff_returns_once_after_restart (project , monkeypatch ):
179206 root , registry , repo = project
180207 before = registry .read_bytes (), (repo / "ACTIVE_GOAL_STATE.md" ).read_bytes ()
0 commit comments