Skip to content

fix(quota): recover canonical sources for lifecycle-bound replans - #6538

Merged
huangruiteng merged 2 commits into
mainfrom
codex/lifecycle-source-recovery-20261015
Oct 15, 2026
Merged

huangruiteng merged 2 commits into
mainfrom
codex/lifecycle-source-recovery-20261015

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

Follow-up to #6524: a Turn bound to a lifecycle replan has no selected Todo to recover by exact ID. When compact views omit its older completed source, later Agent work or a later user gate can make recovery fail with an identity conflict.

Restore the complete canonical Todo inventory inside the existing source-recovery boundary for OPEN, guard-scoped replans. Reconstruct the historical closed-row source independently of current frontier counts and current user Todos. The existing TypeScript owner still validates the original obligation digest, Actor, completion identity, timestamps, qualified evidence and settlement.

The original Turn retains its binding, requires evidence-linked writeback and settles once. Independent later work stays open. A new global user gate remains open and still refuses delivery on a fresh Turn. Recovery does not complete the Goal or grant new-work authority.

Scope And Ownership

  • Base: main, merge base af56c5f4fc6120957b0ae2808f5acae3b8e67882.
  • Three existing production modules, one focused CLI regression and its existing fixture. No new protocol vocabulary, dependency, store, policy switch, budget or UI.
  • Python reads provider facts and invokes the established frontier source builder; shared identity, lifecycle and settlement decisions retain their existing typed owner.
  • Historical exact-Todo receipt recovery remains intact. Canonical active inventory is not a compact display lane; archived/reopened/foreign sources remain subject to existing typed rejection.
  • Specification: docs/quota-allocation.md#receipt-backed-settlement-progress and docs/reference/protocols/quota-cli-hot-path-compaction-v0.md#ownership-boundary at the immutable merge base.

Validation

Final head: 994ef8cce64ed05bd64f008646c71be520b487c3.

  • 117 focused Python tests passed, 0 skips, including four File/SQLite CLI lifecycle cases with and without a later global user gate.
  • 21 TypeScript replan semantic tests passed, 0 skips, including original binding, actor, freshness, invalid/archived source and evidence rejection.
  • Six additional isolated real CLI replays passed: ordinary recovery, 80 additional unrelated terminal rows with reversed source order, and later global user gate, each on File and SQLite.
  • Immutable base regression failed on both providers; review also reproduced the later-user-gate failure on the original PR head before the repair. Both are now covered.
  • Exact-scope strict change-quality receipt, Ruff, semantic advisory/full vocabulary drift, maintainability and whitespace passed. Risk premerge passed all 5 direct checks and all 18 selected canaries; no threshold changes.
  • Earlier test iteration incorrectly treated a projected candidate as admission; the final assertion checks the documented delivery authority and ask-user interaction. The final source has no remaining failed check.

Commands:

uv run --extra test python -m pytest -q tests/control_plane/test_lifecycle_guard_reentry.py tests/control_plane/test_replan_successor_guard_reentry.py tests/control_plane/test_goal_frontier_replan_rules.py tests/control_plane/test_quota_action_selection_conflict.py tests/control_plane/test_deferred_original_turn_binding.py tests/control_plane/test_replan_settlement_runtime.py tests/control_plane/test_replan_terminal_spend_ordering.py
node --no-warnings --experimental-strip-types --test tests/control_plane_ts/replan_semantics.test.ts
uv run --extra test loopx canary premerge --from-git-diff --git-diff-base af56c5f4fc6120957b0ae2808f5acae3b8e67882

Remote CI was not consulted under the configured local-validation policy. PostgreSQL, paid models, a whole-repository pytest sweep and new UI/browser qualification were not run; this PR changes no provider implementation, promotion or visual surface. Isolated canonical File/SQLite stores and actual CLI/writeback/debit readback cover the changed invariant. The extra complete read is limited to open receipt-bound replan recovery. No long-soak or model-effectiveness claim.

Delivery Boundary

  • Existing CLI/GoalModeMCP recovery output corrected; frontend and Lark have no new capability or configuration journey.
  • Public-safe synthetic fixtures only; raw source evidence and logs remain private.
  • Related simplification applied: derive guard fields once and separate historical reconstruction from current frontier/user-gate projection; no parallel state owner or new abstraction.
  • DCO sign-off on both commits. Maintainer explicitly authorized review, repair and admin-bypass merge for this batch; exact-head review and readiness remain separate gates.

Signed-off-by: huangruiteng <huangrt01@163.com>
(cherry picked from commit 45a0e3180bf453aa749e93ac420cd9be3de06d9e)
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewer: model_agent | model=gpt-6.1-sol | provider=OpenAI | declaration_source=runtime_reported | reasoning_effort=xhigh

动机

使用长程 Goal 的 Agent 在处理已完成任务的收尾时,会遇到旧来源被展示窗口省略的问题。旧回合已经绑定了这次收尾,但新任务随后进入当前队列,恢复时却拿当前队列重新判断旧回合,最终报身份冲突,无法完成回写和结算。

本次修复使旧回合从完整的权威 Todo 来源恢复原始义务;在新任务或人工阻塞随后出现时,仍能完成原回合的证据回写和单次结算。验证结果同时要求新任务保持 open,人工阻塞继续约束新回合。

边界是已有生命周期回合的恢复,不扩展执行权限,不代替 Goal 验收,也不证明无限期运行或真实模型效果提升。

改动思路

真实入口仍是 quota should-run → project_live_quota_decision → restore_receipt_bound_todo_source → goal_frontier → receipt_bound_lifecycle_candidate → TypeScript replan semantics。File/SQLite 权威存储提供完整来源,Python 只搬运来源和调用已有 frontier 构造器;原始身份、时间、Actor、完成关系及结算资格仍由已有类型化 owner 校验。不能通过展示列表缺失来判定原义务已经不存在。

核心理由是:历史来源重建不能借用后来新增的队列计数或人工阻塞;去掉这些当前投影输入后,仍须命中原义务摘要,才可能恢复。实时人工阻塞继续作用于新任务准入,历史重建本身不授权执行新工作。本 PR 的边界是补齐现有恢复入口的来源与历史重建参数,保留现有身份、证据与扣费规则,不增加另一套状态或兼容协议。

场景 原路径 本次路径
来源超出展示窗口,新 Agent 任务到达 原义务身份冲突 完整来源恢复旧义务,新任务保持 open
原回合绑定后新增人工阻塞 当前用户队列阻止历史义务重建 原回合完成收尾,新回合继续 ask_user
没有证据回写或重放扣费 拒绝提前扣费,重复扣费不追加 保持相同边界

该表是源码流程说明;下面的真实 CLI 回归提供执行证据。

具体改动

审查整个 af56c5f4fc6120957b0ae2808f5acae3b8e67882..994ef8cce64ed05bd64f008646c71be520b487c3,共 5 个文件。规范依据为 docs/quota-allocation.md#receipt-backed-settlement-progress,spec_revision 为 af56c5f4fc6120957b0ae2808f5acae3b8e67882;同时核对该 revision 的 docs/reference/protocols/quota-cli-hot-path-compaction-v0.md#ownership-boundary。两份规范均未在本 PR 改写。

  • receipt-backed-settlement-progress:已实现。恢复保持原 Goal/Agent/Turn/replan identity;先有合格回写及回执,再执行原绑定的 spend,重放不重复扣费。真实 File/SQLite CLI 覆盖提前扣费拒绝、回写、结算和重放。
  • ownership-boundary:已实现。展示压缩不是决策 owner;完整 Todo reader 补齐事实后,原 TypeScript owner 决定义务与结算,未把 compact 列表缺失解释成权威不存在。
  • 更广的长期稳定性、模型理解、其他平台和存储迁移不属于这次有界来源修复,未宣称完成对应验收。

关键代码讲解

  1. restore_receipt_bound_todo_source:只在 guard-scoped replan 且 replay phase 为 OPEN 时,通过现有完整 list_goal_todos 恢复目标 Goal 的两个 Todo summary,其他 Goal 行不变。Todo-bound 路径仍用既有 exact-ID reader;SETTLED 不进入新增读取分支,缺失 exact Todo 仍明确拒绝。
  2. _receipt_bound_guard_fields / project_live_quota_decision:从现有 settlement readback 派生 scope 和 recorded_at,只计算一次,来源恢复与最终决策使用同一组字段,不增加一个可手工同步的状态源。
  3. build_goal_frontier_projection_context_from_status:历史 lifecycle callback 使用已验证的 completed-row summary,省略实时 frontier counts,并把当前 user summary 排除在历史重建之外。现有 typed lifecycle owner 仍比对原 obligation digest、完成身份、归属与时间;这不是忽略实时用户权限。
  4. test_hidden_completed_source_recovers_its_original_guard_after_new_work:复用原 CLI fixture,参数化 File/SQLite 和后来人工阻塞。24 个较新终态来源遮蔽旧记录后,执行完整恢复、拒绝提前扣费、证据回写和一次扣费;另验证新任务、用户任务保持 open,新回合仍禁止 delivery 并 ask_user。fixture 仅新增可选初始 Todo 输入。

对主干的风险

本次 review 在原 head 1be235f07c18acaac23b013a648f7312c3cc8c8a 复现了遗漏:同 Agent 后来新增 user gate 时,实时 user summary 抢占了历史来源重建,File/SQLite 都报原始 replan 身份冲突。修复提交 994ef8cce64ed05bd64f008646c71be520b487c3 排除这个当前投影输入,并增加持久回归。该发现已修复,无遗留阻断项。

最终 head 验证:117 项聚焦 Python 测试、21 项 TypeScript replan 语义测试、6 个独立真实 CLI 重放(普通恢复、更多无关终态记录并反转输入顺序、后来全局人工阻塞,各含 File/SQLite),以及风险 premerge 的 5 个 direct checks 和 18 个所选 canary 全部通过。不可提前扣费、重复结算不追加、后续工作不被旧回合接管均有断言。独立 immutable base 上普通回归 File/SQLite 均失败,证明测试能区分旧缺陷;原 head 的后来 user-gate 反例也先失败。前一轮新增测试把候选 selected_todo 当作准入结果而误报;核对既有权限合同后改为断言 delivery_allowed/must_attempt/ask_user,保留实际权限边界。

未查询或等待远端 CI,遵循本次管理策略;未运行付费模型、PostgreSQL、完整全仓 pytest 或新 UI 浏览器旅程。这里没有 provider 实现、存储迁移或 UI 变更,实际验证使用隔离的 File/SQLite 权威存储和源码 CLI。剩余成本是仅对未结算且绑定 replan 的恢复读取完整 Todo 来源;没有增加到普通新回合或已结算回合。回滚本 PR 可恢复旧行为,但会重新暴露上述身份冲突。

语义与 CI 对齐

复用现有 ReceiptBoundReplayPhase、guard scope、canonical Todo reader 与 TypeScript replan/settlement 词汇,无新增共享 vocabulary。diff advisory、完整 semantic vocabulary smoke、维护性 ratchet、Ruff 和 whitespace checks 均通过,未调整预算、阈值、权限或判定文字。恢复后仍明确要求 evidence-linked Vision 回写,Todo no-follow-up 本身不算 Goal 验收,也不能成为直接扣费依据。

我的整体评价

APPROVE,精确 head 为 994ef8cce64ed05bd64f008646c71be520b487c3。long_horizon:improved,累积终态记录和新任务不再使旧回合失去原始来源;user_experience:improved,恢复无需重新执行旧任务或手工改写回执,同时新回合仍遵守人工阻塞。结论限于本次有界回归,未将其外推为长期运行或模型能力证明。

方案沿用最近的来源恢复与类型化 owner,新增生产分支只负责完整事实读取;未来相关重构已落实为 guard 字段单次派生和历史/实时投影输入分离,不需要再建一个状态源或新 helper 层。whole-PR 规模与实际故障相称,持久回执兼容保留,没有新公共选项或 default-off 能力。现有 strict change-quality receipt 与最终本地验证通过;按维护者对本批次的明确授权,可在最新 readiness 返回 ready 且 head 未变后 admin bypass 合并。

English verdict: APPROVE - exact head 994ef8c. Complete canonical facts recover the original lifecycle-bound Turn across compact omissions, later work and later user gates. The review-found user-gate reconstruction defect is fixed; evidence writeback, single debit and live gate authority remain enforced. 117 Python tests, 21 TypeScript tests, 6 File/SQLite replays and all selected premerge checks pass; remote CI was not consulted.

