Repository navigation
fix(todos): fail closed on malformed closure witnesses in typed quota planning - #5825
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | xhigh
Exact head: 0c478b8f4c20ff753f24fc66b98bb3286811751e; immutable baseline: a8b759d03e976646aaec6126112b8407cd2a8272.
动机
通过 heartbeat 或 CLI 读取 Goal 下一步工作的用户,会在损坏的收尾证明下被错误告知已经没有后续工作,剩余任务可能因此失去继续执行的机会。
例如一个已完成任务的证明把数量写成 true,或两个 Monitor 数量都写成非法字符串时,基线仍生成无后续工作的停止意图;候选把证明标成无效,正常 quota 继续保留工作准入。
已验证损坏证明不再产生终态停止;合法空来源、完整证明下的有界展示和 watch-only Monitor 仍可收尾,真实 File/SQLite 的重试、恢复和原 Turn 单次结算仍通过。
这批不切换 provider 默认,不删除历史格式、备份回执恢复、活跃 writer 或 Host IO,也不证明 D2 长期成本、attached App 采用或整个 Goal 已完成。
完整 Python writer/capture 退出、默认 SQLite 发布与持续运行资格仍沿既有路线验收;本批只关闭已复现的证明判断切片。
改动思路
复用现有 TS succession 证明 owner 和 quota 批量入口,既保住有价值的收尾规则,也删除 Python 的重复决策;事实解码与展示还原留在现有 adapter,不新增一次 RPC 或并行状态。
本 PR 交付损坏收尾证明的 fail-closed 修复和重复 Python 判断退役;完整 writer/outbox、备份恢复、SQLite D2、默认切换与实际安装采用保持各自原验收。
先保留有价值的证明规则,再让现有证明生成 owner 同时负责验证。源事实来自既有完整来源,展示上限不能代替来源计数;proof 只是观察,不授予结算权。Python 负责旧类型解码与字段还原,TS 决定是否保留停止意图。没有新增 provider、状态表、调用层或人为同步配置。
具体改动
规范依据:docs/architecture/rfcs/typescript-control-plane-migration-v0.md,spec_revision=a8b759d03e976646aaec6126112b8407cd2a8272。T4 的 scoped duplicate-owner 退役条件已在这批证明判断上验证;完整 T4 writer 退出仍 deferred,沿原有调用方与 D1–D3/L9 验收,不宣称切换默认。改动的 reference 文档是行为披露,不是反过来修改验收让代码通过。
关键代码讲解
loopx/control_plane/todos/succession.ts:216,validateTodoClosureSource:匹配来源、角色、计数与终态证明,严格区分合法整数和非法值;两个非法 Monitor 计数相同也无效。空来源、有界完整证明和合法 watch-only Monitor 保留支持。返回只读有效性及派生意图,不执行 provider 写入。loopx/control_plane/todos/quota_selection.ts:193,projectTodoQuotaPlanning:在现有批量调用中组合选择、resume 与证明规则。v2 明确要求 source facts;v0/v1 返回保持原形。缺少 v2 envelope 直接拒绝,不退回 Python 判断。loopx/control_plane/todos/quota_selection.py:25,_closure_source_facts:只传紧凑来源事实,JSON 前保留 Python 严格整数类型,复用已有 watch-only normalizer。删除 quota_summary 中三个私有决策 helper 后,正常 summary 读取原生结果;仍有调用方的 materialization/IO 保留。
对主干的风险
最强反例是证明被压缩或重复投影后丢失类型、完整性,却继续产生终态。旧 49 项测试全绿仍漏掉这个错误;相同新回归在未修改 base 及其独立 wheel 上都是 5 fail/10 controls,候选 source 和 wheel 都是 15 pass。完整来源 20 项、展示 12 项、逆序与删除展示文字仍得到相同决定;缺少 source proof 或把展示行改成 open 时,两边均不能终态。没有修改旧断言、上调预算或拿 skip 当 pass。
source Python 64、聚焦 TS 40、完整 TS 4112 pass;31 项 PostgreSQL integration skip,未声称实测 PostgreSQL。两边各 4 项真实 File/SQLite CLI completion、恢复和重放通过,未对活跃 Goal 注入故障。TypeScript/mypy/Ruff、semantic smoke、8 路径 privacy scan、DCO 通过。精确 CQR 有效;canary 5 direct + 19 selected 全通过,0 failure/manual hold。CI 按 Goal 当前契约未查询。尚未测试 D2 长期成本、Windows、paid model 或实际 attached App 采用。
语义与 CI 对齐
这批有意修正损坏证明读取,影响 legacy 与 canonical quota 终态推导,已在 PR 和双语文档披露。新增内部 v2 是扩展既有 request vocabulary,未造并行 authority;advisory 未发现支持语法内的新 carrier 不代表无语义变化,full-tree smoke 也已执行。没有可选能力开关,default-off 不适用;合法路径和 v0/v1 的实际 paired parity 已验证。非法证明必须由来源 owner 恢复,回滚只需配套 Python/TS 代码包,无持久化迁移。
我的整体评价
未发现阻塞项。交付判断为 justified_increment:long_horizon improved,避免损坏证据误停后续工作;user_experience improved,无额外激活、确认或重填已知信息。这里的一次 source 修复不能作为整个 Goal 完成证明。相关 future-facing pass 已应用:收尾规则收敛为一个 TS owner,同一批次执行,重复 Python 判断实际删除;备份、writer 和 Host IO 的兼容价值继续保留。
复用现有 TS succession 证明 owner 和 quota 批量入口,既保住有价值的收尾规则,也删除 Python 的重复决策;事实解码与展示还原留在现有 adapter,不新增一次 RPC 或并行状态。
本 PR 交付损坏收尾证明的 fail-closed 修复和重复 Python 判断退役;完整 writer/outbox、备份恢复、SQLite D2、默认切换与实际安装采用保持各自原验收。
APPROVE 仅覆盖这个未变的 exact head。残余资格缺口如上,运行控制面 PR 按仓库规则交维护者合并;本 review 和 canary 都不授予自合并、安装采用或默认切换权限。
English verdict: APPROVE. Invalid closure witnesses now fail closed in the existing typed quota batch; valid bounded/watch-only closure and real File/SQLite recovery remain qualified. No blocking finding. PostgreSQL integration, D2, installed App adoption and the SQLite-default release remain outside this slice. Maintainer merge required.
…ute-facts Both read-correction descriptions stay: main's #5825 closure-witness validation and this branch's route-replan source binding. Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Malformed terminal closure witnesses could turn an active quota read into
terminal_no_followup: Python accepted a boolean item count and treated two invalid Monitor counts as equal. Validate retained witnesses in the existing TS succession owner through the same quota-planning batch, then remove the duplicate Python decision code.The internal request becomes v2; v0/v1 wire behavior, valid empty/bounded/watch-only closure and legacy materialization remain supported. Invalid evidence fails closed. This changes malformed-proof reads across legacy and canonical Goals; it adds no RPC, provider default, persisted schema or settlement authority.
Validation: 64 source Python tests, 40 focused TS tests, TypeScript/mypy/Ruff, semantic smoke and scoped public/private scan pass. An independently built and installed head wheel passes the 15-case closure matrix and four real File/SQLite CLI settlement/recovery tests. The same new regression on the unchanged base reproduces five failures and ten positive/negative controls. The full TS suite passes 4112 tests with 31 PostgreSQL integration skips. Managed exact-scope CQR and premerge canary pass with zero failures or manual holds; both independently installed base/head wheels pass the same four real File/SQLite CLI journeys.
The companion refactor keeps the valuable closure invariant and retires only its duplicate Python owner. Historical formats, backup/receipt recovery, Markdown writers and Host IO remain. PostgreSQL integration, SQLite D2 qualification, installed adoption and a SQLite-default release are outside this bounded repair. Maintainer merge required.