refactor(delivery): unify history-to-obligation rules in TypeScript - #4134
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
…undary Signed-off-by: huangruiteng <huangrt01@163.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Reviewed exact head: 9e6dcd79baae333188b4f015e22f62c92f40b013
动机
这个 PR 处理 delivery history 的重复规则所有权:旧代码在 Python 的 delivery_signals.py、outcome_followthrough.py、delivery_outcome.py 和 status wrappers 中分别推断 outcome、turn kind、batch scale、streak 与 follow-through。它还修复一个真实的边界错误——无效/缺失的两个 identifier 可能都 normalize 为 None,进而被误当成相等,错误解除 blocker follow-through。
改动思路
方案将完整的 history-to-obligation read policy 收敛进 delivery_history.ts,Python delivery_history.py 只压缩 typed facts、保留超长/空白 identifier 的 invalidity witness,并批量调用 runtime。status 与 quota 共享同一个 projection;narrative/evidence body 不参与决策。TypeScript 负责 exact outcome/kind/scale、prefix streak 和 follow-through,仍不获得 run write、settlement、quota spend 或 Todo lifecycle 权限。
具体改动
- 新增 typed
projectDeliveryHistory并删除delivery_signals.py、outcome_followthrough.py以及 status 中的重复 wrappers。 - status/handoff 一次选择有界 history batch,quota 的 latest-run consumer 复用同一 owner;unsupported explicit kind 保持 unknown,unknown 会中断 streak,primary outcome 不被显式 obligation 覆盖。
- compact adapter 不发送 classification、recommended action 或 evidence body;超长值加不可 trim 的 invalid suffix,空白 binding 仍保留“存在”事实,避免截断或
None == None伪装成合法 receipt。 - Python writer-side blocker settlement 增加非空 normalized work-item guard;该 intentional behavior change 已在 PR、RFC 和负向用例中披露。
- 27 个文件共 +643/-475;production +251/-289(净减少 38 行)。范围与已有 work_items typed boundary 对齐,没有新 provider、持久化状态、CLI 或 activation surface。
对主干的风险
核心语义验证是扎实的:我在 exact head 上跑了 80 个 Python transport/semantics/CLI tests、7 个 TypeScript tests,以及 delivery-signals、status Markdown、outcome/kind enum、follow-through 和 handoff 等公开 smoke,全部通过;remote required checks 也为成功或预期 skip。负向路径覆盖 missing/mismatched/oversized binding、非法 evidence、unknown enum、literal-true obligation、runtime wire fault 和 narrative mutation。
但仓库要求的 hot-path interface-budget gate 仍然失败:dashboard_status_json 实测为 18,387 字符,合同上限是 18,215。我在 PR base 6f6255ee5624a99c70bc5330102212f793153d1c 和 exact head 都复现了同一数值,因此这不是该 PR 新增的 172 字符,也不能伪造成“本 PR 引入的回归”;它是一个继承但未解除的 merge hold。这个 PR 正在改 status/quota 热路径,不能用其余语义测试全绿替代该 gate。当前 origin/main 也没有相应 budget/payload 修复,单纯 rebase 尚不足以消除它。
最小修复是把 cold/history 字段移出 hot dashboard payload 或压缩现有 projection,使既有 18,215 上限真实通过;如果确需修改 budget,则应作为独立、owner-reviewed contract 决策给出消费端证据,不能只为了让当前 diff 变绿。修复后请重跑 hot-path smoke 与受影响的 status/quota tests。
我的整体评价
架构方向、typed state、domain-neutral obligation、guidance/required flag 区分和 invalid-ID 修复本身都合理;我没有发现第二套 policy owner 或未披露的默认行为变化。future-facing pass 也做到了删除旧规则,而不是加兼容框架。
不过 exact head 仍有一个可复现的 P1 premerge blocker,所以当前结论是 request changes。由于该 PR 属于当前 GitHub 身份,GitHub 不允许 formal self-review,本次以 COMMENTED request-changes conclusion 发布。这个结论只要求解除现有 hot-path hold,不把 baseline 既有超限错误归因给本 PR。
English verdict: REQUEST_CHANGES for exact head 9e6dcd79baae333188b4f015e22f62c92f40b013. The delivery-history consolidation and malformed-binding fix passed 80 Python tests, 7 TypeScript tests, six public smokes, and remote CI, but the required hot-path budget still fails at 18,387/18,215 characters on both base and head. Resolve that inherited same-surface merge hold without weakening the contract merely to fit this PR, then rerun the exact-head status/quota validation.
Summary
work_items/delivery_history.ts: typed outcome, turn kind, scale, consecutive streaks and follow-through. Status sends one selected history batch; quota uses the same owner for its latest run. Narrative and evidence bodies never enter the decision request.delivery_signals.py,outcome_followthrough.py, Python turn-kind inference, stale constants and status wrappers. Production code is +251/-289 (net -38); the complete PR is +643/-475 including characterization, transport regressions and bilingual RFC updates.Issue Or Task
Maintainer-requested next cohesive stage of the TypeScript/control-plane and shared Goal Authority RFCs. Independent of open #4122 (resume planning), #4121 (SQLite provider) and #4101 (projection receipt retention). Rebased onto
6f6255ee5, including #3975, which does not overlap this slice.Validation
9e6dcd79baae333188b4f015e22f62c92f40b013unless noted below.hot-path-interface-budget-smoke.pyreportsdashboard_status_jsonat 18,387 characters against 18,215. Baseline and head reproduce the same size under identical path conditions; no budget was loosened. This remains an explicit merge hold.Coverage and gaps: real CLI/store/read-policy paths and malformed-input counterexamples are covered, not just transport mocks. One runtime request is added per selected batch (and one for quota's latest-run consumer); this is not a speedup claim. A warm local 3-row batch probe measured about 7 ms median over 100 samples, not an end-to-end latency guarantee. Hosted CI and the inherited payload-budget hold remain to be resolved/reviewed before merge.
Type of Change / Area
Control-plane read-policy refactor plus the explicitly disclosed invalid-ID bug fix; tests and documentation. Core control-plane hardening. Base branch:
main.Shared-authority RFC fixture impact
Boundary Checklist