Repository navigation
Preserve the original ready decision across native claims and retries - #8118
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机 / Motivation
使用原生 Host 接续已认领工作的 Agent,需要在重试时读到第一次 ready guard 保存的原始决策。旧路径在保存后重新读取文件计算摘要,文件若在这一窗口被替换,替换内容可能被当作原观察;非普通文件还可能让恢复读取阻塞。修复后固定写入时的摘要,拒绝替换和非普通文件,恢复原文件后沿原 claim 继续。独立 File/SQLite 验证已确认修改 JSON 内容或仅改空白均会被拒绝,原 claim 和恢复命令保留,恢复原文件后可读且不重复认领或花费。本次范围是原生准备与私有快照读取的完整性修复;不增加新执行权限,不宣称真实模型采用、Windows ACL 或整个 C1/C2 已获资格。
改动思路 / Approach
正确性约束是保存的观察与原 journal/claim 一致;摘要由唯一写入者产生,普通文件校验集中在既有 IO 边界,guard 继续拥有资格和权限,Python 不新增决策规则。本 PR 的边界包括写入、原生准备、Hook 回读、journal 重试与公共 replan reader 的拒绝及恢复;隐藏的小回复仅服务同版 preparer。从原始请求到可用结果,无需重填已知信息或增加确认轮次。必要的 guard 资格检查仍在原 owner;单纯读取旧观察不能代替它。正向链路为普通 claim → 同一 Turn 的 ready guard → 完整私有 capture 与写入摘要 → Hook 回读 → 原观察恢复与接续。这是可独立回退的维护结果,不用完成整个上层研究项目才有价值。
具体改动 / Changes
审查全部 11 个文件的 base..head diff,head 为 6e0d0bc417e85001be693221e141aa2434ce258f,base 为 3c7e0935fd6697291c5c432e5267816b4a667cfa。六个生产文件负责同一条原生 IO 链,四个测试文件和双语 reference 解释对应边界。prepared-capture-reference 是内部、默认关闭的同版传输选项,真实注册与调用一起修改;不是新能力开关或第二份权限。共享 opener 合并原 trace 校验,但私有 UID、mode 与输入大小限制仍由原 caller 承担,公共历史 reader 没有被套入私有大小限制。
关键代码讲解
- write_decision_capture:摘要来自实际写入的 UTF-8 JSON 字节,保留 compact 编码、最后换行与原子发布;不再仅为算摘要重新打开文件。
- open_regular_capture:先取得 descriptor,再验证普通文件、目录项及 dev/inode 一致性,拒绝 symlink 与 FIFO。原 caller 的私有权限和大小检查仍在,公共历史读取没有新增大小上限。journal 的 compact 快路径仍保留旧版 pretty/reordered JSON 的类型敏感比较。
- execute_codex_execution_preparation:仍执行原生普通 claim,再检查同一 Goal/Agent/Todo/Turn 的 ready 结果。小回复只带 preparer 真正消费的字段及写入者摘要,不替代完整上下文。
- _emit_quota_result:先保存完整决策,再决定普通呈现或私有回复。
prepare_quota_capture在 guard 前拒绝六类不兼容组合;Hook 即使投影失败也保留原摘要、原 claim 和恢复路线。
语义与 CI 对齐
验收依据是修改前的 docs/reference/protocols/turn-envelope-v0.md,spec revision:3c7e0935fd6697291c5c432e5267816b4a667cfa。Native Turn Host capture → implemented:完整原观察只发布一次,journal 保持身份;错误身份、摘要或原文件必须拒绝,恢复原证据后继续,不能重跑 guard 替代。Captured replan reads / 捕获后的重规划读取 → implemented:公共 reader 仍绑定原始源与摘要,读取不重新准入或 spend。实现对应上述真实入口与正反例;本 PR 同步的说明不能反过来充当独立验收依据。复用既有 ready/claim 状态与原始 source 语义;私有传输字段保持局部用途,不增加权限或第二份执行状态。依当前仓库规定做本地必要验证;没有查询、轮询或等待远端 CI。
对主干的风险 / Risks
最强反例是 ready 文件在 guard 后或记录 claim 后被换成仍合法的 JSON,普通成功测试很容易漏掉这一窗口。另一个风险是 journal 持锁读取 FIFO。两类读取均会拒绝;恢复原文件后可继续,journal、已接收输入、原 claim 与零重复 spend 都被检查。旧版 compact/pretty JSON、bool/int/float 与 signed-zero 差异没有被简单字节比较破坏。
| 验证 | base | 当前 head |
|---|---|---|
| 替换 ready 文件空白,File/SQLite × 两个窗口 | 4 FAIL(仍接受替换) | 4 PASS(拒绝并可恢复) |
| 替换有效 JSON 内容的独立反例 | 4 FAIL(仍接受替换) | 4 PASS(拒绝并可恢复) |
| 原生 capture / preparation / journal / 公共 reader | 未重复整组 | 99 PASS |
| POSIX flag fallback / input retention | 未重复整组 | 104 PASS |
| 两个宽测模块 | 19 PASS / 36 FAIL | 20 PASS / 36 FAIL |
公开验证入口包括 uv run --extra test python -m pytest -q tests/control_plane/test_quota_execution_preparation.py 与 tests/control_plane/test_turn_host_decision_capture.py,以及 test_replan_reader_rejects_replaced_entries_and_recovers_original。真实 CLI 与隔离 File/SQLite 状态已执行;文件替换时序由 reviewer oracle 控制。Host/model 执行用 stub,不把这些结果当作真实模型采用证明。
36 项宽测失败已逐项核对完整 failing identity、message 和规范化堆栈,与 immutable base 相同;主要是旧测试索引 raw packet 字段,而当前 Host 默认输出 native navigation,另四项仍期待旧 recovery.path。规范化仅去除临时运行路径、内存地址、派生 reader 文件名及严格对应的未改动源码行号,保留真实 source hash。Python 3.14.8、59 个包及版本、锁文件、fixture 和这些失败函数的 AST 已对齐,不以相同失败数量代替归因。optional maintainability smoke 的完整输出也与 base 相同,指向未修改的既有 oversized function,未放宽阈值或新增例外。初版 reviewer oracle 曾误收集 helper tests,原运行保留;修正 collection 后的独立结果另外列出,没有删减原断言或把旧失败改成成功。额外 oracle 保留在本次本地验证,未作为新仓库测试提交,公开复现应从上述已提交测试入口开始。
strict TypeScript、配置内 17 文件 mypy、变更 Python 的 Ruff、完整 semantic vocabulary smoke、双语 RFC gate 与 diff 检查均 PASS。Goal-managed premerge 整体 PASS(exit 0):6 项 direct checks、19 项选中检查无阻断性失败,当前 CQR scope 核验有效;保留一项主干已有的 optional maintainability advisory。
我的整体评价 / Verdict
当前 exact head 未发现新的 actionable blocking finding,结论为 APPROVE。本次具名维护任务的可观察结果已闭合;长程执行维度为 preserved:原承诺、身份、重复恢复与结算边界仍在,未据此声称更高 benchmark 分数、真实模型理解或完整成本收益。用户体验维度为 improved:可信地拒绝替换并提供保留原 claim 的恢复入口,已有授权不增加确认轮次。检查的是原生 Host Hook、quota 和 replan reader 的文件及文本恢复路径,没有改动浏览器、App 或 Lark 的渲染页面,因此本次无需截图。无新增渲染表面;真实模型理解与打包 App/Lark 使用效果未在本次验证。
共享 IO 校验和写入者摘要属于同一条完整性保证;保留旧 journal 的类型敏感读取义务与普通 caller 呈现,未引入平行决策服务。保留现存诊断与平台验证边界,不把代码 review、原生 merge readiness 或维护者合入授权混为一体。任何 head/base 变化需要重新核验对应差异;本 review 不执行合入。
English verdict: APPROVE — the verified bounded repair preserves the original authority and recovery contract; disclosed integration and platform limits remain.
Outcome
A native Host can recover the exact decision that made its claimed Todo ready. On the target main, replacing that decision with a different JSON file after the ready check made the hook accept the replacement. Replacing a pending Turn's observation with a FIFO also made the real retry wait under the journal lock.
The guard now returns the digest produced by the capture writer and the small set of fields the Host uses to check the selected Todo and Turn. The consumer checks the original file against that digest before delivery. A failed read preserves the original claim and its recovery command. Regular-file checks also protect journal retries on hosts with and without a no-follow flag. Current compact observations take a fast path; historical, differently formatted observations retain the type-sensitive comparison.
The same regular-file reader now covers the public
quota replan-viewentrypoint. A symlink to identical JSON previously passed its semantic hash check. A FIFO with no writer blocked before validation. The reader rejects both, then accepts the original decision when it is restored. This adds no size cap to historical JSON and preserves its semantic digest.Validation
At
6e0d0bc417, the real CLI regression covers a regular file, symlink, FIFO and restoration. The wider staged and successor suites under the host presentation default returned 20 passes and 36 failures. Target main returned 19 passes and the same 36 failing test IDs. Neither result qualifies those suites as green.Reproduced both failures on main
3c7e0935fd. Tested substitutions immediately after the guard and after the Host records readiness, restoration of the original, and a second hook invocation on File and SQLite.Focused run at
c865bf3dapassed 107 tests and skipped 46 environment-dependent native cases. A separate run with native Codex enabled passed 107 tests covering the selected exec, app-server and code-mode paths, input retention and portable file opening. The remaining native matrix was not run.Two ready benchmark captures took 53,113 and 60,511 bytes each. Replaying their internal Host response produces 535 bytes each with the original digest, Todo and Turn. On four real substitute-and-restore cases the child returned 539 bytes for decision files of 49,807–49,833 bytes. The 10-request scripted model input on this standalone branch equalled main at 526,422 bytes. No paid task, token or score improvement is claimed.
Standard premerge initially lacked the isolated checkout's npm dependencies. After installation the full standard premerge run passed 6 direct and 19 selected checks, with one advisory about the same unrelated function on target main. The five pending slices also passed 98 checks together. Merge review remains open.
This independently reviewable part of #7430 targets the existing main readers and writers. It can be reverted without migrating stored records. The experimental history stays together in #7430.