@@ -149,10 +149,12 @@ def wait(service, operation="analysis-1"):
149149 pytest .fail (str (service .read (operation )))
150150
151151
152- def test_confirmed_wake_reaches_native_acceptance_through_real_delegation_and_turn (service ):
152+ @pytest .mark .parametrize ("mcp_profile" , ["delegation-default" , "explicit-null" , "unmatched-null" ])
153+ def test_confirmed_wake_reaches_native_acceptance_through_real_delegation_and_turn (service , mcp_profile ):
153154 """Real detached worker/CLI/Turn; synthetic native transport, no model/effect."""
154155 from examples import operation_action_fixtures as fixtures
155156 from loopx .chat_action_store import ChatActionStore
157+ from loopx .cli import build_parser
156158 from loopx .control_plane .collaboration .operation_wake import dispatch_confirmed_operation_wake
157159 from loopx .control_plane .turn_driver .codex_cli import load_codex_cli_session
158160 from loopx .control_plane .turn_driver .codex_operation_host import run_codex_operation_host , operation_tool_handler
@@ -161,22 +163,42 @@ def test_confirmed_wake_reaches_native_acceptance_through_real_delegation_and_tu
161163
162164 root , runner = service
163165 executable = root / "fixture-codex"
164- executable .write_text (FAKE_SERVER )
166+ native_starts = root / "native-starts"
167+ startup_probe = (
168+ "from pathlib import Path\n "
169+ f"counter = Path({ str (native_starts )!r} )\n "
170+ "counter.write_text(str(int(counter.read_text()) + 1 if counter.exists() else 1))\n "
171+ )
172+ executable .write_text (FAKE_SERVER .replace ('thread = "owned-app-server-thread"' ,
173+ startup_probe + 'thread = "owned-app-server-thread"' ))
165174 executable .chmod (0o700 )
166175 config = json .loads (runner .config .read_text ())
167176 binding = config ["bindings" ][0 ]
168177 binding ["host_args" ] = ["--host" , "codex-cli" , "--codex-bin" , str (executable ),
169178 "--codex-operation-tools" , "--codex-model" , "test-model" , "--codex-reasoning-effort" , "xhigh" ]
179+ if mcp_profile == "explicit-null" :
180+ # Existing operator option, not a new profile or a worker-selected grant.
181+ binding ["host_args" ] += ["--codex-mcp-server-json" , "null" ]
170182 runner .config .write_text (json .dumps (config ))
171183 argv = runner ._execution_arguments (binding , "preparation" )
172- mcp_server = json .loads (argv [argv .index ("--codex-mcp-server-json" ) + 1 ])
184+ parsed = build_parser ().parse_args (["turn" , "run-once" , "--goal-id" , runner .goal_id ,
185+ "--agent-id" , binding ["agent_id" ], "--todo-id" , binding ["todo_id" ], * argv ])
186+ if mcp_profile == "explicit-null" :
187+ assert argv .count ("--codex-mcp-server-json" ) == 2
188+ assert parsed .codex_mcp_server_json is None
189+ else :
190+ assert parsed .codex_mcp_server_json ["name" ] == "loopx_delegation"
191+ # Reproduce an original standalone operation Session: do NOT prepare it
192+ # with the injected delegation MCP just to make the later resume match.
193+ mcp_server = parsed .codex_mcp_server_json if mcp_profile == "delegation-default" else None
173194 lineage = {"goal_id" : runner .goal_id , "agent_id" : binding ["agent_id" ], "todo_id" : binding ["todo_id" ]}
174195 request = _request ()
175196 request ["turn_envelope" ].update (goal_id = runner .goal_id , agent_id = binding ["agent_id" ])
176197 request ["turn_envelope" ]["action" ]["selected_todo" ]["todo_id" ] = binding ["todo_id" ]
177198 run_codex_operation_host (request , runtime_root = runner .root , registry_path = runner .registry ,
178199 project = Path (binding ["workspace" ]), codex_bin = str (executable ), model = "test-model" ,
179200 reasoning_effort = "xhigh" , mcp_server = mcp_server , timeout_seconds = 5 )
201+ assert native_starts .read_text () == "1"
180202 session = load_codex_cli_session (runner .root , lineage = lineage )
181203 handler = operation_tool_handler (runtime_root = runner .root , registry_path = runner .registry ,
182204 lineage = lineage , session_id = session ["session_id" ], profile_digest = session ["operation_profile_digest" ],
@@ -203,16 +225,30 @@ def test_confirmed_wake_reaches_native_acceptance_through_real_delegation_and_tu
203225 assert receipt ["state" ] == "delegation_requested" , receipt
204226 result = wait (runner , receipt ["operation_id" ])
205227 stored = store .load (proposal ["proposal_id" ])
206- assert stored ["operation" ]["host_start" ] is not None , result
207- assert stored ["operation" ]["host_start" ]["route" ]["thread_id" ] == session ["session_id" ]
228+ resumed = load_codex_cli_session (runner .root , lineage = lineage )
229+ assert resumed ["session_id" ] == session ["session_id" ]
230+ assert resumed ["operation_profile_digest" ] == session ["operation_profile_digest" ]
208231 assert stored ["operation" ].get ("agent_handoff" ) is None
209232 assert stored ["operation" ]["outcome" ] is None
233+ # Omitting the original null override must still fail closed, rather than
234+ # changing/replacing the original Session to bypass the profile fence.
235+ if mcp_profile == "unmatched-null" :
236+ assert result ["status" ] == "rejected" , result
237+ assert stored ["operation" ].get ("host_start" ) is None , result
238+ assert native_starts .read_text () == "1" # refused before native process start
239+ assert stored ["status" ] == confirmed ["status" ]
240+ assert stored ["operation" ]["confirmation" ] == confirmed ["operation" ]["confirmation" ]
241+ return
242+ assert native_starts .read_text () == "2"
243+ assert stored ["operation" ]["host_start" ] is not None , result
244+ assert stored ["operation" ]["host_start" ]["route" ]["thread_id" ] == session ["session_id" ]
210245 # Fixture deliberately waits: startup is not validated domain completion.
211246 assert result ["status" ] == "rejected"
212247 journal = json .loads (runner .path (receipt ["operation_id" ]).read_text ())
213248 assert stored ["operation" ]["host_start" ]["turn_key" ] == journal ["turn_key" ]
214249 assert dispatch_confirmed_operation_wake (stored , runtime_root = runner .root ,
215250 configuration = wake_config )["state" ] == "existing_delegation"
251+ assert native_starts .read_text () == "2"
216252
217253
218254def test_detached_result_reconnects_without_duplicate_execution (service ):
0 commit comments