Skip to content

fix(todos): preserve terminal preview and lifecycle settlement identity - #7872

Merged
huangruiteng merged 1 commit into
mainfrom
codex/decision-terminal-closeout-recovery-20261101
Nov 2, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/decision-terminal-closeout-recovery-20261101

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

Repair two reproducible recovery gaps after a declared Todo has completed, written back and spent its slot:

  1. A same-Turn terminal-closeout preview changes the request fingerprint and conflicts with its committed parent. A historical validation receipt can also reach a preview-only reducer that must not execute validation.
  2. Lifecycle reentry verifies the original quota settlement but discards its identity. The CLI accepts the business closeout without emitting the terminal event and matching fourth receipt for that original Turn.

The same File/SQLite CLI regression fails four cases on base e9eda527afd5fcb262ee7c199e1822b1a936cc24. The fix makes preview and retry preserve the original identity, validation, evidence and once-only accounting. No synthetic successor or replacement Turn is needed.

Author Declaration

Criterion Disposition Owner / validation
Preview executes no validation or durable lifecycle effect implemented TS terminal request identity and reducer; File/SQLite CLI marker and state readback
Original operation, validation and business receipt survive recovery implemented Existing reentry verifier and strict settlement identity decoder; provider conformance
Lifecycle closeout records its original Turn and never repeats accounting implemented CLI rollout binding and settlement readback; File/SQLite replay and one-debit assertions
Legacy receipt bytes remain unchanged; missing settlement fails closed implemented Same provider history before/after, negative verifier case; File/SQLite/PostgreSQL conformance

Change And Continuation

  • Preserve the historical committed fingerprint (dry_run=false) when previewing the same intent; do not treat a preview as a new committed operation.
  • Keep the original validation receipt as recovery evidence without declaring it as a preview effect.
  • Return the existing TS verifier's original settlement binding. The Python adapter transports that binding into the existing rollout/readback path; it does not parse an opaque completion key or invent a policy owner.
  • When an old lifecycle receipt lacks that binding, add verified readback to the response only. Do not rewrite the stored receipt or head.
  • Lifecycle reentry does not dispatch completion hooks again. Existing authorization, ownership, lease checks and completion order remain in force.

Complete as a source repair proposal. Review, merge, installed adoption and any operator-owned recovery remain distinct; no merge or install is performed by this PR.

Validation

  • Tested source head: 06d31d78b0c60b17cc749715b7a41400a7388e0d.
  • Run state: finished for the reported suites and standard premerge.
  • Input classes: synthetic, public_fixture. No live Goal state is used as a test fixture.
Check Result Coverage / limitation
File/SQLite regression on current base expected failed Four cases fail before the fix: preview fingerprint/effect mismatch or missing lifecycle binding
Declared settlement + quota CLI suites failed: 186 passed, 1 failed All declared-terminal cases passed. The remaining oversized-request transport expectation also fails independently on base
Adjacent terminal, lifecycle, reviewed Chat HTTP and retired-source suites failed: 116 passed, 24 failed All 24 failures stop at the unchanged initial guard, before terminal execution; each reproduces on base
Exact base/head diagnostic comparison failed on both: 25 cases Same command, matched fixture/environment and complete normalized failure identities/details; no new or worsened failure in this comparison. The failures remain failures, not a green full suite
Full TypeScript control-plane suite passed 5,864 passed, 77 skipped; the real PostgreSQL arm is run separately
Real PostgreSQL authority-store suite passed 385 passed, 0 skipped; PostgreSQL 16.15 in an isolated disposable synthetic server
TypeScript typecheck, required Ruff and Mypy passed Existing repository commands; Mypy checks its configured 17-file scope
CLI output budget, diff hygiene, semantic advisory, maintainability ratchet passed Advisory found no supported new carriers; this is not a proof of unchanged semantics
Public boundary scan passed Six changed files, no errors or warnings
Extra critical-case run passed Four File/SQLite cases, zero failures at the immutable committed head
Exact-scope CQR / standard premerge passed Receipt cqr_acdfa4454536b2bfee7d verified for the exact diff; six direct and eighteen selected checks passed. The baseline-failure row stays failed under the typed attribution; no merge readiness or full CI pass is claimed

