Skip to content

fix(replan): exclude inferred-successor rows from lifecycle reconstruction - #7751

Open
cocolord wants to merge 1 commit into
mainfrom
codex/lifecycle-inferred-successor-20261031
Open

cocolord wants to merge 1 commit into
mainfrom
codex/lifecycle-inferred-successor-20261031

Conversation

@cocolord

@cocolord cocolord commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

  • Outcome basis / optional anchor: reproduced defect in heartbeat lifecycle settlement (no public issue).

  • Goal/source and gap: a heartbeat Turn admitted for todo_lifecycle_settlement asks the agent to settle the completed Todo with --no-follow-up or link a successor. After a valid no-follow-up closeout, the same Turn's guard re-reads its receipt-bound obligation by reconstructing the completed rows the admitted summary reported as having no successor. The summary closes a successor gap through declared successor ids and inferred resume_when: todo_done:<id> or unblocks_todo_id edges (evaluateTodoSuccession / indexInferredSuccessors). lifecycleSource only checked declared ids. An older completed row that a later advancement Todo had resumed came back into the source. The trigger list then no longer matched the admitted obligation digest, and the guard failed closed with heartbeat_receipt_identity_conflict ("lifecycle source does not match the admitted obligation"). The Turn could not write back or settle.

  • Observable before → after, with the validation row that proves it: same admitted obligation plus the rows after closeout. Before: the reconstructed source holds the settled row and the inferred-resumed older row, settled=false, and the call is rejected as an identity conflict. After: the source holds only the settled row, settled=true, and the guard returns the expected receipt_bound_replan_settlement / vision_outcome_checkpoint_required packet. See the unit and regression_parity rows.

  • Issue/task and intended base: main.

Author Declaration

  • Written by: model_agent (OpenAI GPT-family coding agent).

Implemented against

  • Specification and revision: the existing lifecycle reconstruction contract in loopx/control_plane/work_items/replan_semantics.ts ("Reconstruct only the exact lifecycle source which could be open at admission"), plus the succession gap rule in loopx/control_plane/todos/succession.ts at main 04c5799.
  • Criteria:
Criterion (spec clause) Disposition Symbol / path Test or command
Reconstructed source equals the rows the admitted summary reported as successor gaps implemented lifecycleSource in loopx/control_plane/work_items/replan_semantics.ts tests/control_plane_ts/replan_semantics.test.ts "lifecycle reconstruction excludes rows closed by an inferred successor"
Inferred edges follow the succession owner (advancement rows only, active generation wins) implemented reuses indexInferredSuccessors, taskClass, readResume, id same test: a non-advancement resumer infers no edge and still fails closed
Exact trigger/digest identity check still fails closed on a mismatch implemented (unchanged) lifecycleObligation existing reentry tests plus the new negative case
  • Self-check before submission: confirmed the new test fails on base and passes on head. Ran the full TS replan-semantics suite and the lifecycle/settlement Python suites. Replayed the reconstruction against the read-only rows of the original failing Turn: base rejects, head returns the settlement packet. No change to obligation digests, trigger shape, quota debit, settlement or any output contract. Only the input row set is narrowed to match the admitted summary.

Scope And Continuation

  • Completed scope and remaining work: complete within this scope.
  • Slice boundary / successor: N/A — single fail-closed reconstruction mismatch.

Validation

  • Tested revision: 72295c6
  • Run state: finished
  • Input classes: synthetic, authorized_private_read_only (disposable copies for the entrypoint run)
Check kind Result Public-safe evidence / limitation
unit passed node --experimental-strip-types --test tests/control_plane_ts/replan_semantics.test.ts: 31/31. The new test fails on base (with the base replan_semantics.ts) and passes on head. It covers the resume edge, the unblock edge and the non-advancement negative.
integration passed pytest tests/control_plane/test_replan_semantics_transport.py tests/control_plane/test_lifecycle_guard_reentry.py tests/control_plane/test_refresh_state_replan_gate.py tests/control_plane/test_declared_terminal_settlement_cli.py: 90 passed.
regression_parity passed Read-only replay of the failing Turn's admitted obligation and current Todo rows through projectReplanSemantics: base raises "lifecycle source does not match the admitted obligation", and head returns receipt_bound_replan_settlement. No state was written.
real_entrypoint passed loopx quota should-run --turn-instance-id <failing Turn> against two disposable copies of the owner's runtime and registry (SQLite authority), one per revision. Base (04c5799): ok=false, heartbeat_receipt_identity_conflict. Head: ok=true, the receipt replays as the same Turn and returns the settlement packet vision_outcome_checkpoint_required for the same obligation. The live store was not touched (mtime and size unchanged). The installed CLI snapshot still needs this fix after merge.
  • Coverage and gaps: the change is confined to the reconstruction's row filter. The digest and trigger checks that own identity are unchanged and keep their fail-closed tests. Rows without inferred edges behave exactly as before, so all existing tests pass unchanged.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • First viewport and preview: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A
  • Craft review: N/A

Type of Change

  • Bug fix

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)

Technical Direction

  • Direction / acceptance reference, when applicable: Core control-plane hardening.

Shared-authority RFC fixture impact

N/A

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths (including .loopx/, .codex/goals/, and live ACTIVE_GOAL_STATE.md).
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • Existing English/Chinese RFC pairs (including ledger entries) both have a diff, and the local premerge check python3 scripts/check_rfc_bilingual.py --base origin/main --head HEAD passes, or no paired RFC changed.
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

…ction