@huangruiteng huangruiteng 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 | model=gpt-6.1-sol | provider=OpenAI | declaration_source=runtime_reported | reasoning_effort=xhigh

Approval conclusion (author-owned PR; GitHub blocks formal self-approval). This records the same agent self-review under the authorized maintainer account; it is not a second independent review.

动机

使用长程 Goal 的 Agent 在处理已完成任务的收尾时,会遇到旧来源被展示窗口省略的问题。旧回合已经绑定了这次收尾,但新任务随后进入当前队列,恢复时却拿当前队列重新判断旧回合,最终报身份冲突,无法完成回写和结算。

本次修复使旧回合从完整的权威 Todo 来源恢复原始义务;在新任务或人工阻塞随后出现时,仍能完成原回合的证据回写和单次结算。验证结果同时要求新任务保持 open,人工阻塞继续约束新回合。

边界是已有生命周期回合的恢复,不扩展执行权限,不代替 Goal 验收,也不证明无限期运行或真实模型效果提升。

改动思路

真实入口仍是 quota should-run → project_live_quota_decision → restore_receipt_bound_todo_source → goal_frontier → receipt_bound_lifecycle_candidate → TypeScript replan semantics。File/SQLite 权威存储提供完整来源,Python 只搬运来源和调用已有 frontier 构造器;原始身份、时间、Actor、完成关系及结算资格仍由已有类型化 owner 校验。不能通过展示列表缺失来判定原义务已经不存在。

核心理由是:历史来源重建不能借用后来新增的队列计数或人工阻塞;去掉这些当前投影输入后,仍须命中原义务摘要,才可能恢复。实时人工阻塞继续作用于新任务准入,历史重建本身不授权执行新工作。本 PR 的边界是补齐现有恢复入口的来源与历史重建参数,保留现有身份、证据与扣费规则,不增加另一套状态或兼容协议。

场景 原路径 本次路径
来源超出展示窗口,新 Agent 任务到达 原义务身份冲突 完整来源恢复旧义务,新任务保持 open
原回合绑定后新增人工阻塞 当前用户队列阻止历史义务重建 原回合完成收尾,新回合继续 ask_user
没有证据回写或重放扣费 拒绝提前扣费,重复扣费不追加 保持相同边界

该表是源码流程说明;下面的真实 CLI 回归提供执行证据。

具体改动

审查整个 af56c5f4fc6120957b0ae2808f5acae3b8e67882..994ef8cce64ed05bd64f008646c71be520b487c3,共 5 个文件。规范依据为 docs/quota-allocation.md#receipt-backed-settlement-progress,spec_revision 为 af56c5f4fc6120957b0ae2808f5acae3b8e67882;同时核对该 revision 的 docs/reference/protocols/quota-cli-hot-path-compaction-v0.md#ownership-boundary。两份规范均未在本 PR 改写。

  • receipt-backed-settlement-progress:已实现。恢复保持原 Goal/Agent/Turn/replan identity;先有合格回写及回执,再执行原绑定的 spend,重放不重复扣费。真实 File/SQLite CLI 覆盖提前扣费拒绝、回写、结算和重放。
  • ownership-boundary:已实现。展示压缩不是决策 owner;完整 Todo reader 补齐事实后,原 TypeScript owner 决定义务与结算,未把 compact 列表缺失解释成权威不存在。
  • 更广的长期稳定性、模型理解、其他平台和存储迁移不属于这次有界来源修复,未宣称完成对应验收。

关键代码讲解

  1. restore_receipt_bound_todo_source:只在 guard-scoped replan 且 replay phase 为 OPEN 时,通过现有完整 list_goal_todos 恢复目标 Goal 的两个 Todo summary,其他 Goal 行不变。Todo-bound 路径仍用既有 exact-ID reader;SETTLED 不进入新增读取分支,缺失 exact Todo 仍明确拒绝。
  2. _receipt_bound_guard_fields / project_live_quota_decision:从现有 settlement readback 派生 scope 和 recorded_at,只计算一次,来源恢复与最终决策使用同一组字段,不增加一个可手工同步的状态源。
  3. build_goal_frontier_projection_context_from_status:历史 lifecycle callback 使用已验证的 completed-row summary,省略实时 frontier counts,并把当前 user summary 排除在历史重建之外。现有 typed lifecycle owner 仍比对原 obligation digest、完成身份、归属与时间;这不是忽略实时用户权限。
  4. test_hidden_completed_source_recovers_its_original_guard_after_new_work:复用原 CLI fixture,参数化 File/SQLite 和后来人工阻塞。24 个较新终态来源遮蔽旧记录后,执行完整恢复、拒绝提前扣费、证据回写和一次扣费;另验证新任务、用户任务保持 open,新回合仍禁止 delivery 并 ask_user。fixture 仅新增可选初始 Todo 输入。

