Repository navigation
Recover native execution preparation without repeating claims - #8307
loopx-agent wants to merge 1 commit into
Conversation
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
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
[P1] 旧捕获在升级路径可重新领取已释放租约。 用旧版 c0b6ade 领取后释放 epoch 1,在同一 session 重放未交付的旧捕获,新版用未出现过的 operation ID 再次领取并返回 ready,File、SQLite 均变成 active epoch 2。 ID 派生
[P2] 恢复提示持久化早于送达。 在 readback_sent 写入后、提示输出前终止进程,下一次 PostToolUse 和 SessionStart 均无恢复提示;原租约仍 active,同一来源不会再给回执。旧版的对应重入虽重复 claim/guard,但会给 ready。 提示标记
动机 / Motivation
Codex 原生 Hook 负责领取当前 Todo 的执行租约,并让宿主拿到同一 Turn 的就绪决定。 如果进程在领取后中断,恢复必须区分原领取是否提交、租约是否已退役、就绪结果是否交给宿主。旧路径会再次发起领取和准入,也可能重新激活已释放租约。 本次在真正调用前登记尝试,并为当前版本的新捕获绑定稳定操作 ID;实测它修复了同版本在领取后、guard 前中断的路径。旧捕获和恢复提示丢失仍有反例。 本次只修改原生 Context Hook 及回读指引,执行权仍来自普通 managed claim、原 Todo 与现有 lease owner。
改动思路 / Approach
保留 native session journal 绑定同源捕获;由普通 claim、lease provider 和原 should-run 验证实际执行。Hook 生成回执与恢复指引,局部 marker 没有独立执行权。 在 native session lock 内做一次预约合理。能重复读取的同源回执可复用原 owner;当前代码仍把本地标记当交付完成,旧捕获也没有原执行的兼容 fence。 保留单一的普通 claim 和准入 owner,先把原捕获可安全接回;本次无需增加产品状态或把所有 Host 迁移为新协议。
具体改动 / Changes
基线为 c0b6aded5d173dd474a22ff0b33955d4d93a7732。以既有捕获绑定、原同一 Todo/Turn 准入以及当前 task lease 条件作为验收。 基线规范
- 当前版本接回原执行。 同版本在普通 claim 提交后、ready guard 之前中断,File 与 SQLite 都返回原操作的只读回执及租约;两次后续 Hook 零次自动 claim/guard,同 Turn 手工确认 ready 且租约不变。
- 已释放的执行不可复活。 用旧版 c0b6ade 领取后释放 epoch 1,在同一 session 重放未交付的旧捕获,新版用未出现过的 operation ID 再次领取并返回 ready,File、SQLite 均变成 active epoch 2。
- 原结果可回读。 在 readback_sent 写入后、提示输出前终止进程,下一次 PostToolUse 和 SessionStart 均无恢复提示;原租约仍 active,同一来源不会再给回执。旧版的对应重入虽重复 claim/guard,但会给 ready。 同版本的 ready journal 已写入但宿主未收到回执时,PostToolUse 没有原地址,SessionStart 仍自动重跑一次 claim 和 guard;claim receipt 与 lease epoch 不变。
- 真实模型和成本。 旧捕获的租约复活和恢复地址丢失必须修复;模型实际收到上下文的成功率和完整成本没有验证。
关键代码讲解
native_execution_preparation_request 在 journal 锁内登记尝试;execute_codex_execution_preparation 调用普通 claim 和同一 Turn guard,并核对返回的操作 ID。handle_native_context_command 核对工作目录并分流恢复,但先写 ready 再投影给宿主。现有四个故障组合 覆盖同版本 guard 超时和释放,未覆盖旧版本和送达窗口。文档改动只描述这一路径。
对主干的风险 / Risks
同版本的 ready journal 已写入但宿主未收到回执时,PostToolUse 没有原地址,SessionStart 仍自动重跑一次 claim 和 guard;claim receipt 与 lease epoch 不变。 应从已保存的 ready digest 读回。每份合成夹具先跑 context delivery off 和不同 cwd,均不启动 claim/guard;新捕获和错误摘要仍由既有 owner 处理。 #8279 也触及旧执行的验证;它是并行方案,不能替代此 head 的证据。
源码聚焦套件 256 通过、11 跳过;四项失败中,两项 full/delta 在同基线复现,另两项大捕获断言精确 head 单独重跑通过,初次差异原因未证。独立 File/SQLite 断点均完成;隔离 wheel 重现旧捕获恢复已释放租约与丢提示。 Standard premerge 的 6 项直接检查和 19 项选中检查在重跑通过;初次 semantic-vocabulary smoke 未通过,单独与标准重跑均通过。 与当前 main 0a9dda8 可组合;早一版分段首读组合 75 项通过,现行组合回归:6 passed, 30 deselected in 95.96s (0:01:35)。 前次大捕获不稳定的原因未证明。 远端 CI 未取样。
语义与 CI 对齐
原生入口继续依赖普通 claim 和当前 lease。保留并核对原 claim 操作与 lease generation。旧 capture 缺可校验绑定时,只提供只读恢复或要求 fresh eligible capture,不运行新 claim。 把已预约、原 ready 已持久化、提示已交付分别处理。可重复给出已绑定的只读地址;等宿主确认送达再抑制,禁止以重新 claim 来替代恢复。 复验时,在 claim 返回、ready journal 持久化和读回提示渲染前中断真实 quota context-hook,用相同 session 重入,对照 File/SQLite 的 stdout、receipt、epoch 和调用数。新增 state 与恢复事件留在 native 适配器内,未增加共享权限;跨版本兼容和送达义务仍须对齐。
我的整体评价 / Verdict
请求修改。已验证的同版本改进值得保留,但一条路径错误地恢复了已释放执行,另一条在故障后没有把用户接回原任务。两者分别影响长期执行边界和当前开工。最小修复应复用原回执、同源捕获和原 lease 校验。 旧捕获的租约复活和恢复地址丢失必须修复;模型实际收到上下文的成功率和完整成本没有验证。
English verdict: REQUEST_CHANGES. At 14f9f76, File and SQLite source and wheel probes show that a legacy capture can reacquire a released lease and an interrupted readback can suppress further recovery.
| digest = request.get("source_sha256") | ||
| if not isinstance(digest, str) or BARE_SHA256_PATTERN.fullmatch(digest) is None: | ||
| raise ValueError("Native execution preparation requires its original capture digest") | ||
| return f"todo-claim:codex-capture:{digest}" |
There was a problem hiding this comment.
[P1] 旧捕获会重新取得已释放的 lease。 旧 CLI 的 claim ID 不等于这里新派生的 ID。旧进程在 claim/ready 后退出,释放 epoch 1,再由当前源码或 wheel 重入同一捕获,File 和 SQLite 均出现 active epoch 2。绑定可证的旧回执与原 generation,或在旧捕获缺绑定时要求新的有效准备。
| if previous.get("state") == "attempted": | ||
| if previous.get("readback_sent") is True: | ||
| return None | ||
| previous["readback_sent"] = True |
There was a problem hiding this comment.
[P2] 这里在 stdout 前已抑制同源恢复提示。 第一次 Hook 在 claim 后退出,第二次在 marker 落盘后、提示输出前退出,随后 PostToolUse 和 SessionStart 均不给提示。保留可重复读取的原回执或 ready 地址;有送达证据后再抑制。
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEADFor a same-repository clone whose Keep the DCO |
Problem context
When a native Hook loses readiness after starting a bound claim, a later Hook can replay both the claim and guard from the same captured action. The authority keeps lease acquisition idempotent, but retries still cost control-plane work and can leave the current Turn waiting for readiness.
Change
Reserve the automatic attempt under the existing native session lock before invoking the ordinary claim. Give that capture a stable claim operation ID. When preparation is interrupted, surface one readback of the original claim receipt and current lease. A matching active lease lets the original captured Turn finish its readiness check. A fresh eligible capture can still prepare new work.
Validation
14f9f76e451dd09bc493e6292239263080a96fa3on mainc0b6aded5d173dd474a22ff0b33955d4d93a7732. Source tests 212 passed, 0 skipped. Isolated wheel 9 passed, with changed Python modules verified against the commit. Ruff passed. Standard local premerge ran 6 direct and 19 selected checks with zero mechanical failures and 0 manual holds. The injected test qualifies recovery in the native CLI Hook; full model delivery and task-level costs remain to be measured.