Skip to content

fix(objectql): hook 层用 Logger 契约形状写诊断,不再自带方言 (#5637) - #5780

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5637-hook-logger-contract-shape
Aug 6, 2026
Merged

fix(objectql): hook 层用 Logger 契约形状写诊断,不再自带方言 (#5637)#5780
os-zhuang merged 2 commits into
mainfrom
claude/issue-5637-hook-logger-contract-shape

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5637

按分诊/PM 一致裁决的方向 1执行:packages/objectql 的 hook 层不再自带 logger 方言,改用 @objectstack/spec/contracts 的契约形状(PD #12)。⛔ 未改动 spec 契约(方向 2 未采纳)。

改了什么

1. 两处本地 logger 形状 → 契约的 Pick

hook-wrappers.ts / hook-binder.ts 各自手写的四方法形状删除,改为一个从契约派生的类型别名:

import type { Logger } from '@objectstack/spec/contracts';

export type HookDiagnosticsLogger = Pick< Logger, 'debug' | 'info' | 'warn' | 'error' >;

Pick 而不是整个 Logger,是因为这一层只调这四个级别(「最小可用面」);完整的 Logger 无改动即满足它,而生产上注入的两个 logger(ctx.logger / engine.logger)正是完整契约实现。hook-binder 直接复用 hook-wrappers 导出的同一个类型 —— binder 拿到的 logger 原样转交 wrapDeclarativeHook,两者的形状必须同源,不能各写各的。

2. 四个调用点改为契约参数序 error(msg, undefined, { … })

issue 正文点名三个,实际是四个 —— hook-wrappers.ts 的 condition 编译失败诊断是第四个,同缺陷同文件;改类型之后 tsc 会直接把它顶红(见下方反向验证),所以它不是扩大范围,而是这次修复的必然一环:

文件 诊断
hook-wrappers.ts [hook] condition formula failed to compile; …(issue 未列)
hook-wrappers.ts [hook] handler failed (onError=log; suppressing)
hook-wrappers.ts [hook] async handler error (fire-and-forget)
hook-binder.ts [hook-binder] failed to bind hook

第二参一律留 undefined:四个点手头的值分别是 CelFault({ kind, message },不是 Error)和 catch 绑定(类型 unknown / any,hook handler 可以 throw 任何东西),没有一个在静态上是真正的 Error。它们的 message 本来就在 meta 里,原样保留,所以这次改动不增删任何诊断字段。把 catch 值提升进 Error 位会把每个宿主渲染出来的 error 从字符串换成 { message, stack } 对象 —— 那是另一个决定,不搭这趟车。

3. debug / info / warn 与契约签名完全一致((message, meta?)),未改动。

兼容性

ObjectLogger 是今天所有宿主实际拿到的实现,自 #5575 起三种形状都认((msg, Error) / (msg, meta) / (msg, undefined, meta)),所以第二参 undefined 渲染出的记录与改动前逐字段相同 —— 对现有部署零行为变化。真正变的是契约的另外两个实现(@objectstack/observabilityConsoleLogger / JsonLogger):它们此前会把 meta 整块吞掉(落进 error 位 → error.message / error.stackundefined,meta 本身 undefined),现在如实记录。

导出类型 BindHooksOptions / WrapDeclarativeOptionslogger 字段收窄了,但全仓库(含 examples/apps)除 objectql 自身外没有第二个 bindHooksToEngine / wrapDeclarativeHook 调用点,包内既有测试传的 { debug, info, warn, error } 字面量也仍然满足新类型 —— 全量 typecheck + 全量测试可证。

测试

新增 packages/objectql/src/hook-logger-contract-shape.test.ts(5 例)。关键在于用一个忠于契约的 logger stub(三个参数分开记录、不做形状分派)去审这些调用点 —— 正是 ObjectLogger 的那份宽容让旧缺陷看不见,所以复刻宽容的 stub 什么也测不出来。

  • 4 例覆盖四个调用点:断言 error 位为空、meta 完整落在第三参(hook / object / event / error 等字段逐一 toMatchObject)。
  • 第 5 例是兼容性钉子:真实 ObjectLogger(format: 'json',捕获 stderr)必须照常输出全部字段,证明「第二参 undefined 无害」。
✓ onError: 'log' — the suppressed failure keeps its hook/object/event/error meta
✓ fire-and-forget — the async after-hook failure keeps its meta
✓ an uncompilable condition keeps the condition source in its meta
✓ a throwing registerHook is reported with the hook name and cause in meta
✓ ObjectLogger — emits the hook diagnostic fields on a contract-shaped call
Test Files 1 passed (1)  Tests 5 passed (5)

合并 origin/main(带入 #5760 / #5753 两个同包改动)后重跑全量:

pnpm --filter @objectstack/objectql typecheck   → tsc --noEmit,0 error
pnpm --filter @objectstack/objectql test        → Test Files 124 passed (124) / Tests 2042 passed (2042)

门禁(合并后重跑,全绿):check:nul-bytes(5659 files,无裸控制字节)、check:query-options-erasure(ratchet 84 sites,none new)、check:engine-double-contract(27 pinned / 65 debt / 1 exempt)、check:durability-log-levelcheck:startup-registry-verdict

反向验证(方向先判后跑)

预判三条,跑完三条全中:

  1. 恢复方言参数序 → 4 个契约 stub 用例转红。 实测:AssertionError: expected { hook: 'audit_task', …(3) } to be undefined 等 4 条 —— meta 对象落进了 error 位,metaundefined,正是忠于契约的 logger 会丢字段的那一刻。
  2. 第 5 例(真实 ObjectLogger)保持绿。 这是预期的,不是漏网:ObjectLogger 按形状分派,两种参数序都认,所以它天然不是判别器,只是兼容性钉子。照实记下,不假装它会翻转。
  3. tsc 也一起转红 —— 这是修复新增的类型级防线,改动前并不存在:
src/hook-binder.ts(251,9): error TS2353: Object literal may only specify known properties, and 'hook' does not exist in type 'Error'.
src/hook-wrappers.ts(304,11): error TS2353: …
src/hook-wrappers.ts(376,11): error TS2353: …
src/hook-wrappers.ts(430,15): error TS2353: …

第 3 条正是这单最实质的收益:方言之所以能存活,就是因为契约类型在结构上满足本地形状(参数少的一方可赋值,any 双向兼容),tsc 一句话都不说。换成契约类型之后,同一个错误再写一次会在编译期被顶回来。

范围

packages/objectql/src/hook-wrappers.tspackages/objectql/src/hook-binder.ts + 同包新增测试 + changeset(patch)。未碰 engine.ts / integrity / lifecycle / spec / observability / core,未碰 content/docs/releases/


Generated by Claude Code

claude added 2 commits August 6, 2026 04:33
…al dialect (#5637)

The `Logger` contract declares `error(message, error?: Error, meta?)` — the
`Error` slot is second, meta third. `hook-binder.ts` and `hook-wrappers.ts`
each declared their own four-method logger shape spelling `error` as
`(msg, meta?)`, and their call sites put the diagnostic in the `Error` slot
accordingly.

tsc could not see it (the contract type satisfies the local shape
structurally) and `ObjectLogger` hid it at runtime (it dispatches the second
argument by shape). The contract's other implementations —
`ConsoleLogger`/`JsonLogger` in `@objectstack/observability` — follow the
contract literally, so the meta bag landed in the `error` slot and the whole
diagnostic disappeared.

- Both option interfaces now take `HookDiagnosticsLogger =
  Pick<Logger, 'debug'|'info'|'warn'|'error'>` from `@objectstack/spec/contracts`
  (PD #12: no consumer-side dialect).
- All four `error(...)` call sites pass meta in the third parameter. The values
  in hand are a `CelFault` or a `catch` binding of type `unknown`, none of them
  statically an `Error`, so the `Error` slot stays `undefined`.
- `debug`/`info`/`warn` already matched the contract — unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V7WetGmnfoXNn8cLieKKmx
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 6, 2026 5:10am

Request Review

@github-actions github-actions Bot added the size/m label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/objectql.

13 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/objectql)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/query-syntax.mdx (via packages/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 6, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 6, 2026 05:51
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 290d944 Aug 6, 2026
24 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5637-hook-logger-contract-shape branch August 6, 2026 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants