Uh oh!
There was an error while loading. Please reload this page.
fix(tests): read the kernel log level from logger.level, the key ObjectKernelConfig declares - #11080
Conversation
…jectKernelConfig declares
`new ObjectKernel({ logLevel: 'silent' })` silences nothing. `ObjectKernelConfig`
declares only `logger?: Partial<LoggerConfig>`, so `logLevel` is an unknown
excess property; the kernel builds its logger from `createLogger(config.logger)`
with `config.logger` undefined, and the level falls to the `'info'` default.
Twelve call sites across seven test files declared themselves silent and logged
their whole bootstrap anyway.
Measured before changing anything, against the built `dist`:
{ logLevel: 'silent' } -> 91 bytes on stdout
{ logger: { level: 'silent'} } -> 0 bytes
{} (no config, default info) -> 91 bytes, byte-identical to the logLevel run
`logLevel` is inert: it produces exactly the no-config baseline. `tsc` against
the built types reports TS2353 for that spelling and accepts `logger.level`.
Repairs all 12 sites to `logger: { level: 'silent' }`. Two comments in
record-change-integration.test.ts narrated a contrast against "this file's
OTHER `{ logLevel:`" that this sweep makes false; both are rewritten.
`logLevel` remains correct and untouched elsewhere — `SchemaRegistry` declares
it for real, and esbuild has its own; only ObjectKernel construction was wrong.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. |
os-elon
commented
Aug 22, 2026
Open question answered: A — |
os-elon
commented
Aug 22, 2026
Enqueued — marked ready for review by the Closing the loop on my previous comment, which left this pending because two checks were unfinished. Six required checks, BY NAME on |
| check | verdict | ran for |
|---|---|---|
TypeScript Type Check · workspace | success | 2m30s |
TypeScript Type Check · debt ledger | success | 5m20s |
TypeScript Type Check · source gates | success | 2m14s |
TypeScript Type Check · consumer gates | success | 2m54s |
Lint & Repo Gates | success | ~9m |
Test Core (6 shards) | success | 2m02s – 7m34s |
Dogfood Regression Gate (3 shards) | success | 4m34s / 4m40s / 5m45s |
Build Core | success | 1m28s |
Temporal Conformance (live PG + MySQL) | success | 3m20s |
The four Type Check lanes are quoted individually because the roll-up completes in ~4s whether or not the lanes did anything — reading the roll-up alone cannot tell a pass from a no-op.
⛔ No other red gate. Check Changeset is success on this head, which is the positive confirmation that the skip-changeset disposition is the one the gate wants. Console Pin Gate and Build Docs are skipped by path filter on a test-only diff — stating that rather than counting them as passes.
Base is 4257e4e4e3, the current main tip, so no stale-base refresh was needed here. mergeable_state: clean. Labels read back as size/s, tests, skip-changeset — the bot's own labels survived the write.
What this PR is worth beyond its diff
The diff is 25 lines across 7 test files, which understates it. Twelve fixtures declared themselves silent and logged their entire bootstrap anyway; 1,751 log frames disappear. The measurement that makes it trustworthy is the three-row probe — { logLevel: 'silent' } at 91 bytes, {} with no config at all at 91 bytes, { logger: { level: 'silent' } } at 0 — because byte-identical to the no-config baseline settles that the key was inert rather than weak, and those are different defects. Two further instruments agreed without sharing an assumption: TS2353 on the logLevel line only, and check:type-check-debt moving -2 on runtime and -1 on plugin-approvals, exactly the sites repaired per package.
logLevel is not uniformly wrong in this repo, and the sweep deliberately did not target the identifier. SchemaRegistry genuinely declares it (~40 correct sites, behind OS_REGISTRY_LOG), and esbuild has its own — used in two CLI production files. All left untouched. The population was new ObjectKernel({ logLevel, the constructor.
The observability consequence is filed separately as #11081 rather than folded in: five of the seven fixtures now blanket-silence with no capture pin, so a future unexpected ERROR there would be invisible. Nothing unexpected was silenced today — all 1,751 frames were classified, and the two least obvious turned out to be the asserted behaviour of their own tests. That card is a claim about tomorrow, and grading it is triage's.
Generated by Claude Code
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32589381189 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Fixes#10984
new ObjectKernel({ logLevel: 'silent' })silenced nothing.ObjectKernelConfig(
packages/core/src/kernel.ts) declares only aloggerkey holding a partialLoggerConfig(the type argument spelled in words here because GitHub strips shortangle-bracket fragments out of a body), so
logLevelwas an unknown excess property.The kernel builds its logger from
createLogger(config.logger)withconfig.loggerundefined, and the level falls to the
'info'default (packages/core/src/logger.ts).Twelve call sites across seven test files declared themselves silent and logged their
entire bootstrap anyway.
The defect, measured before it was repaired
Runtime probe against the built
dist, constructing each kernel and registering oneservice (which the kernel logs at
info), capturing stdout/stderr:{ logLevel: 'silent' }— the 12 call sites' spelling{ logger: { level: 'silent' } }— the correct spelling{}— no config at all, default'info'The
logLevelrun is byte-identical to the no-config baseline: the key is inert,not merely weak. Emitted line, identical in the first and third rows:
Static half,
tscagainst the built types — one error, on thelogLevelline only,while the
logger.levelline typechecks clean:An independent confirmation arrived from a gate that never saw this reasoning:
check:type-check-debt --re-measurereports@objectstack/runtime227 recorded /225 measured (-2) and
@objectstack/plugin-approvals348 / 347 (-1) — exactlythe sites repaired in each package.
What changed
All 12 sites, re-measured at this branch's head before editing (12 sites / 7 files,
matching the count on the card exactly). The population is
new ObjectKernel({ logLevel— the constructor, never a bare
logLevelgrep, because the identifier has two otherlegitimate owners in this repo:
SchemaRegistrygenuinely declareslogLevel(packages/objectql/src/registry.ts),behind the
OS_REGISTRY_LOGenv var — roughly forty correct sites, untouched.logLeveloption, used in two CLI production files(
packages/cli/src/commands/plugin/build.ts,packages/cli/src/utils/build-runtime.ts).A repo-wide sweep for
ObjectKernelconstruction carryinglogLevel— not just underpackages/, which is as far as the card went — finds 12 occurrences, all seven ofthem test files. No production call site exists, so the stop-and-report condition
on the card did not fire.
Per-fixture output diff
Each fixture was run individually before and after, and its kernel log frames counted by
level. Every one of the seven goes completely silent — 1,751 frames removed in total:
notification-schema-conformance.integration.test.tsnotifications.hono.integration.test.tsrecord-change-integration.test.tsbulk-write-per-row-context.test.tsformula-context.test.tsmultilookup-context.test.tsstatus-mirror-cascade.integration.test.tsEvery newly-silenced frame was classified, and all fall in expected classes — no
unexpected output was silenced:
sys_metadata could NOT be read at boot,sys_automation_run could not be read at startup,[wait] suspended wait-timer re-arm ABORTED,System started with degraded capabilities. Missing core services: auth.Find operation failedon the authz tables these fixtures do not provision — the sameclass the runtime captures pin.
runAs-with-no-user refusal, whose test asserts the flow write must not land, and there-entrancy guard breaking a self-trigger loop, which that test's own comment narrates.
The expected-noise captures are intact and still load-bearing
The captures on the two runtime fixtures are PINs, not mutes — they intercept at the
driver/engine layer, independent of the kernel's logger level, and assert in
afterAllthat the expected refusal was emitted, failing if it goes silent. Those assertions
still pass, which is positive evidence the captures kept measuring rather than being
defeated by the new silence.
The five fixtures that have no such capture are now on a blanket
silent, which hidesunexpected frames along with expected ones. Nothing unexpected was silenced today — every
frame was classified — but the observability gap is filed separately as #11081 rather
than absorbed here.
Two comments corrected
record-change-integration.test.tscarried two comments contrasting a correct siteagainst "this file's OTHER
{ logLevel:". The sweep makes that contrast false in thesame commit, so both were rewritten to describe the spelling that is now uniform.
The converse comments in
packages/objectql/src/plugin.integration.test.tsandplugin.step2.test.tssaylogger.levelis right and thatObjectKernelConfigneverhad
logLevel— still true, deliberately left alone.Release declaration:
skip-changeset, not a changeset fileThis PR touches only
*.test.tsfiles, which are not part of any published artifact, soit releases nothing. The dispatch asked for a
.changeset/*.md; that route is closedhere and the label is the mechanism this repo actually enforces:
published output is byte-identical, polluting the release notes.
scripts/check-empty-changeset.mjs, so it would trade one red for another.Flagging the deviation rather than resolving it silently.
Verification
Gate union derived with
node scripts/pm/dispatch-gates.mjsand no path arguments, runat head
0af0a90c8a, after the final commit. All green; each gate's own verdict line:check:cross-package-test-inputs—OK: 13 package(s) read outside themselves, all declaredcheck:slot-lookup—✓ slot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none newcheck:test-source-alias—OK — 72 packages with tests scannedcheck:type-source-resolution—OK — 77 packages with a tsconfig.json scannedcheck-ci-filter-parity—OK: all 83 declared cross-package glob(s) (72 unique) are coveredcheck-plugin-teardown-shape—✓ 63 Plugin implementation(s) across 4448 source(s)check-affected-docs—✓ affected-docs self-test: 339 cases pass.check:query-options-erasure—✓ ratchet holds: 67 unswept non-test site(s), none newcheck:type-check-coverage—OK — 65/78 workspace packages type-checkedcheck:engine-double-contract—OK — 377 pinned, 133 in the DEBT ledger, 2 exempt.check:where-matcher—✓ 277 matcher(s) discovered, 277 answer the combinator battery correctlycheck:i18n—OK (9 package(s) — all bundles in sync)check:nul-bytes—OK (scanned 6400 text file(s) ... no raw ASCII control bytes)check:type-check-debt—OK — 33 ledger entr(ies) re-measured in 200.7s, 1896 raw tsc error(s) total, none above its recorded number.Full suites for all three affected packages, not just the changed files — identical
counts before and after, so nothing regressed and nothing became vacuous:
@objectstack/runtime@objectstack/trigger-record-change@objectstack/plugin-approvalsTEST_DEBT ledger deliberately not touched — triage ruled that class out of scope.
The ratchet fails only on upward drift and explicitly permits the two entries to sit
above their measured value, so leaving them is green and lowering them was not this PR's
call to make.
Clause-② path limb:
git diff --name-only origin/main...HEADyields seven paths,none under
packages/spec/src/— the limb is empty, as expected for a test-onlyrepair. No contract surface is touched.
Nothing was repaired outside the seven files on the card.
Generated by Claude Code