fix(replan): keep long-chain obligations scoped and executable - #4825
Conversation
…ision Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
评审对象:d86bbb1575e148a727c0a032b2db03c9bf2b4ea7
动机
这次修改解决的是 #4667 暴露的一条完整控制面语义断裂:Agent lane 的“长 Todo 链”原先按本 Agent 可选的 claimed + unclaimed 任务触发,但义务又需要由本 Agent 的可归责动作来关闭。于是 14 个已认领 advancement Todo 加 1 个共享候选就会让 lane 进入 replan;在 admission 与 writeback 之间,其他 Agent 对共享池的 claim/edit 又可能改变 full frontier revision,让同一个 Turn 的 obligation id 旋转;与此同时,投影给 Agent 的 vision 写回路径并不属于 long-chain obligation 可接受的 typed outcome,导致按提示写回仍可能被拒绝,只能继续制造“再规划”Todo。
这个 PR 将这三个不一致点一起收敛:Agent-scoped 阈值只统计已认领的承诺;共享候选仍可选但不制造本 lane 的义务;obligation identity 使用 owned material identity,保留 full revision 供诊断和历史 ACK 精确匹配;long-chain 接受并投影带 acceptance summary 与 evidence refs 的 vision path。它完成了 #4667 的可观察目标,而不是只修一个 serializer 或提示文本。
改动思路
权威边界保持清楚:quota_selection.ts 继续提供 claimed/unclaimed 计数;frontier_revision.ts 继续唯一负责阈值、material revision、owned identity、ACK/rearm 和 predecessor proof;replan_semantics.ts 继续唯一负责 obligation source 到 typed outcome 的映射;Python 仅把这些 typed 结果接入现有 Goal frontier 和 refresh/spend settlement,没有重建第二套决策。
正向路径是:15 个本 Agent 已认领的 advancement Todo 触发 claimed_advancement_todos;当前 Todo/Turn 仍是 settlement binding;投影的 --agent-vision-json 带验收摘要、continue|no_change|replan 结果与证据;refresh 持久化 accepted semantic ACK 和 satisfied checkpoint;spend-slot 只执行一次;下一个 quota readback 不再重复要求 replan。共享池在 ACK 前后的增删不会改变 owned identity,而本 Agent 已认领 Todo 的实质修改会重新触发。
反向路径也保持 fail-closed:没有 claimed advancement 的共享队列不产生 scoped duty;不完整/重复/stale frontier、无证据或无 acceptance 的 vision、显式更严格的 satisfying_semantic_outcomes、歧义 successor 都不能伪造 ACK。无 agent_id 的 Goal 总览仍保留原 selectable-pool 阈值,历史 revision-only ACK 仍按 full revision 精确匹配。
具体改动
loopx/control_plane/todos/frontier_revision.ts扩充LongChainObservation.count_kind,在 scoped 路径用current_agent_claimed_advancement_count/current_agent_claimed_open_count判阈值;同时把 derivedobligation_identity_revision放进 trigger,并在 successor predecessor binding 中回传 owned identity。loopx/control_plane/work_items/autonomous_replan_obligation.py仅在 obligation-id hash 中用 owned identity 替代 fullfrontier_revision;原始 full revision 仍留在 trigger 中,兼容诊断、checkpoint 与历史 ACK。loopx/control_plane/work_items/replan_semantics.ts为long_todo_chain增加fresh_vision_path_outcome,但保留所有原 progress exits;显式 outcome 限制和更严格的 vision trigger 仍优先。loopx/control_plane/goals/goal_frontier/__init__.py删除 planning-only Todo suggestion,改为让现有 bound Turn 使用replan_action_packet.writeback_contract,避免 replan 只产生另一个 replan Todo。- 协议、状态机、双语迁移 RFC、课程和 self-repair pattern 同步披露旧默认与新默认;测试用完整 CLI journey 替换旧的孤立 binding case。
关键代码讲解
evaluateLongTodoChain(frontier_revision.ts:232)先同时保留 selectable diagnostics,再根据是否有agent_id选择 claimed 或 selectable measurement。这样共享候选仍参与正常调度,但不会借用本 lane 的 obligation/ACK fence。successorCheckpoints(frontier_revision.ts:149)只为唯一、fresh、完整来源的 successor 重建 predecessor;scoped path 用 claimed counts 判断旧 frontier 是否已经达到阈值,并带回 predecessor 的 owned identity,避免共享池变化让 Python identity codec 对不上。ensure_replan_novelty_policy(autonomous_replan_obligation.py:178)把obligation_identity_revision仅用于 identity payload;缺少新字段的历史 trigger 自动退回 full revision,因此是可读兼容而非一次性迁移。requiredSemanticOutcomes(replan_semantics.ts:30)以 exact trigger kind 扩展 long-chain 的合法出口;显式 declared outcomes 与 vision triggers 仍是更强约束,文本里出现long_todo_chain不会误分类。- Goal frontier 的 long-chain branch(
goal_frontier/__init__.py:1204)不再新增元 Todo,而是把现有 evidence/vision 更新投影为当前 Turn 的合法写回;这没有新增 claim、write 或 spend 权限。
对主干的风险
最强回归风险是 identity 口径错位:若共享池变化仍旋转 obligation,会在已开始的 Turn 中拒绝合法 writeback;若 owned 修改没有旋转 identity,又会把旧 ACK 错用于新的承诺集合。第二个风险是放宽 long-chain outcome 时误放宽 strict vision obligations 或显式 outcome 限制。第三个风险是 scoped 修正意外改变无 Agent 的 Goal overview。
我用相同的新完整 CLI regression 在 base 0ef7ebd749ec97a698a8fc7f2a29844dd368689b 与 head 上做了反例验证:base 在预期位置失败,仍返回 selectable_advancement_todos;exact head 通过完整 journey。Head 的 7 个聚焦 Python 文件共 143 passed,覆盖 shared churn、durable ACK、exactly-one spend、next-Turn readback、历史 ACK、successor 因果与 settlement;两个相关 TypeScript 文件 18 passed,覆盖 scoped/unscoped 阈值、非法 identity、显式 outcome、strict vision 与 invalid vision。控制面 TypeScript typecheck、changed-path Ruff 和 git diff --check 均通过,无失败或跳过。按 Goal 配置未查询或等待远端 CI。
语义与 CI 对齐
这是对现有 goal_vision_replan_contract_v0 词汇的扩展,不是另起协议:runtime typed union、协议/状态机、双语迁移 RFC 与回归测试使用同一组 claimed_*、obligation_identity_revision、fresh_vision_path_outcome 语义。wait_for_ci=false 的当前 capability 要求以本地 repository-native evidence 判定;本次已满足 required positive、material negative 和 repository-required local checks。
我的整体评价
没有发现 blocking finding。这个改动没有用抬阈值、降低 gate 或新增手工状态来掩盖问题,而是把 scope、identity 和 accepted writeback 统一放回现有 typed owner;约 50 行净 production 增量与一个完整 real-CLI regression 对故障成本是成比例的。default behavior 的变化也已明确披露:Agent lane 改为 claimed-scope,无 Agent overview 保持 selectable-scope。
剩余风险主要是聚焦 File-provider fixture 未枚举的 frontier 组合,但本 PR 不改 authority store/provider;现有 143 个 Python 与 18 个 TS case 已覆盖最关键的 scoped/unscoped、peer churn、historical ACK、invalid source、successor reconstruction 与 durable settlement。我认为 exact head 可以批准;合并仍需独立 maintainer authority,并且该 control-plane PR 不应由作者自合并。
English verdict: APPROVE - exact head d86bbb1 aligns claimed-scope long-chain admission, owned obligation identity, and evidence-linked vision settlement; the base mutation fails at the old selectable count, while 143 focused Python tests, 18 TypeScript tests, typecheck, Ruff, and diff check pass.
Goal and result
Long-chain review requested a vision delta that its validator rejected, while changes to shared unclaimed work could rotate a lane's obligation between admission and writeback. This could consume repeated replanning turns without returning to useful work.
The fix makes the projected vision route executable and keeps long-chain duties tied to owned commitments. A real CLI regression follows the projected Todo/Turn binding through peer churn, durable ACK, satisfied vision checkpoint, exactly one spend and a following runnable Turn. Evidence-only maintenance stays quiet; an owned material change rearms.
Closes #4667. Base:
main(0ef7ebd74). Builds on the existing vision/recovery fixes, including #4730.Scope and behavior
The related simplification pass replaces the old large-file binding test with a focused complete-journey regression and reuses the existing TS owners. No frontend/Lark editor companion is needed: those entries consume shared quota facts and have no long-chain setting or separate trigger classifier. No UI or packaged frontend code changed.
Validation
Tested implementation:
d86bbb1575e148a727c0a032b2db03c9bf2b4ea7. Input classes: synthetic/public fixtures. Run state: finished.cqr_fe53886a1dd2eed2517dis valid. All 19 selected checks and all direct checks pass on the clean final head; zero failures/skips or manual holds.Quality scope: 18 files, fingerprint
fe53886a1dd2eed2517d74cdefd67b9425912f0732099185470982f028aa88e0. Safe fix was permitted but not applied during review (zero passes); zero blockers, warnings or advisories.The initial four canonical fixture failures encoded shared-pool triggering; the fixtures now establish 15 owned commitments while retaining shared-tail and historical-ACK checks, and all four pass. The first premerge sweep had a namespace timeout and was invalidated by concurrent staging/committing; its failed results are superseded only by the clean-head rerun. No gate or budget was weakened.
File-backed CLI/history and canonical File provider are exercised. No provider/storage implementation changed; PostgreSQL promotion and live model qualification are outside this fix. All original-Turn checkpoint-recovery tests pass. No active Goal/Todo/lease was used as a test fixture.
Maintainer review and merge required. This control-plane change is not self-merged.