Repository navigation
fix(todo): recover missing execution claims in one command - #8310
huangruiteng wants to merge 1 commit into
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
0829aad to
edd3123
Compare
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
[P2] 默认租约诊断与同 Turn 丢响应恢复未闭合。 默认 task-lease acquire 遇到自己的重叠租约,旧版渲染 write_scope_conflict 和冲突 Todo;新回执缺少旧 renderer 读取的 cli_args,两个 backend 都报 KeyError,诊断未输出。 目标同时与自己和他人的租约重叠时,旧 JSON 列出两个持有者;当前只留 foreign_conflict_count=1,conflicts 消失。按建议释放自己的租约后,同一目标仍被另一位持有者阻挡。 同 Turn 的 --recover-execution 首次完成并提交。模拟丢失响应后逐字重试,新版返回 coordination_operation_identity_mismatch 且没有恢复指引;拿到第一次内部 claim ID 再显式重试,才能读回已提交的原完成。File 与 SQLite 相同,未发生第二次写入或扣额。
动机 / Motivation
遇到缺失 proof 或租约冲突的 Agent 和操作者需要知道执行是否已提交、应读哪条回执以及谁仍占用 scope。 同样的本地 File/SQLite 输入:已准入 Turn 漏传 claim,重复完成;另以默认和 JSON 读取自己及混合冲突。 真实 File/SQLite 中,已准入同 Turn 的普通 completion 从三次命令缩为一次;错 Turn 在领取前被拒绝。保留原 claim ID 时完成回执可重放,未新增租约 epoch 或 debit。 默认输出、混合冲突和可重复完成的证据还不完整。 逐项读完 6 个 PR 文件;没有变更 App 的已审 proof disclosure、provider 选择或状态迁移。
改动思路 / Approach
Python 先执行原 lifecycle 操作,再由 canonical owner 给出 claim-only recovery;只增加原 claim 证明重试。TypeScript lease acquire 的新 recovery.action 另行投影自身冲突。 CLI wrapper 复用 typed claim owner,正路径规模合适;新增 recovery.action 缺少默认 renderer 对应分支,冲突投影与完成 replay 消费者未接上。 显式 opt-in 层仅组合已有能力;新 lease 诊断本身已改变默认接口,应与机器与 Markdown 消费者保持兼容。
具体改动 / Changes
基线为 e2371c476805f67903dd3c338a7e2712f577c9cc。现有规范保持当前 actor、CAS、scope 和执行身份;已提交的原操作需有稳定的重放与读回路径。PR 的新操作显式选用。 基线规范
- 一次完成。 真实 File/SQLite 中,已准入同 Turn 的普通 completion 从三次命令缩为一次;错 Turn 在领取前被拒绝。保留原 claim ID 时完成回执可重放,未新增租约 epoch 或 debit。
- 默认与混合冲突。 默认 task-lease acquire 遇到自己的重叠租约,旧版渲染 write_scope_conflict 和冲突 Todo;新回执缺少旧 renderer 读取的 cli_args,两个 backend 都报 KeyError,诊断未输出。 目标同时与自己和他人的租约重叠时,旧 JSON 列出两个持有者;当前只留 foreign_conflict_count=1,conflicts 消失。按建议释放自己的租约后,同一目标仍被另一位持有者阻挡。
- 丢响应恢复。 同 Turn 的 --recover-execution 首次完成并提交。模拟丢失响应后逐字重试,新版返回 coordination_operation_identity_mismatch 且没有恢复指引;拿到第一次内部 claim ID 再显式重试,才能读回已提交的原完成。File 与 SQLite 相同,未发生第二次写入或扣额。
- 既有预算。 基线、head 的 turn plan 都触发现有预算;保留失败。
关键代码讲解
新冲突回执交给旧 Markdown renderer,而同一 PR 的完成重试将原 proof 隐藏在成功返回中。
对主干的风险 / Risks
默认 CLI 变化不受 --recover-execution 控制;混合冲突不应通过隐藏其他 holder 来缩短输出。同一 Turn 的首次成功和响应丢失后的读回分别验证。
49 项测试通过。对照独立复现默认渲染、混合冲突与丢响应;同 Turn 首次完成、显式原 proof 重放及无额外 lease/debit 通过。 Quick premerge 6 项直接检查通过,3 项选中检查中一项失败。基线与 head 都在 turn plan 增长 11432 字符触发现有预算,无 PR 新增归因;本次合并树无冲突且 DCO 齐全。 默认输出回归与可重放性回归独立于当前主干的预算失败。 远端 CI 未取样。
为 inspect_own_conflicting_lease 接入 Markdown 的显式类型分支,保留 JSON 的冲突明细;为同 Turn 已提交的自动恢复提供绑定原 claim 的只读回执或明确恢复命令,不生成新 claim。
我的整体评价 / Verdict
对 edd3123ff1c6929c15f322904fa2b03474a86b06 请求修改。保留已通过的一次完成和权限 fence;补齐冲突输出与同一完成的可恢复路径。 修复后需要在两种本地 authority 上复验 JSON/默认 Markdown、混合冲突和同 Turn 丢响应。现有 CLI 输出预算失败也需另行修复。
English verdict: REQUEST_CHANGES. The opt-in first completion works, but default lease conflict rendering crashes, mixed conflict details disappear, and an identical bound retry cannot recover the committed completion.
| version: leaseVersion(ownConflictLease), | ||
| }, | ||
| recovery: { | ||
| action: "inspect_own_conflicting_lease", |
There was a problem hiding this comment.
[P2] Render this recovery in the default CLI format
默认 task-lease acquire 遇到自己的重叠租约,旧版渲染 write_scope_conflict 和冲突 Todo;新回执缺少旧 renderer 读取的 cli_args,两个 backend 都报 KeyError,诊断未输出。
复现:隔离 File 或 SQLite 中,A 持有另一个重叠写 scope 的 lease,对目标运行默认格式的 task-lease acquire。请按 action 显式渲染 inspect/release 的结构,保留原冲突回执,并测默认 Markdown 和 JSON。
| // Own conflicts get a bounded inspect/release route above. Foreign | ||
| // leases remain immutable and visible only when no own recovery can | ||
| // resolve the caller's collision. | ||
| ...(conflictLeases.length && ownConflict === null ? {conflicts: conflictLeases} : {})}); |
There was a problem hiding this comment.
[P2] Preserve other holders in a mixed write conflict
目标同时与自己和他人的租约重叠时,旧 JSON 列出两个持有者;当前只留 foreign_conflict_count=1,conflicts 消失。按建议释放自己的租约后,同一目标仍被另一位持有者阻挡。
复现:A 持有 src/owned/,B 持有 src/peer/,A 申请覆盖 src/** 的目标。请保留所有仍阻挡的冲突明细;只有自己的一条 lease 时也应保留既有消费者兼容。
| except LocalCoordinationAuthorityRejection as initial_error: | ||
| if not args.recover_execution: | ||
| raise | ||
| payload = _recover_todo_execution_once( |
There was a problem hiding this comment.
[P2] Make the committed same-Turn completion recoverable
同 Turn 的 --recover-execution 首次完成并提交。模拟丢失响应后逐字重试,新版返回 coordination_operation_identity_mismatch 且没有恢复指引;拿到第一次内部 claim ID 再显式重试,才能读回已提交的原完成。File 与 SQLite 相同,未发生第二次写入或扣额。
复现:让 File 或 SQLite 的 hard-lease Todo 已准入,带同一 --turn-instance-id 和 --evidence 运行两次 todo complete --recover-execution,模拟第一次响应丢失。请用原 Turn 与已提交的 claim 找到原完成回执,或返回可执行的原证据读回;不得重新领取。
Goal And Delivered Outcome
claim_taskrecovery, but must currently issue a failed lifecycle command, claim separately, and retry manually.--recover-executionoption now consumes only that typed recovery, performs one ordinary managed claim, and retries the unchanged operation in the same CLI call. A synthetic parity check reduced the caller-visible sequence from 3 invocations with 1 failed call to 1 invocation with 0 failed calls.main.Author Declaration
Implemented against
_recover_todo_execution_oncetest_explicit_one_command_execution_recoveryvalidate_todo_execution_recovery_optionstest_one_command_recovery_*executeCanonicalTaskLeaseAcquiretest_dependency_links_replay_and_recovery_preserve_real_lease_authoritytodo_execution_recovery_retry_failedtest_one_command_recovery_reports_committed_claim_when_retry_failsScope And Continuation
todo update/complete; recoveries requiring inspection or revision reconciliation remain caller-visible.Validation
edd3123ffunitpassedstaticpassedintegrationbase regressionorigin/main: head and base both render small/crowded Turn plans at 10,537/21,977 characters (11,440 growth versus the existing 9,300 ceiling).regression_paritypassedmanualpassedFrontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).python3 scripts/check_rfc_bilingual.py --base origin/main --head HEADpasses, or no paired RFC changed.none.Signed-off-bytrailer (git commit -s).