Skip to content

Recover native execution preparation without repeating claims - #8307

Open
loopx-agent wants to merge 1 commit into
mainfrom
codex/native-preparation-readback-20261107
Open

loopx-agent wants to merge 1 commit into
mainfrom
codex/native-preparation-readback-20261107

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

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

  • A synthetic timeout occurs after a real managed claim on both File and SQLite. The first Hook returns the original claim operation and read-only commands. Later PostToolUse and SessionStart events keep the count at one claim and one automatic guard. A matching lease reaches ready through the same Turn. A released lease stays released with the same epoch.
  • The native journal covers same-source reservation, rejection of a different source, a one-time recovery hint and eligibility for a new capture. The prepared reader also rejects a replaced ready capture and retains its original digest.
  • Head 14f9f76e451dd09bc493e6292239263080a96fa3 on main c0b6aded5d173dd474a22ff0b33955d4d93a7732. 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.

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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}"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 这里在 stdout 前已抑制同源恢复提示。 第一次 Hook 在 claim 后退出,第二次在 marker 落盘后、提示输出前退出,随后 PostToolUse 和 SessionStart 均不给提示。保留可重复读取的原回执或 ready 地址;有送达证据后再抑制。

@mergify

mergify Bot commented Nov 7, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @loopx-agent.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

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 HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Nov 7, 2026
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
@loopx-agent
loopx-agent force-pushed the codex/native-preparation-readback-20261107 branch from 14f9f76 to 44e2cd0 Compare November 8, 2026 10:30
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Nov 8, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant