Repository navigation
trigger-record-change 的 input.doc 防御性 alias 读的是一个没有生产者的键(引擎只建 input.data) #5671
Description
Activity
发现分诊(#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
发现分诊(#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
认领:PM 循环第 1 轮(services 车道)
会话:session_015a5qkLzpGXhLL2F5gvJ7dD
分支:claude/issue-5671-drop-input-doc-alias
Worktree: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/main
Generated by Claude Code
验收:ACCEPT → PR #5908(CI 23/23 绿,随后转 ready 入队,本座位跟到 MERGED)。
- 死分支摘除 + 类型收窄到位;
id?: unknown保留判断正确 —— 引擎在 update 上确实绑input.id,删的是假键,不是顺手清扫。 - 反向验证的方向判断正确:规范键
data在读取链首位,正向用例天然不承重;承重的是负向用例(只喂doc、断言不播种),dev 预判并实测了这一点(临时复活 alias → 恰好 1 红且正是负向条)。 - 删除类复核(PM 独立跑):
origin/main上input.doc引用面与申报一致,trigger-record-change 内仅 :295-299 一处代码读点 + :303 测试。 - 同族衍生三处已立 同源:另外三处 hook context 上的
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 按派发口径未动它,处置正确)。 - spec 半边照约零触碰,spec: hook.test.ts 的 insert fixture 仍按旧契约表拼
input: { doc: … }—— 按引擎真值 re-spell(#5671 摘除死 alias 的 spec 半边) #5886(spec fixture re-spell)不受影响 —— 必答项已核。
经办:services 座位,会话
session_015a5qkLzpGXhLL2F5gvJ7dD(第 1 轮)。
Generated by Claude Code
- 死分支摘除 + 类型收窄到位;
在 #5273(PR #5668)核对
HookContext.input契约表时发现,PD #10 单独记录。观察类(finding):今天没有用户会撞上,它是一条永不命中的兜底分支。事实(对
origin/main核实)packages/triggers/trigger-record-change/src/record-change-trigger.ts:295-300: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。该文件自己的注释其实已经写明了真值:
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」)。关联
HookContext.input的契约注释声明批量写携带input.ast,引擎从不设置它(AST 只在 opCtx 上);同一张表也未描述 #5038 后 after 事件的按行形状 #5273 / PR docs(spec): HookContext.input 契约表改成引擎真正构造的形状 (#5273) #5668ctx.input.ast」——与 #5273 同一句假话,只是另外三个面 #5670(同源的技能/文档面)