对主干的风险

本次 review 在原 head 1be235f07c18acaac23b013a648f7312c3cc8c8a 复现了遗漏:同 Agent 后来新增 user gate 时,实时 user summary 抢占了历史来源重建,File/SQLite 都报原始 replan 身份冲突。修复提交 994ef8cce64ed05bd64f008646c71be520b487c3 排除这个当前投影输入,并增加持久回归。该发现已修复,无遗留阻断项。

最终 head 验证:117 项聚焦 Python 测试、21 项 TypeScript replan 语义测试、6 个独立真实 CLI 重放(普通恢复、更多无关终态记录并反转输入顺序、后来全局人工阻塞,各含 File/SQLite),以及风险 premerge 的 5 个 direct checks 和 18 个所选 canary 全部通过。不可提前扣费、重复结算不追加、后续工作不被旧回合接管均有断言。独立 immutable base 上普通回归 File/SQLite 均失败,证明测试能区分旧缺陷;原 head 的后来 user-gate 反例也先失败。前一轮新增测试把候选 selected_todo 当作准入结果而误报;核对既有权限合同后改为断言 delivery_allowed/must_attempt/ask_user,保留实际权限边界。

未查询或等待远端 CI,遵循本次管理策略;未运行付费模型、PostgreSQL、完整全仓 pytest 或新 UI 浏览器旅程。这里没有 provider 实现、存储迁移或 UI 变更,实际验证使用隔离的 File/SQLite 权威存储和源码 CLI。剩余成本是仅对未结算且绑定 replan 的恢复读取完整 Todo 来源;没有增加到普通新回合或已结算回合。回滚本 PR 可恢复旧行为,但会重新暴露上述身份冲突。

语义与 CI 对齐

复用现有 ReceiptBoundReplayPhase、guard scope、canonical Todo reader 与 TypeScript replan/settlement 词汇,无新增共享 vocabulary。diff advisory、完整 semantic vocabulary smoke、维护性 ratchet、Ruff 和 whitespace checks 均通过,未调整预算、阈值、权限或判定文字。恢复后仍明确要求 evidence-linked Vision 回写,Todo no-follow-up 本身不算 Goal 验收,也不能成为直接扣费依据。

我的整体评价

APPROVE,精确 head 为 994ef8cce64ed05bd64f008646c71be520b487c3。long_horizon:improved,累积终态记录和新任务不再使旧回合失去原始来源;user_experience:improved,恢复无需重新执行旧任务或手工改写回执,同时新回合仍遵守人工阻塞。结论限于本次有界回归,未将其外推为长期运行或模型能力证明。

方案沿用最近的来源恢复与类型化 owner,新增生产分支只负责完整事实读取;未来相关重构已落实为 guard 字段单次派生和历史/实时投影输入分离,不需要再建一个状态源或新 helper 层。whole-PR 规模与实际故障相称,持久回执兼容保留,没有新公共选项或 default-off 能力。现有 strict change-quality receipt 与最终本地验证通过;按维护者对本批次的明确授权,可在最新 readiness 返回 ready 且 head 未变后 admin bypass 合并。

English verdict: APPROVE - exact head 994ef8c. Complete canonical facts recover the original lifecycle-bound Turn across compact omissions, later work and later user gates. The review-found user-gate reconstruction defect is fixed; evidence writeback, single debit and live gate authority remain enforced. 117 Python tests, 21 TypeScript tests, 6 File/SQLite replays and all selected premerge checks pass; remote CI was not consulted.

@huangruiteng
huangruiteng merged commit c08e561 into main Oct 15, 2026
5 of 6 checks passed
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