refactor(trigger-record-change): 摘掉 input.doc 这条没有生产者的防御性 alias 读 (#5671) - #5908
Merged
Conversation
…5671) `buildContext()` 里的 `inputDoc` 三元把 `input.data` 之后又兜了一条 `input.doc`。该分支在任何引擎路径上都不可达:ObjectQL 的写事件上下文一律把 载荷拼在 `data` 上(insert / update),before/afterDelete 两者都不带、直接落 到 `previous`。真值由 objectql 的 `hook-input-shape-contract.test.ts` 钉住 (「insert carries `data` — never `doc`」,#5273 / PR #5668)。 该 alias 当初留下的唯一依据是旧的 `HookContext.input` 契约表把 insert 写成 `{ doc, options }` —— 那张表本身是错的,已由 PR #5668 改成 `{ data, options }`。 依据消失后按 PD #12 删掉,而不是继续养成第二套事实契约。 行为零变化(该分支不可达)。同时: - `record-change-trigger.test.ts` 的 `hookCtx` fixture 原本拼的是 `doc`,正是 它让这条死分支在测试里保持「活着」;按引擎真值 re-spell 成 `data`。 - 原「falls back to input.doc」用例整条替换为一对承重 pin:正向钉 `input.data` 播种 record;反向钉「只拼 `doc` 的上下文不播种」—— 后者才是 承重的那条(`data` 在读取链首位,alias 限支复活时正向用例仍绿)。 - `attachment-lifecycle.test.ts` 的 insert fixture 同样按引擎真值 re-spell。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015a5qkLzpGXhLL2F5gvJ7dD
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Aug 6, 2026
hotlong
marked this pull request as ready for review
August 6, 2026 11:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5671
背景
record-change-trigger.ts的buildContext()在input.data之后又兜了一条input.doc。这条分支在任何引擎路径上都不可达:ObjectQL 的写事件上下文一律把载荷拼在data上(insert / update),before/afterDelete两者都不带、直接落到previous。该 alias 当初留下的唯一依据,是旧的
HookContext.input契约表把 insert 写成{ doc, options }—— 那张表本身是错的,已由 PR #5668(#5273)改成{ data, options }并加了 pin。依据消失后,按 PD #12 删掉,而不是继续养一套第二事实契约。行为零变化 —— 该分支不可达,真值 pin 在
packages/objectql/src/hook-input-shape-contract.test.ts(「insert carriesdata— neverdoc」)。本 PR 只引用该 pin,未改动它。改动
packages/triggers/trigger-record-change/src/record-change-trigger.ts—— 删掉input.doc三元限支与类型里的doc?:声明,只读input.data;局部变量inputDoc随之更名inputData(纯局部,不导出),注释改写为指向引擎真值与那条 pin。id?: unknown:它虽然在本函数内未被读,但是真的(update 事件上引擎确实绑input.id)。删的是那个假的键,不是顺手清扫。record-change-trigger.test.ts——hookCtxfixture 原本拼的就是doc,正是它让这条死分支在测试里保持「活着」(validateOrgAxisRedLines 读的 sharing-rule 键是 spec 拒收的:ADR-0105 D6 ① 在 criteria 路径上从不触发 #4984 那一族:fixture 照着错契约表写,于是死逻辑一直绿)。按引擎真值 re-spell 成data,并把原「falls back to input.doc」用例整条替换为一对承重 pin。packages/services/service-storage/src/attachment-lifecycle.test.ts—— insert fixture 同样按引擎真值 re-spell(fixture 三分法里的 re-spell 档)。反向验证 —— 方向先判,再测
这条链的规范键
data排在读取链首位,所以「把删掉的限支放回去、看新用例转红」对正向用例并不成立:正向用例喂data,alias 复活与否它都绿。承重的是反向那条 —— 喂一个只拼doc的上下文,断言它不播种 record。把
doc限支临时放回源码后实测:正好 1 红,且正是反向那条;正向用例如预期保持绿。这一对是刻意配的,注释里也写明了哪条承重。恢复后全绿。
验证
按
lint.yml/ci.yml逐条枚举跑了 diff 可能影响的门,全程持容器级验证锁 +--max-old-space-size=4096+--filter范围化:pnpm --filter @objectstack/trigger-record-change typecheckpnpm --filter @objectstack/trigger-record-change testpnpm --filter @objectstack/service-storage testeslint --no-inline-config(三个改动文件)pnpm check:nul-bytespnpm check:engine-double-contractpnpm check:adr-anchorspnpm check:published-filespnpm check:type-check-coverage(
@objectstack/service-storage无typecheckscript —— 已在check-type-check-coverage.mjs的台账里,该门 PASS。)两个必答项
1. 全仓
doc读者是否归零?——「hook input 形状」这一面归零,但另有三处同族,已另立单 #5906。改动后
input.doc的读者全仓只剩下注释文本,零代码读点在trigger-record-change。但同一次 grep 翻出另外三处,都不在本 issue 的派发作业面内,按 PD #10 另立 #5906(unassigned,finding),未在本 PR 修:packages/services/service-storage/src/attachment-lifecycle.ts:174——ctx?.result ?? ctx?.input?.doc ?? ctx?.input?.data,注意次序与本 PR 相反,doc在data前面;因doc恒 undefined 而每次穿到data,纯死码。packages/plugins/plugin-sharing/src/primary-bu-projection.ts:80——(ctx?.input?.data ?? ctx?.input?.doc)?.user_id,doc限支不可达。packages/runtime/src/sandbox/body-runner.ts:308—— 读的是顶层ctx.doc/ctx.previousDoc,不是ctx.input.doc,严格说不属于本次 grep 的目标键;但HookContext只声明input/result/previous,这两个键同样无生产者,同族,一并列入 同源:另外三处 hook context 上的doc/previousDoc防御性 alias 读也没有生产者(#5671 全仓 grep 的剩余部分) #5906 便于一次判。另需提示:
hook-input-shape-contract.test.ts:23的文件头注释写着「trigger-record-changestill carries a defensiveinput.docalias read for that reason — filed separately, not fixed here」,本 PR 合入后这句即过时。派发口径明确 ⛔ 不改该 pin 文件,故此处未动,留给该文件的座位顺手修一句。2. 对 #5886(spec fixture re-spell)的影响:完全无影响,既不变简单也不变难。
本 PR 的 diff 里没有任何
packages/spec文件(已核:git status中 spec 文件数 = 0)。#5886 的作业面是packages/spec/src/data/hook.test.ts:422/474/490那一组 fixture,喂的是开放形状的z.record,与本包的消费端读取逻辑无耦合 —— 两边既不共享 fixture,也不互为前提。#5886 该怎么 re-spell 仍怎么 re-spell。范围
⛔ 未触
packages/spec任何文件;⛔ 未改hook-input-shape-contract.test.ts;⛔ 未触content/docs/releases/。Generated by Claude Code