refactor(replan): unify typed history triggers and count logical turns - #4902
Conversation
…turns Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…sent Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…owner Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
评审目标:#4902,exact head 1182f7c6ef448e621d84d359dc56b40cde256975,base c41e09473a9ab883c53b077a73e47ee4eda78816。
动机
现有历史 replan 由几段 Python 扫描分别决定 typed progress、Monitor 重复和定期审查;同一逻辑 Turn 的重试记录可能被重复计数,已接受 ACK 没有一致地截断进度窗口,中性额度记账也可能遮住重复停滞。把这组共享规则收敛为一个决策边界是有价值的完整增量;它不等于整个 Goal authority 的 TS promote。
改动思路
现有 status/quota 路径从持久化 Run 与 Todo 投影取得事实;replan_history_codec.py 仅沿用旧指纹、时间及 Turn ID 解码,向 effect runtime 发送有限 typed facts;replan_history.ts 先按 agent 划分历史,再按 accepted ACK 截断、中性分类过滤、逻辑 Turn 去重,依原优先级产生 progress、Monitor 或 periodic trigger。后续仍由 Python 建立原有 obligation,前端与 Lark 无新字段。Future-due Monitor 的判断复用现有 TS Todo resume planner,未另建 Todo 权威状态。
具体改动
关键代码讲解
replan_history.ts的historyWindow保证 peer ACK 不清除当前 lane,distinctTurns仅对有可信 Turn ID 的有效证据去重;进度、Monitor 和定期审查共用这个窗口。replan_history_codec.py的project_replan_history对旧 Run 做兼容解码并调用work_item.replan_history.project;autonomous_replan_obligation.py/progress_observation.py删除原来的独立选择循环,保留 obligation 形状。effect_runtime_handlers.ts注册纯决策方法;autonomous_replan_ack.py为局部整理;status.py和 status projection 改为引用共享中性分类。三组新测试覆盖 typed 负例、重试和 File/SQLite 实际调用;双语 RFC 检查点和协议文档披露默认行为改变及 promote 边界。
对主干的风险
**[P1,阻塞] loopx/status.py:10 的公开兼容导出未满足现有审计契约。**本 PR 将 REPLAN_HISTORY_NEUTRAL_CLASSIFICATIONS 以 AUTONOMOUS_RUN_HISTORY_NEUTRAL_CLASSIFICATIONS 别名导入公开 facade,但 _PUBLIC_COMPAT_REEXPORTS 没有相应、可审计的 canonical 绑定。仓库既有 tests/architecture/test_control_plane_import_boundaries.py::test_public_facade_import_only_reexports_match_the_audited_allowlist 在 base 通过,在当前 head 失败,唯一多出的绑定就是该别名。请让 facade 导出符合现有审计契约;如果选择去掉公开别名,先核实外部兼容性。修后重跑该架构测试及聚焦 status/quota 路径。
本地验证:新增 TS 测试 21/21 通过,聚焦 Python 行为及真实 File/SQLite consumer 14/14 通过,control-plane typecheck 与 git diff --check 通过;上述必需架构测试 1 项失败。它说明行为测试全绿仍不能证明公开 facade 兼容性。该 PR 没有默认关闭路径,文档已明确这次修正对既有 lane 默认生效,且把 replan 描述为机器执行条件而非建议。未做整个 Goal 的迁移验收;作者声明的 PostgreSQL 适配范围也不是本 slice。
语义与 CI 对齐
这次选择是复用现有 replan / Todo 语义词汇,而非创建新 authority 或 actor 生命周期。status.py 的新增导出违反现行公开 facade import-only allowlist,必须修复并通过同一条架构测试,不能用新行为用例替代。这里只依据上述本地复现作出结论。
我的整体评价
规则归属、重试计数和负例设计总体合理,文件规模与要消除的重复决策相称;没有发现需要扩大成另一个框架的理由。但当前 exact head 的仓库必需测试出现明确的 base→head 回归,故结论为 REQUEST_CHANGES。修好 facade 审计后,再按新 head 复核完整 PR、真实 consumer 和必需测试。此改动属于 control-plane,仍应由 maintainer 合并。
English verdict: REQUEST_CHANGES - At head 1182f7c6ef448e621d84d359dc56b40cde256975, the new public status.py alias breaks the audited import-only facade contract (base test passes, head test fails). The focused TS (21) and Python/File/SQLite (14) tests and typecheck pass; repair the facade binding and rerun the architecture gate before re-review.
The replan refactor replaced the local AUTONOMOUS_RUN_HISTORY_NEUTRAL_CLASSIFICATIONS literal with an aliased import, which the facade audit reads as a new unlisted public import-only binding, so tests/architecture/test_control_plane_import_boundaries.py::test_public_facade_import_only_reexports_match_the_audited_allowlist regressed from base to head. Import the codec name privately and keep the established public name as an identity alias, the same shape the facade already uses for STATUS_NEUTRAL_CLASSIFICATIONS. The vocabulary stays single-sourced in the codec, the public name and its value are unchanged for existing callers, and the audited allowlist needs no new entry. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…policy-0922 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)
评审目标:#4902,exact head 3341c82bc3486e6b706a1458b3bc9b972ec21309,base be29847fffb8324383f1403e273f63c2f5a938bf。上一轮 REQUEST_CHANGES 的唯一阻塞项(loopx/status.py 新增公开别名未进入审计 allowlist)已在本 head 修复,因此转为 APPROVE。
动机
历史触发的 replan 原先由几段 Python 扫描各自决定 typed progress、Monitor 重复与定期审查:同一逻辑 Turn 的重试记录可能被重复计数,已接受 ACK 没有一致地截断进度窗口,中性额度记账也可能遮住重复停滞。把这条共享规则收敛到一个决策边界是完整、可回滚的增量;它不是整个 Goal authority 的 promote,也没有翻转默认采用范围。
改动思路
status/quota 路径继续从持久化 Run 与 Todo 投影取事实;replan_history_codec.py 只保留旧指纹、时间戳与 Turn ID 的解码和单一 RPC,replan_history.ts 按 agent 划分历史、按 accepted ACK 截断、过滤中性分类、对可信用 Turn ID 去重,再依原优先级产生 progress、Monitor 或 periodic trigger,obligation 仍由 Python 按原形状建立。上一轮结论指出的 facade 兼容性契约在本 head 用「私有导入 + 身份别名」满足:公开名字与取值不变,审计 allowlist 不变,词汇表仍单点定义在 codec。
具体改动
关键代码讲解
replan_history.ts的historyWindow保证 peer ACK 不清除当前 lane,distinctTurns只对有可信 Turn ID 的证据去重,progress、Monitor 与 periodic 共用同一窗口;future-due Monitor 复用现有 TS Todo resume planner,未新建 Todo 权威状态。replan_history_codec.py的project_replan_history兼容解码旧 Run 后调用 TSwork_item.replan_history.project;autonomous_replan_obligation.py与progress_observation.py删除被取代的独立选择循环,只保留 obligation 形状与写回要求。loopx/status.py现在以REPLAN_HISTORY_NEUTRAL_CLASSIFICATIONS as _REPLAN_HISTORY_NEUTRAL_CLASSIFICATIONS私有导入,再把既有公开名AUTONOMOUS_RUN_HISTORY_NEUTRAL_CLASSIFICATIONS定义为身份别名,并在注释中写明理由(Refs #4447)。这与同文件既有的STATUS_NEUTRAL_CLASSIFICATIONS = HISTORY_STATUS_NEUTRAL_CLASSIFICATIONS形状一致,因此tests/architecture/test_control_plane_import_boundaries.py的公开 facade import-only allowlist 不需要修改即可继续成立。autonomous_replan_projection.py同样改为引用 codec 的词汇表;双语 RFC 检查点与协议文档披露了默认行为改变与 promote 边界。
修复验证
在本 head 复现并确认上一轮的阻塞项已消失:tests/architecture/test_control_plane_import_boundaries.py 15 passed(base 与 head 现在一致),AUTONOMOUS_RUN_HISTORY_NEUTRAL_CLASSIFICATIONS 仍是同一取值,且 allowlist 未新增名字。全仓 lint 与 origin/main 基线完全一致(loopx tests 同为 9 条,loopx/status.py 同为 5 条既有 F401),说明这次修复没有引入新的 lint 出口。
对主干的风险
未发现新的阻塞项,本轮本地验证:
npm run test:control-plane:2798 tests,2774 passed,0 failed,24 skipped;npm run typecheck:control-plane、配置的python -m mypy(22 source files)与git diff --check通过;- CI 同scope 的
python -m ruff check tests loopx/canary loopx/control_plane loopx/domain_packs loopx/presentation通过; - 聚焦 Python:replan policy/provider/架构边界 29 passed,status/quota/ACK/progress-observation/monitor-scope/writeback 消费者 150 passed;
loopx canary premerge --from-git-diff --goal-id loopx-meta:selected=19,failures=0;- 精确范围 change-quality receipt
cqr_15512ec60776d82f77ab对 head3341c82bc/ basebe29847ff,receipt_valid: true,无 unresolved blocker;两条 advisory 已如实登记:facade 公开集合与 codec 共享同一可变对象(仓库内无任何 mutate 调用,且沿用同文件既有别名形状),以及移除 Python 兜底后畸形 typed facts 会显式失败而非回退(有负例测试固定这一契约)。
仍存在但属既有范围之外的记录:archive capture 依赖角色/类别不完整,本 read-path 证据不解除此迁移 hold;PostgreSQL 存储未被本 slice 改动或验收。PR 正文已披露默认行为变更,没有默认关闭的隐藏路径,也没有新增设置或能力。
我的整体评价
规则归属、重试计数、ACK 截断与负例设计合理,文件规模与被删除的重复决策相称;没有需要扩大成另一个框架的理由,也没有发现为后续投机预留的结构。上一轮的阻塞项已用仓库既有模式最小化修复,最终范围与 base 同步到最新 main 后重跑了架构门、TypeScript 全量、聚焦 Python、lint/typecheck 与 premerge canary。结论为 APPROVE;此改动属于 control-plane,按仓库规则仍由 maintainer 合并。
English verdict: APPROVE - At head 3341c82bc3486e6b706a1458b3bc9b972ec21309, the only prior blocker is repaired: the facade keeps the established public name and value as an identity alias of the codec constant, so the audited import-only allowlist is unchanged and test_control_plane_import_boundaries.py passes (15 passed). Full TS control-plane suite 2774 passed / 0 failed, typecheck, mypy, focused Python (29 + 150 cases), CI-scope ruff with baseline parity, git diff --check, and premerge canary (19 selected, 0 failures) all pass; exact-scope receipt cqr_15512ec60776d82f77ab is valid with no unresolved blocker. This is a control-plane change and remains for the maintainer to merge.
|
Merge decision: authorized self-merge of an owner-authorized control-plane slice 授权与范围:本轮由维护者在本机明确指示「#4902 自修复自合并」,因此该 PR 在本次会话内获得 control-plane 变更的自合并授权。PR 由仓库 owner( 合并对象:head 变更表面
验证
失败与跳过
合并方式GitHub 侧 |
History-triggered replanning used separate Python scans, so retries could prematurely trigger periodic/Monitor review, accepted ACKs could leave typed-progress stalls active, and neutral accounting could hide repetition. This PR makes the existing status/quota callers share one TypeScript history policy and removes the replaced Python decisions.
Refs #4574. The TS and shared-authority RFC ledgers record this T3 decision-family closure and the conditional 5–8 remaining default-adoption packages. This does not flip provider defaults or qualify whole-Goal promotion. Frontend/Lark keep consuming the existing obligation contract; there is no new setting or capability.
Validation: 164 Python cases, 34 TypeScript cases, control-plane typecheck, configured mypy, focused ruff, docs governance and public-boundary checks. The status facade retains five baseline-only F401 diagnostics with no new lint findings. A read-only real-source rehearsal used 345 active Todos / 600 history rows / five lanes: all lane results matched baseline, and isolated File/SQLite readback plus quota CLI passed without a display or source mutation. Full archive capture independently remains blocked by an incomplete archived dependency role/class; this read-path evidence does not discharge that migration hold. PostgreSQL storage was not changed or qualified by this slice.
The first semantic-vocabulary check reported 44/43 same-basename Python/TS pairs. The historical compatibility module is explicitly named
replan_history_codec.py: it owns encoding and the single RPC, with no Python trigger fallback. The unchanged check now reports 43/43; no budget, scan scope or fixture population was increased/reduced. Python product code shrinks by 253 lines overall. Updated on mainc41e09473, including #4886 and #4887. Scope: 17 files, +1005 / -445 lines.Final qualification: standard premerge canary passed (19 selected checks, zero failures); exact-head change-quality receipt
cqr_5d9f098e704637b5aff1is valid for head1182f7c6e/ basec41e09473. Scope fingerprint:5d9f098e704637b5aff1cbad31ba361686faacb1928693f9220a940478b1a201. No unresolved quality blockers.Maintainer merge required for this control-plane change.