fix(goal): surface declared vision fallback gaps in frontier projection - #3979
Conversation
A fallback direction declared in the goal vision used to disappear silently once the primary path blocked: the blocked-successor wait state clears acceptance gaps, so the fallback text stayed in the vision while the scheduler had no selectable successor for it. Add an advisory read-path check that keeps each declared fallback accounted for at projection time. When the primary lane is blocked and none of the three dispositions holds (a runnable open Todo referenced via todo_delta, a bounded create/reopen successor declaration, or an explicit terminal no-follow-up disposition via a closed-family state or path_delta.outcome=stop), exactly one vision_fallback_unresolved gap is projected into the independent fallback_gaps field, which the wait state never clears. The field is advisory only: it does not enter the acceptance-gap replan stream and does not render into CLI output surfaces. Focused fixtures cover the three acceptance checks from the issue: blocked primary plus a runnable fallback stays selectable, an unresolved declared fallback projects exactly one actionable gap, and a valid terminal disposition closes the gap without regenerating it. Signed-off-by: now-ing <now-ing@users.noreply.github.com>
Drop the schema_version field from the vision fallback gap: the sibling acceptance-gap records in the same projection carry only their typed kind, and the repo's versioned schemas all live under the loopx_ prefix, so a standalone goal_fallback_gap_v0 constant deviated twice for no consumer. Signed-off-by: now-ing <now-ing@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
动机
结论:REQUEST_CHANGES,精确 head 022263c218189c2ef5140b6d56bfd9ba68c001b9。两个 P2 正确性问题阻断了本 PR 的核心验收,并非可选风格建议:
- [P2] 英文单词出现不等于声明了 fallback。
fallback_disposition.py:44-54只在自然语言里匹配\bfallback\b。生产 projection fixture 中,“No fallback is authorized; wait for the primary prerequisite.” 被投影成需要补建/保留 fallback 的 gap;“主路径阻塞时,执行已声明的备用方案。”却完全没有 gap。前者与声明相反,后者继续静默丢失真实方向。最小修复是从明确的结构化声明/现有 path-disposition 关联读取意图;不要用扩充中英文关键词或否定词列表来补第二套 prose 分类器。需加入无 fallback、否定/引用文本、多语言声明的反例。 - [P2] 其他 Agent 的主路径 Todo 被当成当前 fallback 已解决。
fallback_disposition.py:91-108,175-178汇总 backlog 等槽位,只有 open/advancement 检查,没有当前 Agent 可选性,也没有声明方向到具体 Todo 的关联。复现:当前 Agent 的主 successor 仍 deferred,另一个 Agent 持有 primary prerequisite;vision todo_delta 同时 retain 这两个主路径 Todo,根本没有 fallback Todo,结果 fallback_gaps 消失。最小修复应复用权威的 Agent-scoped eligible/selectable frontier,并确认 Todo 与这个 fallback 的对应关系;不能把任意 todo_delta ID 和任意 open backlog 的交集当作完成证据。
Issue #3916 要求声明的 fallback 在主路径阻塞后仍有可执行后继或有证据的终止处置,允许从一个警告开始。这个目标有价值:文字里的备用方向不应消失在 blocked-successor wait 中。但当前实现既不能可靠识别“声明”,也不能证明“这个 Agent 有对应工作”,所以不能以新增字段本身作为 issue 已解决的证据。
改动思路
should_run_prepare.py 调用 build_goal_frontier_projection_context_from_status,读取最新 agent vision 和 Todo summaries。已有 wait state 会清空普通 acceptance_gaps;PR 在这个步骤旁调用新 helper,再将最多一个 gap 通过两个 builder 参数传入最终 goal_frontier_projection.fallback_gaps。这是实际 quota 生产路径,不是仅供测试的模块。
正向路径:英文声明、主路径等待、没有匹配 Todo/终止处置 → 生成一个 JSON advisory gap,普通 acceptance_gaps 仍空、replan_required 仍 false。已有真正可选且被引用的 fallback Todo 时,quota 的原有选择规则选中它。负向路径:英文否定句也被当作声明;或另一个 Agent 的主路径 Todo 命中宽泛集合使 gap 消失。新字段不接入义务和重排,因此不会直接启动执行,但会误导读取它的操作者/Agent。
具体改动
三个文件共 +455/-0,无机械搬移:新生产模块 199 行,既有 frontier 模块增加 21 行接线,235 行 pytest fixture。没有 UI、renderer、CLI 文案或 schema 文件改动。
关键代码讲解
fallback_disposition.py:44_declares_fallback_direction检查 vision_patch 的 acceptance/vision 文本及顶层 vision_summary。这里是新增领域判断的事实来源,目前是 regex,不是 typed declaration,见第 1 项。fallback_disposition.py:91_summary_runnable_open_todo_ids从五类 summary 槽提取 ID;_item_is_runnable_open_advancement重判 status/task_class。它的“runnable”弱于调度器的可选性,且缺少 agent_id 输入;原 quota fixture 的跨 Agent 情形揭示了差异。fallback_disposition.py:140declared_fallback_gap_from_agent_vision先排除 closed-family/stop,再检查声明与 blocked 主路径,随后通过 Todo ID 交集或 create/reopen 文本 delta 消除 gap。最后生成固定 reason_code/recommended_action,最多三个 unresolved IDs;generated_at 也做了长度限制。终止状态复用现有 helper 是正向的;todo_delta actions 却复制了 sibling 常量,应收敛到同一个 owner。goal_frontier/__init__.py:1475的 context builder 接入 helper;build_goal_frontier_projection只添加 fallback_gaps,不改变 acceptance/replan 分支。这证明“advisory”描述与当前机器执行行为一致,但不证明 gap 的内容正确。test_goal_frontier_fallback_disposition.py的六项测试覆盖英文 happy path、无英文关键字、closed/stop、create delta 和已有可选 fallback;未覆盖否定文本、多语言或其他 Agent 的主路径引用。创建 delta 无实际 Todo 的探索探针另有普通 acceptance/replan gap,因此本次没有将它报成“完全静默”的独立 finding。
对主干的风险
本地原新增测试 6 passed,frontier/replan/blocked-successor/vision succession 合计 117 passed;三个独立语义探针 3 failed(否定句、多语言、跨 Agent 主路径误作 fallback)。Ruff 和 diff hygiene 通过,远端旧精确 head 的 CI 执行检查成功。未运行全仓测试或模型调用;本次使用合成 quota fixture,通过实际 production projection builder 复现,没有修改活动目标或注册表。
无 opt-in/default-off 声明,此 advisory 会在正常 projection 路径默认计算;未新增 actor 权限,generic 文案无业务领域限定,不制造 user gate,也未把强制义务伪装成 guidance。主要风险是输入语义和所有权被弱化,不是权限升级。新增 schema 形状虽为可选字段,仍是输出合同变化,PR body 已披露;现有 Markdown renderer 和 Workspace 没有消费 fallback_gaps,所以本 PR 本身没有可展示的前端改进,不应以它关闭“用户看到了警告”的验收。
我的整体评价
警告式切入比新建 fallback 工作流引擎合理,原 blocked wait 和 terminal helper 的复用也应保留。但“声明”与“可执行关联”这两个核心事实不应靠 regex 和第二套宽泛 Todo 分类来猜。按原 issue 重新评估,新增 199 行领域逻辑只有在这些语义可验证时才值得维护。相关简化建议是复用结构化 path/linkage 与权威 selectable frontier,并收拢重复 action 常量;不要为了修关键词识别继续扩张词表。
当前 hold,修复上述正确性缺口后再按新 head 复审。没有改代码或合并此 PR。就发布排序而言,这是后端 JSON 诊断补充,优先级低于已经验证的个人工作区交互与可靠性修复。
English verdict: REQUEST_CHANGES at 022263c218189c2ef5140b6d56bfd9ba68c001b9. P2 blockers: prose keyword matching invents a fallback for an explicit negation and misses a Chinese declaration; an unrelated other-agent primary Todo can suppress the missing-fallback warning. 117 existing focused tests pass, while three independent production-projection probes fail; Ruff and diff checks pass. Reuse structured declaration/linkage and agent-scoped selectable frontier rather than extending keyword heuristics. Advisory JSON only; no Workspace UI improvement or merge claimed.
The prose fallback-word matcher invented a gap for explicit negations (No fallback is authorized) and missed non-English declarations. A declaration now requires a structured todo_delta linkage entry (activate/resume/retain) outside the blocked-successor wait scope; prose text alone never projects a gap. Completion evidence now reuses the authoritative agent-scoped selectable advancement frontier (slot order and item predicates of todo_advancement_frontier_counts), so a peer-claimed primary prerequisite retained in todo_delta no longer suppresses the missing-fallback warning, and linked non-advancement work does not count as resolution. Converge the todo_delta action constants and the entry parser into fallback_disposition as the single owner, re-exported by the package root, removing the duplicated sibling constant sets. Signed-off-by: now-ing <now-ing@users.noreply.github.com>
|
Thanks for the precise probes — both P2s are fixed at P2-1 (word occurrence ≠ declaration). The P2-2 (other-agent primary Todo as resolution). Completion evidence is no longer an arbitrary todo_delta × open-backlog intersection. It now requires the declared linkage id to sit on the authoritative agent-scoped selectable advancement frontier — a new id-level mirror of Nit. The duplicated action constants and the two divergent Verification: 13 tests in the focused suite (including all three probes), 235 across the frontier/replan/blocked-successor/vision domain, 261 with consumers and m6 gates, 14 architecture, 43 on the TS |
huangruiteng
left a comment
There was a problem hiding this comment.
动机
结论:REQUEST_CHANGES,精确 head d7985ff38735363531ecb51ea640706731570a6a。本轮修复方向有两点明显进步:删掉了 prose 关键词分类器,否定句不再误报;同时补上了 Agent claim / task class / exclusion 过滤。13 个 focused tests、Ruff 和远端 11/11 checks 都通过。但核心 fallback 关联仍没有被结构化表达,且我新增的生产 projection 探针证明一个不相关的 create 可以让真正缺失的 fallback 再次静默消失,因此当前仍不能关闭 #3916。
改动思路
当前实现把 todo_delta 的 activate/resume/retain 解释为“声明 fallback”,把任意 create/reopen 解释为“fallback 已有 bounded successor”,再把这些 ID 与一个 Agent-scoped advancement ID 集合求交。这个模型比自然语言正则稳定,但 todo_delta 本身只是通用 Todo 变更日志,没有 fallback 类型、方向 ID 或 declaration→successor 关系;它无法回答“哪个 Todo 对应哪个 fallback”。
具体改动与阻断项
- [P2] 不相关的
create/reopen会全局关闭 fallback gap。fallback_disposition.py:203-205只要看到任意 create/reopen action 就直接返回None,完全没有比较 successor ID 与已声明 fallback linkage。独立复现:blocked primary;retain:todo_declared_fallback;没有该 Todo;再加入create:todo_unrelated_maintenance。当前 projection 得到fallback_gaps=null、acceptance_gap_count=0,只剩 blocked-successor wait state——正是 #3916 要防止的静默消失。最小修复必须把 create/reopen 与具体 fallback 声明做 typed 关联,并加入“unrelated create 不得消除 gap”的负向 fixture。 - [P2] 通用 Todo linkage 仍被当作 fallback declaration。 新测试
test_other_agent_primary_todo_does_not_resolve_the_gap的注释明确写着“there is no fallback Todo at all”,却要求 peer-held primary prerequisite 生成vision_fallback_unresolved。也就是说普通 primary-pathretain被重新命名成了 fallback 声明,产生语义假阳性;另一方面,真正仅存在于 vision prose 的声明现在全部被忽略。请增加一个明确的结构化 fallback declaration/relationship(可在 agent vision 或既有 task-graph/linkage contract 上做最小 typed 扩展),再据此逐个验证 runnable/create/terminal disposition;不要继续从通用 todo_delta 猜关系。 - [P2] “复用 authoritative frontier”目前仍是复制算法。
agent_scoped_selectable_advancement_todo_ids重新实现了todo_advancement_frontier_counts的 slot precedence 和 predicates;测试只证明当前单个 fixture 的计数一致,不能防止未来一个 owner 修改 slot/predicate 后另一份漂移。建议让 projection 的一个共享 helper 返回 authoritative eligible items/IDs,再由它派生 counts 与 fallback resolution,消除第二事实源。
对主干的风险
这条路径默认在每次 goal frontier projection 中执行,虽是 advisory JSON、没有直接接入 obligation/replan,但消费者会把 fallback_gaps 当作结构化事实。当前会同时出现两类错误:普通 Todo 被标成 fallback;真正缺失的 fallback 被一个无关 create/reopen 掩盖。后一类已通过 production builder 复现为 acceptance gaps 也被 wait state 清空,所以不是仅展示层的小偏差。改动共 3 文件 +616/-12,新增 239 行领域判断;在关系未 typed 之前维护成本和误导风险偏高。
我的整体评价
方向仍然正向:独立 advisory field、复用 terminal disposition、避免制造 user gate、保持 fallback gap 不进入普通 replan stream,这些都值得保留。当前 blocker 很集中,不需要扩成 fallback workflow engine:补一个最小 typed declaration→successor 关系,按关系验证 disposition,并把 selectable frontier IDs 收回同一个 owner。修复后我会按新 exact head 复审。
English verdict: REQUEST_CHANGES at d7985ff38735363531ecb51ea640706731570a6a. The prose heuristic is gone and agent-scoped filtering improved, but the fallback relationship is still not represented. An unrelated create:todo_unrelated_maintenance suppresses the real missing-fallback gap entirely under the blocked-successor wait state, while a generic retained primary prerequisite is treated as a fallback declaration even when the test says no fallback exists. Add a typed declaration-to-successor relation and derive selectable IDs/counts from one authoritative helper. 13 focused tests, Ruff, and all 11 remote checks pass; the independent negative production-projection probe fails semantically.
|
已按最新 review 意见修复,更新至 head
本地验证:
|
… frontier items Add a structured fallback declaration-to-successor contract to resolve fallback directions without guessing from generic todo_delta actions. An unrelated create/reopen action no longer suppresses declared fallback gaps, and generic primary-path retain actions no longer trigger false positive fallback warnings. Derive both agent_scoped_selectable_advancement_todo_ids and todo_advancement_frontier_counts from a single authoritative helper todo_advancement_frontier_items in projection.py, eliminating duplicate precedence and predicate logic. Signed-off-by: now-ing <now-ing@users.noreply.github.com>
496166c to
1e0e20d
Compare
|
Thanks for the round-3 probes — all three findings are addressed at Typed declaration→successor relation. A fallback direction is now a typed relation instead of an interpretation of generic todo_delta actions: a Unrelated create/reopen no longer suppresses the gap. Resolution now requires the create/reopen action to reference the declared successor, not merely to exist. Your probe — blocked primary, a declared fallback that is missing, plus No more false positives from generic retains. A retained primary prerequisite with no fallback declaration projects nothing ( One frontier owner. The selectable-advancement ids are no longer a re-implementation: Verification: 17 tests in the focused suite (13 prior plus the four new probes/inversions), 30 across the maintainability ratchet and CLI output budget gates, Ruff check and format clean on all changed files. CI is running on the exact head; the round-2 red/green probes still pass with the new relation model in place. |
huangruiteng
left a comment
There was a problem hiding this comment.
动机
REQUEST_CHANGES,精确 head 1e0e20da0684fef09518ba842eb4e385dcb1176e。旧的 prose 猜测与 unrelated-create 消除 gap 已改善,但新 declaration 仍没有接通实际写入/读回路径。
[P1] 真实 Vision 入口丢弃新 declaration,测试绕过它后才出现 gap。 fallback_disposition.py:116-123 消费 fallback_declarations 等新字段,semantic_history.py:170-173 只从收到的历史对象转发两个字段;未改动的 normalize_goal_vision_packet() 经真实 TypeScript goal.vision_checkpoint.evaluate prepare 后将 declaration 丢弃,compact_goal_vision_packet() 也会丢弃它。用相同合成 Vision 经 production preflight 后再调用 production frontier builder,结果 acceptance_gaps=[] 且没有 fallback_gaps;直接使用测试手填的 raw history 则有 gap。实际 caller 仍会遇到本 issue 要解决的静默消失。最小修复是让一个有界、唯一的 typed declaration 通过既有 TS Vision 写入验证、持久化、status/shared-runtime compaction 和历史读回;补真实 write→独立 readback→quota/frontier 的 fixture,不要仅继续给 reader 加别名。Todo fallback linkage 的新字段同样需要证明受支持的 authoring/metadata 路径;当前新增测试只是直接向 summary dict 塞字段。
改动思路
Issue #3916 的目标有价值:主路径阻塞后,明确声明的 fallback 不能消失。PR 保留独立 advisory fallback_gaps,不制造 user gate,也不把 gap 强行送入 acceptance replan stream。最新 head 把“声明”从 generic todo_delta 分离,并让 selectable IDs 与 counts 复用 items owner。这两点优于上轮实现。
正向路径在直接构造的已含 declaration 历史中成立:primary 等待、fallback 缺失 → 单个 bounded gap;存在本 Agent 可选 successor → 无 gap;无关 create 不再清除 gap。负向的真实路径却是:caller 输入 declaration → TS preflight/compact read model 丢字段 → semantic_history 没有可转发的数据 → parser 得不到声明 → wait state 清空普通 gaps 后无任何 fallback 提示。
具体改动
五文件 +1014/-69:新增 375 行生产 parser/projection、470 行测试,frontier 接线、history 字段转发与 Todo projection 提取;不是纯展示 warning 的几行变更。
FallbackDeclaration记录 declaration、target、successor,candidate_todo_ids联合三者。关系比 prose 明确,但支持三个顶层别名、patch 别名、多个字段别名及箭头/冒号字符串没有已验证的生产 caller,建议收敛为一个受写入契约承认的形状。declared_fallback_gap_from_agent_vision()复用 closed-state 与 blocked-successor helper,再按 selectable IDs/create/reopen 判断 disposition。仍需审查其减去 waiting IDs 的语义:显式声明本身指向等待中的 Todo 时,probe 得到无 gap;“不可执行”不应自动等同“已解决”。目前先由生产 declaration 接线问题阻断。todo_advancement_frontier_items()成为 items/IDs/counts 的共同来源,删除上轮第二套 predicate 的方向正确;原数字摘要 lower bound 仍在 counts 保留。不要把有计数就等价于可恢复所有具体 ID。semantic_history.latest_agent_vision_from_runs()和三个 frontier builder 只负责读回/转发,不能替代前置的 typed write owner。- 新测试涵盖 peer-owned/monitor/unrelated-create/terminal 等边界,但 raw fixture 注入跳过了真实 Vision prepare 和 status compaction,解释了为何 17 项绿灯仍漏掉核心路径。
对主干的风险
独立验证:17 focused tests +128 adjacent frontier/Vision/checkpoint tests 全部通过,Ruff 通过;独立 probe 调用真实 TS preflight,并分别对 raw、prepared、compact Vision 运行 production frontier builder,只有 raw fixture 能保留 declaration/gap。未修改活跃 Goal,也未把此局部证明当成完整 CLI 持久化验收。完整写入/readback、全部计数提取的 baseline parity 仍未验证,不能据此批准。
这是默认 read-path 行为,没有 opt-in 声称,也没有新 peer authority。Advisory 与 must-attempt obligation 的分离保持正确;但新领域关系必须由已有 typed TS 边界接受,不能在 Python reader 中自行假定一套持久协议。原 issue 要一个可用 warning,目前代码量增长而可用入口未成立,value/maintenance 比例尚未证明。
我的整体评价
保留独立 advisory field 和共享 frontier-items 提取;删除无真实 caller 的兼容别名,先完成最小声明形状的 production write/readback 闭环。Future-facing pass 应落在既有 Vision owner,而非继续扩展 reader parser。这次不是要求把 warning 扩成 fallback workflow engine,而是要求新增的关系能被产品真实保存和读取。当前不能关闭 #3916。
English verdict: REQUEST_CHANGES at 1e0e20da0684fef09518ba842eb4e385dcb1176e. The real TS Vision preparation and status compaction drop the new fallback declaration fields; only raw test-history injection reaches the new warning. Independently reproduced the missing gap after production preparation, with 145 focused/adjacent tests and Ruff passing. Wire one bounded typed declaration through the existing write/readback owner, and remove unsupported alias scaffolding before claiming the issue is solved.
…te contract The real caller entry dropped the round-3 fallback_declarations: the TS-owned goal.vision_checkpoint prepare whitelisted them away, and the status/shared-runtime compact read model mirrored that loss, so only tests that hand-filled raw run history could project a fallback gap. - prepare now validates and carries one bounded shape: at most four entries, unique non-empty declaration_id, optional target_todo_id and successor_todo_id, each public-safe and 120-char bounded; over-wide, duplicated, unsafe, or id-less packets are rejected explicitly instead of silently losing the declared fallback direction - compact_goal_vision_packet mirrors the same bounds so the persisted declaration survives status and shared-runtime read-model compaction - the frontier parser now consumes only the contract-written shape; the fallback_relationships/fallbacks aliases, arrow/colon string forms, renamed-key fallbacks, and the un-authored todo-summary linkage fields are removed rather than kept as reader-only compatibility - tests exercise the production chain end to end: caller packet through the real TS prepare and compact read model into run history, an independent semantic-history readback, and the quota/frontier projections; alias shapes stay non-declarative Signed-off-by: now-ing <now-ing@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
动机
审查 head:54519bd0089adde8fdaa19940bcf6aeb11e46f37。结论:REQUEST_CHANGES。
[P2] 真实 refresh-state 的 run index 仍丢弃 fallback_declarations,后续状态读取看不到提醒。 新增 semantic_history.latest_agent_vision_from_runs 保留逻辑依赖索引存在该字段,但未修改的 loopx/state_refresh.py:_build_state_refresh_output_projections(533–543 行)仍按旧 allowlist 写 agent_vision,遗漏 fallback_declarations。新 compact helper 并没有接入这个实际 writer。
在隔离的合成 Goal 上运行真实 CLI refresh-state、TS prepare 和磁盘写入,命令 exit 0:响应和完整 run JSON 都有 declaration;runs/index.jsonl 和从索引恢复的 latest vision 都没有。将真实完整记录交给相同 blocked-summary 投影能得到 vision_fallback_unresolved,实际索引记录则没有该 gap。不是 parser 不接受,而是成功之后的持久化/独立读回断链。
原始 #3916 希望主路径等待时,显式声明的 fallback 不再静默悬空:关联可执行 Todo、形成有界后继,或明确终止。它要的是一个投影提醒,不是自动创建 Todo 或新的规划引擎。
改动思路
当前通过 typed fallback_declarations 表达意图,既有 Todo frontier 决定是否 runnable,独立 fallback gap 只做 advisory,不混入 acceptance、quota must-attempt 或用户 gate。方向合理。此前 TS prepare 丢字段的问题已修,但需要走完真实 writer → index → later consumer,而非只验证 normalize / compact 的组合。
最小修复应复用现有 compact serializer 或补齐实际 writer 的同一契约,避免维护另一套字段白名单。用真实 refresh CLI 写盘后,再从索引进行独立 status/quota 读取,证明等待场景出现提醒;不需要增加自动 mutation 权限。
具体改动
完整审查覆盖八个文件:frontier 入口、289 行 fallback_disposition helper、semantic_history、goal_vision、typed vision_checkpoint、Todo projection helper 抽取,以及 Python 和 TS 测试;整体约 +1249/-72。PR 描述原来的“无 TS / schema 改动”已不符合当前 head,应更新。
关键代码讲解
normalizeFallbackDeclarations/ vision checkpoint prepare:校验有界列表、唯一 declaration_id 和字段预算,写入 agentVision;真实 CLI 已证明本段现在可通过。compact_goal_vision_packet/latest_agent_vision_from_runs:前者新增字段保留,后者消费最新历史;问题是实际 run-index serializer 在两者之间没有传递字段。对应真实调用链不是测试手工组装的 run dict。fallback_disposition:typed declaration → blocked-primary 判断 → runnable successor 或 terminal disposition → 最多有限条 unresolved gap。不是用任意 prose 关键词判定,也没有代替 Todo owner 或直接创建工作。todo_advancement_frontier_items和 frontier 入口:复用既有可执行筛选,排除 peer-owned、monitor、waiting 等项,并把 fallback gap 与其他诊断分开。该抽取同时服务计数与可选择 ID,必须维持既有筛选语义。
正向 helper 路径:显式 declaration 经 typed prepare / compact,被 blocked frontier 识别为未解决,或被已有 runnable / terminal 证据消解。真实负向路径:CLI 成功 → 完整记录正确 → 索引投影丢字段 → latest vision 无 declaration → 提醒消失。现有 _fallback_vision_run 测试手工拼装历史行,跳过的恰是出问题的 writer。
对主干的风险
113 项聚焦 Python 测试、16 项 TS 测试、Ruff 和 diff check 通过;GitHub 可见 checks 通过,发布任务按设计跳过。独立真实 CLI 在 exact base bf217e1e01bec79f357c9ecbd580cf2dfa73db8b 不保留声明,当前 head 只在响应/完整记录保留,索引仍不保留。正控制证明相同投影拿到字段后能输出 gap。
未跑全仓库,也未证明所有抽取后的 frontier 组合与基线逐项等价;不能把聚焦绿测当作全局兼容。该字段是显式输入,不授予自动执行权限;实际 Todo 创建并未由本 PR 实现,不能把 create/reopen 声明本身称为已完成创建。无新 PostgreSQL 存储实现。
我的整体评价
REQUEST_CHANGES。从“一条提醒”扩展到 typed schema、历史序列化、frontier 抽取后,应重新证明完整交付价值;当前 change proportionality 仍 not_yet_proven,因为真实后续消费者没有收到新字段,而不是单凭行数否定。前瞻性改进应收敛在已有 vision 序列化边界:减少重复字段知识,补真实持久化读回测试,保持提醒与强制义务分离。修复这个贯穿路径后再评估完整 head。
English verdict: REQUEST_CHANGES at 54519bd0089adde8fdaa19940bcf6aeb11e46f37. Real refresh-state accepts and returns fallback_declarations, but the production run-index writer drops them; later history-based consumers therefore lose the unresolved-fallback warning. 113 Python and 16 TS tests pass, as do visible CI checks, but an independent real CLI → disk → index readback reproduces the missing field. Reuse the actual serializer boundary and cover separate readback, not a hand-assembled history fixture.
|
Thanks for the precise reproduction — it matched exactly. The real entry chain dropped the declaration at two whitelists: the TS-owned
Full run: 19 focused + 237 adjacent frontier/vision/checkpoint/quota tests, the maintainability ratchet, output budget/differential, 605 TS tests, typecheck, and Ruff all green; the only failures in the broad sweep pre-exist at the base head. |
…list The state-refresh run index still wrote agent_vision through the old field allowlist, so a successfully prepared and persisted fallback declaration disappeared from runs/index.jsonl and every later semantic-history read missed the frontier reminder the declaration exists to provide. The allowlist now carries fallback_declarations, pinned by a builder-level index regression that feeds a real typed declaration through and asserts it survives the index projection. Signed-off-by: now-ing <now-ing@users.noreply.github.com>
The previous formatting pass expanded historical compact imports and pushed the module past the maintainability ratchet line budget. Restore the original layout and reapply only the fallback_declarations allowlist entry, keeping the module at its previous 1479 lines. Signed-off-by: now-ing <now-ing@users.noreply.github.com>
|
Found and fixed at The allowlist now carries Verification: state-refresh projection tests (including the new index regression) and the full fallback-disposition suite pass, maintainability ratchet green, CI 11/11 on the exact head. |
huangruiteng
left a comment
There was a problem hiding this comment.
动机
APPROVE,exact head b765958076d5ed655261bab040696a762ff322b7,全量基线 bf217e1e01bec79f357c9ecbd580cf2dfa73db8b。此前 54519bd0089adde8fdaa19940bcf6aeb11e46f37 的 run-index 丢字段 blocker 已修,本轮独立的 CLI→磁盘→后续 quota 读回证明提醒确实可达。
#3916 要求主路径等待时,显式 fallback 不再静默悬空。目标是一条有界 advisory,不是自动创建 Todo、授予 peer 权限或增加强制执行任务。只有关键消费者真正收到声明,增加 typed input、serialization 和 frontier 的成本才有实际收益。
改动思路
Vision 中显式、限量的 fallback_declarations 由 TS prepare 验证;Python compact/history 保留;真实 refresh-state 的 index writer 本轮补上同一字段;后续 quota 从历史恢复 vision,再结合权威 Agent frontier 投影 unresolved gap。
比较 base/head 的 vision normalize/compact、run-index writer、semantic history、blocked-successor wait 和 Todo frontier。复用既有 runnable/ownership 判定,不另造任务状态源;fallback_gaps 不进入 acceptance-gap replan stream,因此可以在普通 acceptance gaps 因等待而清空时保留提醒,又不把提醒升级为 obligation。
具体改动
全量十文件 +1316/-75:frontier 入口与 289 行 helper、semantic history、Python vision compact、TS checkpoint、Todo projection 抽取、state_refresh,以及三份 Python/TS 测试。最新两文件 +67/-3,主要是 writer allowlist 与回归测试,核心机制没有再扩张。
normalizeFallbackDeclarations:列表最多四项、declaration_id 唯一、字段预算受控;prose 和普通 todo_delta 不会自动变成 fallback 声明。compact_goal_vision_packet/_build_state_refresh_output_projections/latest_agent_vision_from_runs:串起 prepare、完整 run、索引、后续读回;本轮实际 writer 保留字段,补上上次只验证 helper 组合的缺口。declared_fallback_gap_from_agent_vision:显式声明 + 主路径阻塞 + 没有 runnable/terminal/有界后继声明,产生独立 gap。peer-held 或 monitor 不能当作当前 Agent 可执行后继。todo_advancement_frontier_items/ counts / selectable IDs:共用 executable backlog 优先级和 claim/exclusion 规则,计数仍保留已有 summary/peer diagnostic floor;复用此边界比复制筛选器合理。- frontier 入口:最多一条 gap、有限 unresolved ID,不新增调度器或自动 mutation。
create/reopen在这里是有界后继声明的 disposition,并不证明 Todo 已实际创建,不应在产品描述中混称。
对主干的风险
真实反事实采用相同隔离 registry、文件 Todo、typed vision 输入:peer 持有 prerequisite,当前 Agent 的 primary Todo deferred,声明 fallback 尚无 runnable Todo。旧 54519bd 的 refresh 成功且响应保留声明,但 index=false,后续 quota 无 gap;当前 refresh/index 均保留,独立 quota CLI 输出 vision_fallback_unresolved,包含 exact fallback ID。两边普通 acceptance_gaps 都为空、replan_required 都是 false、primary 仍 waiting——没有借修复提醒改变执行义务。
直接 status 命令在该合成场景没有渲染此 frontier 字段;真正验证的最终消费者是随后独立的 quota CLI,不能把它写成所有 status 展示面都已验证。status/quota 的整体退出码 1 来自合成 Goal 的健康/等待状态,无 exception/error;refresh exit 0,目标字段正常读回。
本轮 21 focused Python +111 adjacent Python tests、16 TS tests、TypeScript typecheck、Ruff、diff check 通过。覆盖 runnable fallback、终止 disposition、无声明、无关 create、monitor/peer 以及 blocked-successor 分支;远端可见检查成功,发布任务有条件跳过。未跑全仓库或所有可能的旧缓存形状,不把这些结果等同于穷举证明。
无 opt-in/default-off 能力声明或新安装指令;这是既有 vision 的显式输入扩展。无声明不会生成 gap。错误与建议保持 Goal-neutral;typed declaration 不是 prose 关键词判定,advisory 与机器 obligation 清楚分离。
我的整体评价
原始需求到真实持久化消费者现在闭环,本轮不再维持“机制价值未证实”的阻塞。这个独立提醒的边界仍足够窄,并复用了已有状态所有者。
未来向整理建议收敛 vision compact 与 run-index 的字段白名单知识,避免下一个字段再次只修一个 serializer;但本次 surgical writer 修复已有真实读回证据,不必为了去重扩大重构。PR body 中“无 TS/schema 改动”等旧描述应更新。批准此 head,未合并。
English verdict: APPROVE at b765958076d5ed655261bab040696a762ff322b7. The production run-index writer now preserves fallback declarations. Paired real refresh/file/quota probes change the prior missing warning into the expected unresolved-fallback advisory while preserving waiting state and no replan obligation. 132 Python and 16 TS tests, typecheck, Ruff, diff checks and visible CI pass. Direct status presentation and all cache permutations are not claimed as fully qualified. No merge performed.
Summary
A fallback direction declared in the goal vision used to disappear silently once the primary path blocked: the blocked-successor wait state clears acceptance gaps, leaving the fallback text with no selectable successor and no structured channel to surface it. This adds an advisory read-path projection check: when the primary lane is blocked and none of the three dispositions holds (a runnable Todo referenced via
todo_delta, a bounded create-reopen successor, or an explicit terminal no-follow-up disposition via the closed-state family /path_delta.outcome=stop), exactly onevision_fallback_unresolvedgap is projected into the new independentfallback_gapsfield — which the wait state never clears and which does not feed the acceptance-gap replan flow.Advisory only, per the issue's suggested starting point ("one projection warning plus a focused fixture"): no obligation wiring, no new schema, no new state machine.
Issue Or Task
Closes #3916
Validation
python3 -m pytest tests/control_plane/test_goal_frontier_fallback_disposition.py— 6 passed, one per acceptance check:build_quota_should_runreturnsdecision=="run"withselected_todo==<fallback id>)acceptance_gaps==[]under the wait state whilefallback_gapscarries exactly one gap (the issue's core bug scenario)path_delta.outcome=stop, parameterized) closes the gap, and a second projection does not regenerate itgoal_frontier|build_quota_should_rundependent tests → 876 passed (1 pre-existing environmental failure unchanged on the untouched baseline)test_m6_quality_gates.py→ 3 passed;test_cli_output_budget.py→ 21 passed;test_cli_output_differential.py→ 33 passed (fallback_gapsdoes not enter the CLI rendering surface)ruff checkclean on all three changed files; red/green probes: disabling gap generation, the terminal check, or the runnable-resolution each turns the matching acceptance fixture redType of Change
LoopX Area
loopx/command surface)apps/presentation/dashboard)Technical Direction
Boundary Checklist
.loopx/, credentials, private traces, raw sessions, or local machine paths committedSigned-off-bytrailer (git commit -s)