Repository navigation
Conversation
…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
left a comment
There was a problem hiding this comment.
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.
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_settlementasks the agent to settle the completed Todo with--no-follow-upor 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 inferredresume_when: todo_done:<id>orunblocks_todo_idedges (evaluateTodoSuccession/indexInferredSuccessors).lifecycleSourceonly 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 withheartbeat_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 expectedreceipt_bound_replan_settlement/vision_outcome_checkpoint_requiredpacket. See theunitandregression_parityrows.Issue/task and intended base:
main.Author Declaration
Implemented against
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 inloopx/control_plane/todos/succession.tsatmain04c5799.lifecycleSourceinloopx/control_plane/work_items/replan_semantics.tstests/control_plane_ts/replan_semantics.test.ts"lifecycle reconstruction excludes rows closed by an inferred successor"indexInferredSuccessors,taskClass,readResume,idlifecycleObligationScope And Continuation
Validation
unitpassednode --experimental-strip-types --test tests/control_plane_ts/replan_semantics.test.ts: 31/31. The new test fails on base (with the basereplan_semantics.ts) and passes on head. It covers the resume edge, the unblock edge and the non-advancement negative.integrationpassedpytest 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_paritypassedprojectReplanSemantics: base raises "lifecycle source does not match the admitted obligation", and head returnsreceipt_bound_replan_settlement. No state was written.real_entrypointpassedloopx 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 packetvision_outcome_checkpoint_requiredfor the same obligation. The live store was not touched (mtime and size unchanged). The installed CLI snapshot still needs this fix after merge.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
N/A
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).