A receipt-bound lifecycle review reconstructs the completed rows that the
admitted summary reported without a successor. That summary also closes a
gap through inferred resume/unblock edges, but the reconstruction only
checked declared successor ids. An older row that was resumed by a later
Todo re-entered the source, its trigger list no longer matched the admitted
obligation digest, and the same Turn's guard failed closed with
heartbeat_receipt_identity_conflict after a valid no-follow-up closeout.

Reuse the succession owner's inferred-edge index with its active-generation
identity rule so the reconstruction matches the admitted summary.

Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com>
Co-authored-by: TRAE CLI <traecli@bytedance.com>

@songoow songoow 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 | GPT-6 Astra Pro | OpenAI | self_reported

审阅固定在 72295c69749381036df7f7ab8c1bda96e60c02be;基线 04c5799b88f6c4cf12a224b7fa679f272e1e794e。核对了最新讨论与当前 main 21367015cce45294dcf99f54a3211d66f5d842c5,触及的关键生产 owner 在 main 仍与基线一致。

本轮未发现新的具体阻断性代码缺陷;当前为验证证据 hold。 当前failed browser/shards缺少充分独立归因;本次changed-invariant测试不等于所有当前失败均已解决。

动机 / Motivation

受影响的是在同一个 heartbeat Turn 内完成任务收尾、随后再次读取准入状态的 Agent。 当另一个已完成任务已有 resume/unblock 推导出的后继时,旧重建路径仍把它算成无后继缺口,导致原本正确的收尾与绑定的 obligation 摘要不再一致。 本次重用已有后继关系索引,排除已由后继覆盖的行,使绑定到原 Turn 的生命周期收尾继续对应原来的义务。 范围是原义务的只读重建;不放宽 digest 身份校验,不把后继存在当作 Goal 已接受,也不新增执行许可。

未发现为本次具体增量单独批准的书面验收规范;按原问题、基线现有owner契约与已有讨论判断,不把本PR新增文档当作独立验收依据。

改动思路 / Approach

后继推导由现有 succession owner 负责,lifecycleSource 只把规范化行交给该索引,避免维护第二套 resume/unblock 业务规则。 当前 PR 的边界是修正 receipt-bound lifecycle reconstruction 的源集合;原触发身份和后续 Vision 要求继续生效。 最小修复是让两个读取同一 Todo 图的入口使用相同边关系,而不是移除摘要校验或宽松接受更多 settlement。新代码先按逻辑 Todo 身份选择当前 active generation,再通过 canonical read codec 读取 resume_when 与 unblocks_todo_id;只有 advancement_task 贡献推导边。之后仍执行原完成时间、actor、归档、no_followup 与 digest 校验。

具体改动 / Changes

关键代码讲解

  • lifecycleSource(replan_semantics.ts:130,新增核心:143–162)先建立与已有 succession 读取一致的 active-generation 映射,再调用 indexInferredSuccessors,过滤已有推导后继的完成行。输入仍是完整 canonical items,排序仍按原 completed_at,故展示条数不决定义务。
  • indexInferredSuccessors(todos/succession.ts:80,复用未修改)仅为 advancement 行建立非自指的 unblocks/resumes 关系;通用 Todo、不合法身份和自身边不会因此清空生命周期缺口。
  • lifecycleObligation(replan_semantics.ts:182,后移未改语义)继续验证 selected obligation、trigger 列表和原身份摘要,既不把一次 reentry 当作 Goal 接受,也不会免除后续要求。新增测试分别覆盖 resume 与 unblock,并检查非推进任务仍不能解除缺口。

验证

exact head 的 TypeScript replan_semantics 套件 31/31 passed。把同一个新增回归用例放到不可变 base 04c5799 的生产实现上,它如预期失败:重建列表多出 todo_resumed;head 只保留 todo_settled。另运行真实 Python→TS Effect Runtime 的 transport、lifecycle guard reentry、refresh-state replan gate 与 declared terminal CLI 四套件:90 tests passed in 778.12s,但session exit=1,因为全局隔离gate看到启动后出现默认usage-ping目录。创建时间与并行审查quota CLI探针吻合,属于共享审查环境的隔离污染证据,不能把该运行简写为全绿,也不能据此指控本补丁回归。最初受沙箱loopback权限阻止的运行同样保留;没有改断言或放宽gate。 本PR对其不可变base执行git diff --check,检查通过。

对主干的风险 / Risks

未发现新的具体阻断性代码缺陷。风险集中在 active/archive 代际、不同 actor 和重复回读时错误过滤义务,因此保留原身份校验很重要。当前远程浏览器失败包含 loaded lens 超过1秒预算与 delegation-search rows 超时,另外若干 test shards 的完整日志不可取得;这些与本次两文件变更没有已证实因果关系,但尚不能宣称已经独立归因为基线问题。局部通过不替代当前失败的归因,pending 状态本身也不是拒绝理由。 当前报告只覆盖明确列出的执行与源码证据,未完成的provider、scope矩阵或视觉状态不会标成通过;review结论与合并时的分支保护、完整CI资格分开记录。

我的整体评价 / Verdict

这是一处有真实失败反证的小范围 owner 复用修复,逻辑方向合理,未增加新状态、新CLI或可写权威。当前保留验证 hold,要求的最小补证是针对现有失败签名的当前有效覆盖或不可变基线对照;不要通过放宽已冻结性能预算来取得绿色,也不要重复要求修理已由本次回归测试证明修复的推导后继问题。

本变更只改生命周期重建与其测试,没有修改渲染页面;已检查该内部状态经现有 CLI 回读的边界。 不适用;远程浏览器失败另作为当前验证风险记录,未声称视觉通过。

English verdict: REQUEST_CHANGES — exact head 72295c6; no new concrete code defect found; current validation gaps remain explicitly unverified.

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.

2 participants