Repository navigation
Description
在 #5273(PR #5668)核对 HookContext.input 契约表时发现,PD #10 单独记录。观察类(finding):今天没有用户会撞上,它是一条永不命中的兜底分支。
事实(对 origin/main 核实)
packages/triggers/trigger-record-change/src/record-change-trigger.ts:295-300:
const inputDoc =
input.data && typeof input.data === 'object'
? input.data
: input.doc && typeof input.doc === 'object'
? input.doc
: undefined;input.doc 这条分支在任何引擎路径上都不可达:
- 全仓
HookContext生产点恰好 5 处,全在packages/objectql/src/engine.ts,加上 [17.x] 批量写按行语义实现:hook 按行触发 + record-change trigger 按行绑定 previous/record(#4800/#4862 拍板 A) #5038 的buildPerRowAfterContexts。写事件构造的键是data(insert4879、update5243),没有一处写doc。 beforeInsert/beforeUpdate上input.data恒为对象,所以三元第一支恒真;beforeDelete/afterDelete根本不带data也不带doc,落到previous兜底。两种情况都轮不到input.doc。
该文件自己的注释其实已经写明了真值:
objectql lifecycle hooks carry the written row under
input.data(insert / update payload);idis on update. (dockept only as a defensive alias.)
packages/spec 的契约表当时确实把 insert 写成 { doc: Record, options } —— 那是假的,已由 PR #5668 改成 { data, options } 并加 pin。所以这条 alias 现在连「文档这么说」的依据也没有了。
分级说明
标 finding:纯休眠代码,行为上零影响。但它是 AGENTS.md PD #12 点名的那类消费端 ?? 兜底——「a tolerant fallback fossilizes the wrong convention into a second de-facto contract」——而且是为一个从来不存在的生产者留的。严重程度请分诊轮判。
建议
删掉 input.doc 分支与类型里的 doc?: 声明,只读 input.data;真值已被 packages/objectql/src/hook-input-shape-contract.test.ts(PR #5668 新增,断言 insert 上下文有 data、无 doc)钉住。
顺带:packages/spec/src/data/hook.test.ts:422 与 packages/services/service-storage/src/attachment-lifecycle.test.ts:159 的 fixture 也拼的是 input: { doc: … }。两处都只喂开放形状的 z.record,不会因此变红,但它们是照旧契约表写的,清理时应一并按引擎真值重拼(fixture 三分法里的「re-spell」)。
Activity
os-zhuang commentedon Aug 5, 2026
发现分诊(#4949 纪律):持有,保留
finding,补domain:services(落点packages/triggers/trigger-record-change,triggers 族归 services 车道——域表)。一行理由:纯休眠代码零行为影响(
input.doc分支在任何引擎路径上不可达,已核作者对 origin/main 的生产点盘点),但 PD #12 的化石化论据成立,值得清。重启条件:PR #5668(#5273)合入 main 后晋级——届时hook-input-shape-contract.test.ts的 pin 在 main 上,删 alias + 两处 fixture re-spell 成为纯机械活;在其之前动手会对着还在飞的真值源。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-zhuang commentedon Aug 6, 2026
发现分诊(#4949 纪律):重启条件已触发,晋级 —— 摘
finding换pm:queue,domain:services已在。依据:前次持有评论的重启条件 = PR #5668(#5273)合入 main,已于 2026-08-06 落地(
28ce594),pinpackages/objectql/src/hook-input-shape-contract.test.ts已在 origin/main;record-change-trigger.ts:298-299的input.docalias 仍在,该包自 #5635 后无相关改动 —— 按预记计划,删 alias + fixture re-spell(含record-change-trigger.test.ts:303那个「falls back to input.doc」用例的整条替换)现在是纯机械活。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
hotlong commentedon Aug 6, 2026
认领:PM 循环第 1 轮(services 车道)
会话:
session_015a5qkLzpGXhLL2F5gvJ7dD分支:
claude/issue-5671-drop-input-doc-aliasWorktree:
objectstack-issue-5671域:
domain:services文件面:
packages/triggers/trigger-record-change/src/record-change-trigger.ts+ 同包测试(含record-change-trigger.test.ts:303「falls back to input.doc」用例整条替换)+packages/services/service-storage/src/attachment-lifecycle.test.ts(fixture re-spell);⛔ 不触packages/spec——hook.test.ts:422的 fixture 半边已转席 #5886(spec 座位)串行约束已清:今日 2a607d2(#5806)迁移了该包 7 条集成测试到 sqlite
:memory:,基于合并后 origin/mainGenerated by Claude Code
hotlong commentedon Aug 6, 2026
验收:ACCEPT → PR #5908(CI 23/23 绿,随后转 ready 入队,本座位跟到 MERGED)。
id?: unknown保留判断正确 —— 引擎在 update 上确实绑input.id,删的是假键,不是顺手清扫。data在读取链首位,正向用例天然不承重;承重的是负向用例(只喂doc、断言不播种),dev 预判并实测了这一点(临时复活 alias → 恰好 1 红且正是负向条)。origin/main上input.doc引用面与申报一致,trigger-record-change 内仅 :295-299 一处代码读点 + :303 测试。doc/previousDoc防御性 alias 读也没有生产者(#5671 全仓 grep 的剩余部分) #5906(attachment-lifecycle.ts:174 / primary-bu-projection.ts:80 / body-runner.ts:308),留分诊定级;hook-input-shape-contract.test.ts:23头注释合并后过时的一句,已追记到 同源:另外三处 hook context 上的doc/previousDoc防御性 alias 读也没有生产者(#5671 全仓 grep 的剩余部分) #5906(该文件属 engine-core 车道,本 PR 按派发口径未动它,处置正确)。input: { doc: … }—— 按引擎真值 re-spell(#5671 摘除死 alias 的 spec 半边) #5886(spec fixture re-spell)不受影响 —— 必答项已核。经办:services 座位,会话
session_015a5qkLzpGXhLL2F5gvJ7dD(第 1 轮)。Generated by Claude Code