Full Python CI, Windows and installed release qualification have not been run locally. The matched baseline diagnostic exception cannot waive required CI, independent review or merge readiness. The two broad failing commands are disclosed above; neither is presented as an all-green validation run.

Frontend / Visual Evidence

UI impact: none. This repairs the existing CLI/host completion recovery path and its shared typed owner; it adds no settings or frontend capability. Existing reviewed Chat HTTP recovery is included in the adjacent suite. No rendered page or navigation changed; screenshots are not applicable.

Type / Area

  • Bug fix
  • Test update
  • Control plane / host recovery
  • Direction: existing S7 once-only settlement and S2 Todo recovery; no new roadmap milestone or runtime provider.

Boundary

  • No private state, raw sessions, credentials, local paths or internal links in the diff or public artifacts.
  • No benchmark execution, permissions, bypass, provider activation or storage promotion.
  • Existing receipt schemas and committed fingerprints retained; no data/history rewrite.
  • No RFC pair changed; DCO sign-off included.

Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>

@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

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

HEAD: 06d31d78b0c60b17cc749715b7a41400a7388e0d

动机 / Motivation

受影响的是已完成声明验证、随后通过 CLI 收尾或恢复同一轮工作的 Agent 与维护者。例如一项工作已经验证、回写并扣过一次额度:旧实现的终态预览会与原回执指纹冲突,按原完成键恢复时又可能丢失结算身份,迫使调用者手工查找记录。本头让预览保持只读,并从已验证的原回执返回同一个身份;实际 CLI 能读回四步收据,重复恢复不会再运行验证器或再次扣账。本次不新增完成权限、额度、人工确认或前端配置,也不认证安装升级、跨主机采用或长期成本净收益。

改动思路 / Approach

保留 TS 对完成、权限和回执的唯一决策权,Python 只恢复既有身份并投影结果;这样无需新协议、第二份账本或调用者手工同步字段。当前 PR 的边界是同一原始完成身份的预览、恢复和终态读回,包含真实 CLI、持久化兼容和可选观察器隔离。旧的请求版本或另一份账本都不能替代原始验证与扣账事实。新的字段来自严格核验后的历史记录,不能作为新的执行授权。最强反例是:旧回执缺字段却仍能恢复到别人的轮次,或恢复过程再次触发观察器;本轮分别以真实后端的原记录不变断言和真实 CLI 加记录型可选消费者核对。流程用下表说明,表格来自源码,测试证据另列。

触发 本头行为 保留的约束
同轮终态预览 读取原提交意图,预览不带验证效果 无写入、无验证器、无再次扣账
原完成键恢复 从严格历史核验返回原身份 不解析键猜身份,不补造缺失收据
旧回执缺绑定字段 仅补齐本次返回投影 原 provider head 与 receipt 字节不变

具体改动 / Changes

先读不可变规范 docs/reference/canonical-terminal-review.md,版本 e9eda527afd5fcb262ee7c199e1822b1a936cc24,并对照同版 docs/quota-allocation.md 的 Receipt-backed settlement progress。按原有章节映射:Operate and recover 已实现原身份优先恢复与只读预览;Wire and migration boundary 已实现原提交指纹、ID 和持久回执保留;Quota-bound CLI completion 已实现原身份贯通验证、回写、单次扣账及最终收口。没有用本 PR 新增测试来定义原规范。

六个路径、+119/-15 的完整 diff 均已阅读。声明验证与 Todo 所有权仍由 TS 判断,Python 没有新增业务判定;历史兼容针对持久记录,不是保留另一套旧请求解码器。

关键代码讲解

  • terminalRequestSha:预览读取原提交意图,摘要保留已提交请求的 dry_run=false;其余身份、lease 和验证声明字段仍参与约束。
  • executeCoordinationTodoTerminalLifecycle:预览不给 reducer 传验证效果;旧回执缺绑定时仅派生返回值,缺少原结算仍拒绝,未改写既有回执。
  • verifyReentrySettlement:读完整 Goal rollout/run 快照,按原 actor 与 effect 反推出 Turn 后严格重算同一身份;不从 opaque key 猜测,不允许 unbound 回退。
  • handle_todo_command:采用 TS 已核验身份,终态事件和结算回读使用原 Turn;--completion-identity-key 路径不重新派发可选 post-writeback hook。

