fix(replan): derive causal wait coverage before Todo compaction - #4059
huangruiteng merged 4 commits into
Conversation
Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com>
Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com>
Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Exact head: 3a6c5ca9555f057c27259baf4432ccd970aa9ec2
动机
这次修复针对的是一个真实的 Goal 等待误判:同一个 Vision acceptance 同时依赖 causal Todo A、B 时,旧路径只看到摘要中的 A 正在等待,就可能把整个 Vision 判成合法等待;如果 B 尚未创建、已经被摘要裁掉,或仍可执行,Agent 都会被错误地允许静默等待。
我先按最新审阅契约挑战了设计。关闭的 #4049 通过让 Agent 另写 fallback_declarations 修这个问题,但那会复制已有 planning state,而且缺少稳定的生产、更新和退役流程。本 PR 采用更小的边界:Agent 仍只表达既有 Vision→Todo 因果意图,LoopX 从 canonical Todo 状态推导当前覆盖,不新增一份需要人工同步的 fallback 权威。
改动思路
正常写入路径没有改变:refresh-state 仍把不可推导的规划意图写进 Vision 的 todo_delta;Todo 生命周期、successor 与 resume 关系仍由 canonical Todo 行持有。新增逻辑在摘要裁剪之前读取这些事实,为每个活跃 Vision 构造完整 causal root、真实等待、当前 Agent blocker 和有向 successor 边,再交给 TypeScript reducer 判断“所有 root 是否都能到达合法等待/阻塞”。
因此状态分层是清楚的:Vision 关系是已有持久化意图,Todo 行是 canonical lifecycle,vision_wait_states / causal_todo_ids 是每次重建的 read model,TypeScript 是覆盖决策所有者,Python 只做解析和适配。旧 fallback_declarations 只保留兼容性的 advisory 输入,不再是等待成立的必要条件。
正向路径是 A、B 都能沿 lineage 到达真实等待时返回 agent_scope_wait;负向路径是 B 缺失时要求 autonomous replan,B 可执行时继续选择 B。无关 Todo、排序和摘要上限不会参与 causal root 构造,因此不会改变决定。
具体改动
goal_vision_read_model.py集中原先散落在 frontier、fallback 和 semantic-history 中的活跃 Vision 解析;这是对已有知识的抽取,不是新的状态 owner。goal_vision_wait.py与goal_vision_wait_projection.py从完整 canonical Todo 投影构造每个 Vision 的 causal coverage 输入,并把causal_todo_ids带到等待证明。vision_wait_coverage.ts用显式 typed reducer 验证每个 causal root 是否到达真实 wait 或当前 Agent blocker;缺 root、断边和不完整输入 fail closed。- quota/Todo summary 只消费这个派生 read model;文档同步说明 derivation、兼容字段和 source-completeness 语义。
- Python 与 TypeScript 回归覆盖缺失 root、可执行 root、successor/resume lineage、无关项、顺序与摘要裁剪。
关键代码讲解
attach_active_vision_waits:在 display cap 之前把活跃 Vision 与完整 Todo 集合结合,避免把摘要缺失误认为 canonical 缺失。project_goal_vision_wait_state:把 Vision causal id、Todo lifecycle、wait/blocker 和 lineage 适配成稳定的派生输入;它不持久化第二份业务状态。deriveVisionWaitCoverage:真正的语义 owner;只有所有 root 都被覆盖才允许 wait,缺失或不可达 root 直接返回未覆盖。prepare_should_run:把已验证的 read model 接入现有 quota 仲裁,不在 Python 再实现一套覆盖规则。latest_agent_vision_from_status_payload:抽取并复用既有 Vision 读取逻辑,避免 frontier、fallback 与 semantic history 各自漂移。
对主干的风险
最大风险不是“能否识别一个 wait”,而是摘要、无关 Todo 或旧引用重新获得决策权。我用真实 public CLI 对同一组 registry/state/run-history 做了 baseline/head 反事实:A 等待而 B 缺失时,baseline 错误返回 agent_scope_wait 且 must_attempt=false;本 head 返回 autonomous_replan_required 且 must_attempt=true。B 可执行时两边都继续选择 B;A、B 都等待时本 head 正确返回 wait 并列出 A+B。把无关等待 Todo 从 0 增加到 40,三个决定和 causal 集合都不变。
验证方面,114 项相关 Python 测试、6 项 TypeScript 测试、TypeScript typecheck、Ruff、git diff --check 均通过;标准 premerge 的 18 项检查全部通过;远端 14 项检查成功或按设计跳过。代码量主要来自真实 CLI、compaction 和生命周期回归;生产部分是已有解析抽取加一个小型投影与 reducer,没有继续扩张 #4049 的重复状态协议。
剩余风险是分支基于较早的 main。这个批准只绑定当前 exact head;一旦 rebase 或 head 改变,需要重新核对调用者、merge tree 和上述反事实。
我的整体评价
我没有发现当前 exact head 的阻塞问题。它同时修复了旧误判和上一方案的架构根因:不可推导的意图继续由 Agent 表达,可推导的等待状态由 LoopX 计算;typed TypeScript reducer 保持唯一决策权,Python 不复制规则。future-facing pass 已体现在共享 Vision read model 抽取中,继续增加通用框架反而会扩大维护面。
结论:APPROVE,严格绑定 3a6c5ca9555f057c27259baf4432ccd970aa9ec2。
English verdict: APPROVE on exact head 3a6c5ca9555f057c27259baf4432ccd970aa9ec2. The PR derives complete causal wait coverage from existing Vision intent and canonical Todo lifecycle before compaction, keeps the TypeScript reducer authoritative, and avoids #4049's redundant Agent-authored fallback state. Real CLI baseline/head counterfactuals, 114 Python tests, 6 TypeScript tests, typecheck, Ruff, 18 premerge checks, and hosted CI passed; any rebase requires re-review.
…main-20260908 Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com>
cocolord
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewed head: 0c619324870f2f4ce9e9a550b6bc0228722d5095. Integration baseline: 54681bccd5e5780dc03390488c5afcf217daf692.
动机
仍值得推进。当前主干在 Vision 关联 A、B,而只有 A 合法等待、B 尚未落实时,会返回 monitor_quiet_skip。同一真实 CLI 回归在主干失败,在此 head 通过;这不是由旧评论推断出来的问题。
改动思路
从已有 acceptance、Todo、resume 条件和有向 successor lineage 逐项证明等待资格,在展示裁剪前计算。复用既有写入与生命周期;无需 Agent 再维护 fallback 声明。
具体改动
goal_vision_read_model.py 收拢 Vision 读取、todo_delta 解析与 acceptance gap;projectVisionWaitCoverage 在 TypeScript 中逐个检查 causal binding;attach_active_vision_waits 只把可重算的正向等待证据带过裁剪边界。quota/frontier 与 semantic writeback 共用上述规则,Todo parser/summary 接入完整来源。handler、tsconfig、聚焦测试、协议文档和一条通用修复记录构成其余变更。
正向路径:A、B 都有合法等待,增加 40 个无关项或改变顺序仍 defer。负向路径:B 缺失、属于其他 Agent、被排除或没有有效等待时,A 不能掩盖 B;相关可执行工作出现则正常继续。共享前置任务不会把兄弟任务变成替代关系,归档 predecessor 只通过显式 successor 传递关系。
对主干的风险
这里有意收紧旧的 any-related-wait 默认,文档已披露;普通 acceptance 的 replan 行为改变,权限、quota、终态 Vision 和独立 user gate 仍保留各自约束。验证使用隔离文件 authority 和真实 TypeScript/CLI:159 项 Python 回归、6 项 TS 测试、typecheck、18 项标准 premerge 均通过,公开边界检查通过。未运行真实 Goal、PostgreSQL 集成或 benchmark;此改动不修改存储后端实现。远端 CI 以此 head 的 checks 为准。
我的整体评价
这条修复仍有明确收益。边界收敛已应用:共享读取与解析,TS 保留状态规则,移除旧的 Python 无向合并逻辑;19 文件 +905/-276 服务于同一条等待资格链。先合入本 PR,再处理基于它的 #4061。本结论是作者自查结果,仍需维护者评审;本次没有执行合并。
English verdict: APPROVE conclusion for 0c619324870f2f4ce9e9a550b6bc0228722d5095. The canonical wait-coverage bug still reproduces on current main; per-binding directed coverage fixes it without extra fallback authoring. Validated with 159 Python tests, 6 TypeScript tests, typecheck, and 18 premerge checks. Author-owned review; maintainer review is still required.
A vision that binds A and B can currently defer while only A has a valid wait and B has no materialized Todo. Derive coverage for every existing causal binding from canonical Todo rows before display compaction, using directed lineage and the TypeScript reducer. Reuse one vision read model for quota, Todo projection, and semantic writeback.
Validation on current main
54681bcc: the same real CLI regression fails on main and passes with this change; 159 focused Python tests, 6 TypeScript tests, TypeScript typecheck, and 18 standard premerge checks pass. The fix needs no fallback declarations. Missing/runnable/waiting paths, unrelated rows and ordering, ownership, archived successors, and semantic writeback are covered. No benchmark or live Goal run was launched.Updated the existing branch with current main. The shared read model is also the dependency for #4061; merge this PR first. No merge has been performed by this update.