refactor(hooks): 摘掉最后三处 hook 上下文的 doc / previousDoc 防御性 alias 读 (#5906) - #6269
Conversation
…5906) #5671(PR #5908)清掉 trigger-record-change 那条 `input.doc` alias 后,全仓 grep 剩下的三处同族兜底一并收官。三条限支都在为一个从不存在的生产者兜底,任何引擎路径 都不可达,行为零变化: - `service-storage` 附件生命周期:`ctx.result ?? ctx.input.doc ?? ctx.input.data` —— 注意 `doc` 排在 `data` 前面,但恒为 undefined,`??` 每次都穿到 `data`。 - `plugin-sharing` primary-BU 投影:`(ctx.input.data ?? ctx.input.doc).user_id`。 - `runtime` hook 沙箱:`engineCtx.input ?? engineCtx.doc` 与 `engineCtx.previous ?? engineCtx.previousDoc` —— 读的是顶层键,同一族上一层。 真值:ObjectQL 的写事件上下文一律把载荷拼在 `data` 上,由 objectql 的 `hook-input-shape-contract.test.ts` 钉住(「insert carries `data` — never `doc`」, #5273 / PR #5668);顶层那对同理 —— `HookContextSchema` 只声明 `input` / `result` / `previous`,`engine.ts` 作为 HookContext 的唯一生产者两个都不构造。 依据消失后按 PD #12 删掉,而不是继续养成第二套事实契约。 承重 pin(各自「正向 + 反向」一对,反向那条才承重 —— 真值键都在读取链首位, alias 限支复活时正向用例仍绿): - `attachment-lifecycle.test.ts`:既有 insert fixture 同时给了 `result`,链首命中, 对本次清理不承重;另配「无 `result` 只有 `input.data`」的正向用例,以及 「只拼 `input.doc`」的反向用例(限支复活即红)。 - `body-runner.test.ts`:新增一对,反向用例喂一个只拼 `doc`/`previousDoc` 的上下文, 断言沙箱看到空 input、无 previous。 另:`hook-input-shape-contract.test.ts` 文件头那句「trigger-record-change still carries a defensive `input.doc` alias read — filed separately, not fixed here」在 #5908 合入后已成假话,改写为收官表述(仅改注释,不动该包任何生产代码)。 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
|
📓 Docs Drift CheckThis PR changes 3 package(s): 27 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 31181660008 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
队列踢出分诊(services 座位 PM,按 triage 清单逐条):
(背景读数:过去 24h 队列 77 次失败构建——高扰动日,定时器竞态类用例在全量负载下偶发是常见形状。) Generated by Claude Code |
|
Queue steward — yielding (队列管家让行). The services-lane PM triaged this kick-out at 13:26:56Z, inside my 30-minute yield window, so the disposition stays with the lane. I am taking no action on this PR: no re-queue, no rerun, no label or state change. One reading I can add, having pulled the failing job's log rather than the truncated extract in the bot comment above (SKILL Operational note 7 — judge from the full archive, never the tail):
That corroborates the lane's point 1 on harder evidence: the failure is in Against the #5810 signature ledger this is a new signature — it matches no row: not the Generated by Claude Code |
Fixes #5906
#5671(PR #5908)清掉
trigger-record-change那条input.docalias 之后,#5671 全仓 grep 剩下的三处同族兜底在这里一并收官,外加一句已成假话的注释改写。行为零变化:三条限支都在为一个从不存在的生产者兜底,任何引擎路径都不可达。前提核对(对
origin/main,四处逐字命中)packages/services/service-storage/src/attachment-lifecycle.ts:174ctx?.result ?? ctx?.input?.doc ?? ctx?.input?.datapackages/plugins/plugin-sharing/src/primary-bu-projection.ts:80(ctx?.input?.data ?? ctx?.input?.doc)?.user_idpackages/runtime/src/sandbox/body-runner.ts:308engineCtx?.input ?? engineCtx?.doc/engineCtx?.previous ?? engineCtx?.previousDocpackages/objectql/src/hook-input-shape-contract.test.ts:23input.docalias read … filed separately, not fixed here」三条真值证据:
input.doc无生产者:hook-input-shape-contract.test.ts(PR docs(spec): HookContext.input 契约表改成引擎真正构造的形状 (#5273) #5668)在真引擎上钉住「insert carriesdata— neverdoc」;HookContextSchema.input的契约表逐事件写明载荷一律拼在data上。doc/previousDoc无生产者:HookContextSchema只声明id/object/event/input/result/previous/session/provenance/transaction/ql/api/user—— 两个键都不在其中;engine.ts作为 HookContext 的唯一生产者也都不构造。全仓 greppreviousDoc只有 body-runner 这一条读,零处写。buildSandboxContext的唯一调用点是同文件hookBodyRunnerFactory,喂进来的就是引擎原生 ctx。340a34f75(PR refactor(trigger-record-change): 摘掉input.doc这条没有生产者的防御性 alias 读 (#5671) #5908)已合入main,那条 alias 早被摘掉。改动
1/2/3 各自只保留引擎真值键,
??链其余部分不重排;三处都留了注释说明依据(引用 #5273 / #5671 与本单),按 PD #12 而不是继续养成第二套事实契约。第 4 处只改注释一句,改写为收官表述——不动 objectql 任何生产代码。承重 pin(正向 + 反向各一对,反向那条才承重)
真值键在两条读取链里都排首位,所以正向用例在 alias 限支复活时仍然绿——反向用例才是承重的那条。这跟 #5908 建立的判法一致。
attachment-lifecycle.test.ts:159的既有 insert fixture 同时给了result,??链首位就命中,对本次清理不承重。因此另配一对:正向「无result、只有input.data」证明现在只读真值键;反向「只拼input.doc」断言 tombstone 不动。body-runner.test.ts新增一对,反向用例喂一个只拼doc/previousDoc的上下文,断言沙箱看到空 input、无 previous。plugin-sharing的collectUserIds/bindPrimaryBuHooks在仓内没有任何既有测试覆盖(全包 grep 确认),按派发口径此处不新建测试文件、在此说明:该处data本就在链首,删的是其后恒 undefined 的限支,行为等价。反向验证(方向事前预判为 RED,实测一致)
把两条限支放回去,只有两条反向用例转红,正向用例照绿——正是它们承重的原因:
复原后两文件各自全绿(25 / 26)。
验证
changeset
按仓内同类先例(#5908 的
.changeset/olive-pugs-repeat.md,同样是零行为变化的死限支清理)出 patch changeset,覆盖三个生产包,正文写明 dead alias branch removal / zero behavior change。因此本 PR 不需要skip-changeset。Generated by Claude Code