对主干的风险 / Risks

未发现阻塞问题。主要风险是预览产生副作用、恢复误绑身份、重跑验证/扣账,以及历史兼容覆盖原记录。File/SQLite 的实际 CLI 流程会先尝试过早收口并确认拒绝,再执行返回的原命令,完成回写、一次扣账、两类终态预览/执行与所有阶段重放,最后独立列出 Todo 并读回完整四步收据。原声明、状态和验证器/扣账计数均受断言保护。相同当前四个案例放到不可变 base,全四项失败;当前头全四项通过。旧回执缺绑定、核验拒绝和完整记录不变也在真实 PostgreSQL 上执行。

本轮验证:

检查 结果 边界
declared terminal + quota CLI 完整两模块 186 PASS / 1 FAIL 22 个声明终态场景均通过;红项单独归因如下
File/SQLite 原生 authority conformance 791 PASS 含历史回执、CAS、当前权限、声明与生命周期负例
真实 PostgreSQL 16.15 store 集成 385 PASS 一次性合成数据库,已移除;另一个可选 service-URL 套件 1 SKIP
实际 CLI 的可选观察器隔离 2 PASS 只替换可选消费者为记录器,业务 owner/后端/验证和结算真实;普通入口仍到达观察器,生命周期入口不派发
既有 post-writeback 边界 4 PASS 未调用真实外部 sink
TypeScript typecheck / 两个 Python 文件 Ruff PASS 源码版本与 DCO 已核对

保留红项 test_settlement_read_snapshot_is_explicit_and_preserves_complete_facts,不能写成全绿。它在相同 base 与 head 都于第 2255 行报 DID NOT RAISE EffectRuntimeRejected。同一个 2,550,303-byte 合成请求低于两边相同的 8 MiB 请求上限;完整普通/私有返回值及不支持方法的拒绝详情一致,transport、quota readback 和该测试文件的 Git blob 全部相同,且该 RPC 不进入本次终态路径。因此这是已有、与本变更无关的断言失败;未修改断言、样本或上限来消除它。当前变更的不变量由上面的独立通过证据覆盖。

语义与 CI 对齐

本头复用已有 typed completion/settlement vocabulary;不新增启用开关、状态账本或模糊文本分类。原结算核验是强制正确性要求,可选 hook 仍是观察器。没有抓取、轮询、等待或触发 CI,远端 CI 的未知状态与未知原因仅保留为诊断,不是本次评审的阻塞条件。Windows、完整 Python/TS 全量、安装/UI、真实外部 sink 与跨主机采用未获得本次认证,合并 readiness 和维护者权限仍需独立处理。

我的整体评价 / Verdict

APPROVE,绑定上述精确 head。保留 TS 对完成、权限和回执的唯一决策权,Python 只恢复既有身份并投影结果;这样无需新协议、第二份账本或调用者手工同步字段。当前 PR 的边界是同一原始完成身份的预览、恢复和终态读回,包含真实 CLI、持久化兼容和可选观察器隔离。长程维度的可验证收益是重复恢复时继续保留同一承诺与单次成本;用户体验维度是沿用既有命令恢复已知身份,没有再要求人工提供已存在的信息或新增确认轮次。这不代表已经证明长期总成本净收益。视觉审阅不适用:已检查 CLI 与未改的 dashboard 完成状态消费者,无页面或展示改动;安装 UI 和跨主机采用仍未验证。持久历史兼容有实际旧回执消费者,保留是必要的;再增加 wrapper、协议版本或新配置目前没有更小且等价的收益。已有红项、可选跳过与未测范围全部保留;本结论不替代正式 GitHub self-approval、合并授权或安装发布。

English verdict: APPROVE — exact head 06d31d7; terminal preview and original settlement recovery are verified on real backends, with the unchanged baseline transport-test failure disclosed separately.

@huangruiteng
huangruiteng merged commit b6af4d5 into main Nov 2, 2026
28 of 38 checks passed
@huangruiteng
huangruiteng deleted the codex/decision-terminal-closeout-recovery-20261101 branch November 2, 2026 07:35
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.

2 participants