From e0cb45e87536c81f67ad2be6173fb92917467881 Mon Sep 17 00:00:00 2001 From: Yehya Kin Date: Sat, 8 Aug 2026 18:59:25 +0800 Subject: [PATCH] fix: use host launch identity proof --- .agents/skills/sol-control/SKILL.md | 26 +++++++++----- .../sol-control/references/orchestration.md | 29 +++++++++------ .../sol-control/references/runtime-notes.md | 36 +++++++++++++------ .codex/agents/sol-controller.toml | 2 +- tests/fixtures/forward-cases.json | 3 +- tests/test_hybrid_routing.py | 10 ++++++ 6 files changed, 74 insertions(+), 32 deletions(-) diff --git a/.agents/skills/sol-control/SKILL.md b/.agents/skills/sol-control/SKILL.md index becc331..c6b6eb5 100644 --- a/.agents/skills/sol-control/SKILL.md +++ b/.agents/skills/sol-control/SKILL.md @@ -39,15 +39,23 @@ a permanent agent team. - Route to **Terra High** for cross-module work, long-context investigation, ambiguous debugging, shared interface judgment, or high-risk implementation. - Start every custom agent with a fresh context: set `fork_turns="none"` and use - the first turn only as an identity handshake. The parent launch record proves - the requested `agent_type` and fork mode; the child reports its runtime model, - reasoning effort, and effective permission boundary. No task execution or - file write is allowed during this handshake. -- After the handshake matches the expected custom-agent configuration, send the - complete minimal plan or task packet to that same agent. Never combine a - custom `agent_type` with a full-history fork; a full-history custom-agent fork - is invalid and fails closed. If the exact model identity, reasoning effort, - selected agent, fork mode, or permission is mismatched or unprovable, do not + the first turn only as an identity handshake. The authoritative Host/tool + contract plus the parent launch record must prove the selected `agent_type`, + fork mode, model, and reasoning effort. The child is not asked to self-report + runtime identity that its surface cannot observe; it reports the effective + permission boundary, its operational constraint, and that it performed no + task, write, or subagent launch. No task execution or file write is allowed + during this handshake. +- After the combined proof matches the expected custom-agent configuration, + send the complete minimal plan or task packet to that same agent. Sol must be + operationally read-only: require either an enforced read-only sandbox or a + Host-owned before/after changed-path check proving zero Sol writes. Never + combine a custom `agent_type` with a full-history fork; a full-history + custom-agent fork is invalid and fails closed. Configuration text, an agent + label, or a child's unsupported identity claim is not authoritative proof. If + the Host/tool contract does not expose the exact role-to-model mapping, or if + the exact model identity, reasoning effort, selected agent, fork mode, + permission boundary, or no-write proof is mismatched or unprovable, do not send the task: **Fail Closed** and return `BLOCKED`. - One file has one owner for the whole run. Only when Luna's first failure happens before Luna writes any owned file may Sol escalate the same task and diff --git a/.agents/skills/sol-control/references/orchestration.md b/.agents/skills/sol-control/references/orchestration.md index a8f32e5..8030bed 100644 --- a/.agents/skills/sol-control/references/orchestration.md +++ b/.agents/skills/sol-control/references/orchestration.md @@ -7,12 +7,14 @@ completion decision; Luna Max or Terra High owns bounded execution. - Explicit `$sol-control` invocation starts Sol. - The Host starts `sol-controller` with `fork_turns="none"` for an identity-only - handshake. The launch record proves requested `agent_type` and fork mode; Sol - reports its actual runtime model, effort, and permission boundary without - planning or writing. Only after they match does the Host send the plan request - to that same Sol. Every worker uses the same two-turn handshake before it - receives a task packet. A full-history custom-agent fork is invalid and fails - closed. + handshake. The authoritative Host/tool contract and launch record prove the + requested `agent_type`, fork mode, model, and reasoning effort. Sol reports + its effective permission boundary, operational read-only constraint, and zero + task/write/subagent activity without planning or writing. The child is not + asked to self-report runtime identity that the surface cannot expose. Only + after the combined proof matches does the Host send the plan request to that + same Sol. Every worker uses the same two-turn handshake before it receives a + task packet. A full-history custom-agent fork is invalid and fails closed. - Ordinary simple work without explicit invocation remains direct. - Planning-only or review-only work may stop after Sol and use zero workers (and therefore zero Luna workers). - Execution work uses the minimum useful number of workers selected by Sol. @@ -23,11 +25,16 @@ mechanical, or high-throughput work. Route Terra High to cross-module work, long-context investigation, ambiguous debugging, shared interface judgment, or high-risk implementation. Terra never plans or approves the overall task. -Before task execution or any write, combine the parent launch record with the -child's identity-handshake result to prove exact model identity, reasoning -effort, selected custom agent, and effective inherited permission boundary. If -that proof is unavailable, do not send the task: **Fail Closed** and return -`BLOCKED` rather than substituting a nearby model. +Before task execution or any write, combine the authoritative Host/tool role +mapping, parent launch record, and child's permission/no-side-effect handshake +to prove exact model identity, reasoning effort, selected custom agent, fork +mode, and effective inherited permission boundary. Configuration text, an agent +label, or a child's unsupported identity claim is not authoritative proof. Sol +must have either an enforced read-only sandbox or a Host-owned before/after +changed-path check proving zero Sol writes after every Sol turn. If any required +proof is unavailable or mismatched, do not send the task: **Fail Closed** and +return `BLOCKED` rather than substituting a nearby model or silently weakening +the read-only boundary. For authorized execution, a plan is not a stop point. Stop or pause only for a new permission request, an irreversible choice requiring confirmation, or a diff --git a/.agents/skills/sol-control/references/runtime-notes.md b/.agents/skills/sol-control/references/runtime-notes.md index 3b226a7..c68a710 100644 --- a/.agents/skills/sol-control/references/runtime-notes.md +++ b/.agents/skills/sol-control/references/runtime-notes.md @@ -53,12 +53,20 @@ or review contract. ## Exact runtime proof -Configuration text and agent names alone are not proof of execution identity. -Every custom agent uses a two-turn gate. Its first turn is an identity-only -handshake: the parent retains the requested `agent_type` and `fork_turns="none"` -launch record, while the child reports the actual runtime model, reasoning -effort, and effective permission boundary. The parent sends the real plan or -task packet to that same agent only after the combined evidence matches: +Configuration text, agent names, and unsupported child identity claims are not +proof of execution identity. Every custom agent uses a two-turn gate. Its first +turn is an identity-only handshake. Exact selection proof is the combination of: + +- an authoritative Host/tool contract that exposes the fixed custom-role model + and reasoning-effort mapping; +- the parent launch record containing the requested `agent_type` and + `fork_turns="none"`; and +- the child's report of its effective permission boundary, operational + constraint, and zero task/write/subagent activity. + +The child is not asked to self-report a runtime model or reasoning effort that +its surface cannot observe. The parent sends the real plan or task packet to the +same agent only after the combined evidence matches: - `sol-controller`: exact model `gpt-5.6-sol`, reasoning effort `high`, read-only; @@ -69,10 +77,18 @@ task packet to that same agent only after the combined evidence matches: with effective access no broader than the inherited parent boundary and the `workspace-write` ceiling. -No task execution or file write is allowed during the identity handshake. If -any exact selection cannot be proved, **Fail Closed** without sending the task. -Do not silently substitute a nearby model, effort, role, or permission profile, -and do not use an agent label to spoof identity. +Sol remains operationally read-only. Prefer an enforced read-only sandbox. If a +surface inherits broader technical access, the Host must own the repository +baseline and perform a before/after changed-path check after every Sol turn; any +Sol-authored change fails closed. A child promise alone is not sufficient +no-write evidence. + +No task execution, file write, or subagent launch is allowed during the identity +handshake. If the Host/tool contract does not expose an authoritative exact +role-to-model mapping, or if any selection, permission, fork, or no-write proof +cannot be established, **Fail Closed** without sending the task. Do not silently +substitute a nearby model, effort, role, or permission profile, and do not use +an agent label or a child's unobservable self-report to spoof identity. Luna and Terra must not spawn or create subagents. Every custom-agent launch, including the initial `sol-controller`, must use `fork_turns="none"` plus the diff --git a/.codex/agents/sol-controller.toml b/.codex/agents/sol-controller.toml index 37666ab..0a01e57 100644 --- a/.codex/agents/sol-controller.toml +++ b/.codex/agents/sol-controller.toml @@ -12,7 +12,7 @@ Understand the user's actual goal and define observable completion criteria. Pro Route execution without creating a standing agent team: Luna Max is only for clear, low-ambiguity, falsifiable, small-context, mechanical or high-throughput work. Terra High is only for cross-module work, long-context investigation, ambiguous debugging, shared-interface judgment, or high-risk implementation. Sol is the only controller and final reviewer; Terra does not plan or approve the overall task. Schedule independent tasks with non-overlapping write scopes in parallel up to live capacity. Schedule dependent, overlapping, or uncertain tasks sequentially. Every writable file, including shared integration files, must have one owner for the entire run. -Before dispatch, prove the exact custom agent, model, reasoning effort, and effective inherited permission boundary. If model identity or reasoning effort cannot be proved, Fail Closed and return BLOCKED. Only when Luna's first failure happens before Luna writes any owned file may Sol make one bounded escalation of the same task and unchanged scope to Terra instead of unbounded Luna retries. If Luna has written any owned file before failing, Luna retains all ownership; only the original Luna owner may receive one focused fix, otherwise return BLOCKED. Terra's write state is never the escalation gate, so do not route an already-written file to a different worker. +Before dispatch, require the Host to prove the exact custom agent, model, reasoning effort, and fork mode from an authoritative Host/tool role mapping plus the parent launch record; configuration text, an agent label, or a child's unsupported identity claim is not authoritative proof. Use the child's handshake only for its effective permission boundary, operational constraint, and zero task/write/subagent activity. If any identity, permission, fork, or no-write proof cannot be established, Fail Closed and return BLOCKED. Only when Luna's first failure happens before Luna writes any owned file may Sol make one bounded escalation of the same task and unchanged scope to Terra instead of unbounded Luna retries. If Luna has written any owned file before failing, Luna retains all ownership; only the original Luna owner may receive one focused fix, otherwise return BLOCKED. Terra's write state is never the escalation gate, so do not route an already-written file to a different worker. Remain read-only and do not perform bulk mechanical implementation. Review each worker's actual changed files, complete diff, verification output, artifacts, and evidence against the original request and every completion criterion. Evidence must bind to the final candidate by commit+diff identity or an exact changed-file snapshot; if the candidate changes after verification, treat old evidence as stale and rerun affected verification. Transport/spawn completed is delivery only, never task PASS; require structured worker PASS, Verification/Evidence/changed-path proof, and Sol review. Do not accept PASS without sufficient evidence and do not accept out-of-scope writes. diff --git a/tests/fixtures/forward-cases.json b/tests/fixtures/forward-cases.json index bca27d5..7c8435f 100644 --- a/tests/fixtures/forward-cases.json +++ b/tests/fixtures/forward-cases.json @@ -413,7 +413,8 @@ "resume": "not_applicable" }, "required_assertions": [ - "the launch record and child handshake must prove model identity and selection", + "the authoritative Host/tool role mapping and launch record must prove model identity and selection", + "the child handshake proves permissions and no side effects without inventing an unobservable model self-report", "Fail Closed prevents silent model substitution", "no Luna or Terra task execution or write occurs when identity is unavailable" ] diff --git a/tests/test_hybrid_routing.py b/tests/test_hybrid_routing.py index 111bb98..2eab762 100644 --- a/tests/test_hybrid_routing.py +++ b/tests/test_hybrid_routing.py @@ -151,11 +151,21 @@ def test_unprovable_model_identity_fails_closed_before_execution(self) -> None: skill_files = [path for path in SKILL_ROOT.rglob("*") if path.is_file()] text = compact("\n".join(read_text(path) for path in skill_files)) self.assertRegex(text, r"(?i)Fail\s+Closed|失败关闭") + self.assertRegex( + text, + r"(?is)authoritative\s+(?:Host/tool|Host|tool)\s+(?:contract|role\s+mapping).{0,320}" + r"(?:parent\s+)?launch\s+record", + ) self.assertRegex( text, r"(?is)(?:exact\s+model|model\s+identity|模型(?:身份|选择)).{0,240}" r"(?:cannot|unable|unprovable|无法|不可证明).{0,240}(?:blocked|fail\s+closed|关闭)", ) + self.assertRegex( + text, + r"(?is)child.{0,120}(?:not\s+asked|unsupported|cannot\s+observe).{0,220}" + r"(?:runtime\s+model|runtime\s+identity|model)", + ) self.assertRegex( text, r"(?is)identity(?:-only)?\s+handshake.{0,360}(?:no|without).{0,120}"