diff --git a/benchmark/README.md b/benchmark/README.md index 15fc76cd7c..e4a1c1cad2 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -874,6 +874,9 @@ runtime receipt 绑定摘要;programmatic adapter 也可指定已放入 guest 失败后,修复声明不得把后来的状态补记成同一原点。评测参与者使用上文明确的 公开 SForge fork/pin 和 Python 3.12;普通 upstream 安装缺少该 seam 时明确 拒绝。Codex 原生会话的真实分页/compaction 与隔离 fork 须单独验证。 +中途原生捕获将实际 TurnEnvelope 开关绑定到封存的 interrupted guard; +关闭开关的普通 guard 可以捕获,恢复时模式不匹配仍拒绝。旧产物缺少该字段 +时保留其原有开启语义;这只是历史校验兼容,不会为当前运行启用 TurnEnvelope。 评测机会及 incumbent 参与者也分配未占用的 ID,并在封存的 `point_metadata.evaluation_opportunity` 中记录实际映射;无 incumbent 时对应值为 null。 文件 witness 校验按该映射定位,不会把同名调用者文件误当原生候选。 diff --git a/benchmark/runtime/checkpoint_wake.py b/benchmark/runtime/checkpoint_wake.py index b83e9c54dd..299a2f0dbe 100644 --- a/benchmark/runtime/checkpoint_wake.py +++ b/benchmark/runtime/checkpoint_wake.py @@ -132,6 +132,7 @@ def _capture(self, held, deadline): "registry": self.env["LOOPX_REGISTRY"], "runtime_root": self.env["LOOPX_RUNTIME_ROOT"], "goal_id": self.env["LOOPX_GOAL_ID"], "agent_id": self.env["LOOPX_AGENT_ID"], "turn_instance_id": held["quota"]["heartbeat_receipt"]["turn_instance_id"], + "turn_envelope": self.receipt.get("turn_envelope", False), "capture_root": str(self.capture_root), "socket_path": self.socket_path, "decision_sha256": held["sha256"]} reader = readers.enter_context(native_checkpoint_reader(self.env, timeout=max(.1, window - time.time()))) diff --git a/benchmark/tests/test_native_checkpoint.py b/benchmark/tests/test_native_checkpoint.py index e6a26e7f79..9c6b58bc90 100644 --- a/benchmark/tests/test_native_checkpoint.py +++ b/benchmark/tests/test_native_checkpoint.py @@ -814,7 +814,8 @@ def forbidden_fork(*args, **kwargs): assert settled.progress["state"] == "settled" -def test_interrupted_cursor_requires_exact_unreleased_final_guard(tmp_path, monkeypatch): +@pytest.mark.parametrize("turn_envelope", [None, False, True], ids=["legacy", "ordinary", "envelope"]) +def test_interrupted_cursor_requires_exact_unreleased_final_guard(tmp_path, monkeypatch, turn_envelope): """A stopped command is eligible only at the declared pre-output boundary.""" import copy import shlex @@ -828,6 +829,10 @@ def test_interrupted_cursor_requires_exact_unreleased_final_guard(tmp_path, monk "--format", "json", "quota", "should-run", "--goal-id", "research", "--agent-id", "worker", "--turn-instance-id", "turn-1", "--turn-envelope", "--decision-output-root", guard["capture_root"], "--decision-handoff-socket", guard["socket_path"]] + if turn_envelope is not None: + guard["turn_envelope"] = turn_envelope + if turn_envelope is False: + argv.remove("--turn-envelope") command = shlex.join(["/bin/bash", "-lc", shlex.join(argv)]) item = {"type": "commandExecution", "id": "guard-call", "command": command, "cwd": str(tmp_path), "status": "failed", "exitCode": 137, "aggregatedOutput": None} @@ -845,6 +850,19 @@ def test_interrupted_cursor_requires_exact_unreleased_final_guard(tmp_path, monk rendered[-1]["items"][-1]["command"] = shlex.join(["/bin/bash", "-lc", "LOOPX_TURN=turn-1\n" + shlex.join(argv).replace("--turn-instance-id turn-1", '--turn-instance-id "${LOOPX_TURN:?}"')]) _verify_interrupted_guard(rendered, guard) + # A caller cannot change the captured presentation/authority mode on restore. + opposite = list(argv) + if "--turn-envelope" in opposite: + opposite.remove("--turn-envelope") + else: + opposite.append("--turn-envelope") + changed = copy.deepcopy(turns) + changed[-1]["items"][-1]["command"] = shlex.join(["/bin/bash", "-lc", shlex.join(opposite)]) + with pytest.raises(ValueError, match="routes or identity"): + _verify_interrupted_guard(changed, guard) + for invalid in [None, 0, 1, "false"]: + with pytest.raises(ValueError, match="must be boolean"): + _verify_interrupted_guard(turns, {**guard, "turn_envelope": invalid}) variants = [] for field, value in [("aggregatedOutput", "score already exposed"), ("cwd", "/elsewhere"), ("status", "completed"), ("command", shlex.join(["/bin/bash", "-lc", shlex.join(argv) + "; touch later"]))]: diff --git a/benchmark/tests/test_native_checkpoint_handoff.py b/benchmark/tests/test_native_checkpoint_handoff.py index c56abcc2af..a30188d486 100644 --- a/benchmark/tests/test_native_checkpoint_handoff.py +++ b/benchmark/tests/test_native_checkpoint_handoff.py @@ -742,6 +742,7 @@ def response(payload, index, message): native = manifest["point_metadata"]["native_session"] assert "completed_turn_id" not in native assert native["interrupted_guard"]["native_call_id"] == "call_midwake" + assert native["interrupted_guard"]["turn_envelope"] is False assert native["interrupted_guard"]["decision_sha256"] == event["decision_sha256"] # Reconstruct the earlier captured store after the source has # already continued. Fixed guest paths require an isolated home; diff --git a/loopx/hosts/codex_checkpoint.py b/loopx/hosts/codex_checkpoint.py index 3272ee3d96..b5f609b4e6 100644 --- a/loopx/hosts/codex_checkpoint.py +++ b/loopx/hosts/codex_checkpoint.py @@ -106,10 +106,15 @@ def arguments(command): except (SystemExit, ValueError) as error: raise ValueError("native pending guard arguments are invalid") from error args = arguments(item.get("command", "")) + # Older sealed interrupted guards were captured with mandatory envelopes. + # New captures bind the explicit execution mode; neither format opts in. + turn_envelope = guard.get("turn_envelope", True) + if not isinstance(turn_envelope, bool): + raise ValueError("native pending guard envelope mode must be boolean") expected = {"command": "quota", "quota_command": "should-run", "format": "json", "registry": guard["registry"], "runtime_root": guard["runtime_root"], "goal_id": guard["goal_id"], "agent_id": guard["agent_id"], - "turn_instance_id": guard["turn_instance_id"], "turn_envelope": True, + "turn_instance_id": guard["turn_instance_id"], "turn_envelope": turn_envelope, "decision_output_root": guard["capture_root"], "decision_output_dir": None, "decision_handoff_socket": guard["socket_path"]} if any(args.get(key) != value for key, value in expected.items()):