Skip to content

trigger-record-changeinput.doc 防御性 alias 读的是一个没有生产者的键(引擎只建 input.data) #5671

Description

@os-zhuang

#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 这条分支在任何引擎路径上都不可达:

该文件自己的注释其实已经写明了真值:

objectql lifecycle hooks carry the written row under input.data (insert / update payload); id is on update. (doc kept 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:422packages/services/service-storage/src/attachment-lifecycle.test.ts:159 的 fixture 也拼的是 input: { doc: … }。两处都只喂开放形状的 z.record,不会因此变红,但它们是照旧契约表写的,清理时应一并按引擎真值重拼(fixture 三分法里的「re-spell」)。

关联

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions