Skip to content

Ratchet the declared registry log level across engine-booting suites - #15559

Merged
baozhoutao merged 5 commits into
mainfrom
claude/issue-15425-registry-log-level-ratchet
Sep 4, 2026
Merged

Ratchet the declared registry log level across engine-booting suites#15559
baozhoutao merged 5 commits into
mainfrom
claude/issue-15425-registry-log-level-ratchet

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #15425

Nothing in this repo ratcheted a registry log level. PR #13985 and PR #14016 declared OS_REGISTRY_LOG in four vitest harnesses and removed ~47,900 console-carried lines between them, and deleting any one of those env lines restored five figures of output while every suite stayed green — the declared-but-unenforced shape this repo refuses.

The card's population claim did not survive contact with the tree

The card stated the population as "4 app-booting suites, and all 4 took the declaration". The repo's own audit contradicts it: docs/audits/2026-09-test-log-volume-census.md measures all 72 vitest packages and records the residual [Registry] lines after #13985/#14016 as dogfood 2, verify 0, runtime 9, objectql 66 — and packages/rest, that audit's own named untouched control, at 528. rest emits eight times declared objectql's residue and had no declaration at all.

So "4" is a property of where #13517's selection stopped, not of the tree. The PM ruling on this card (comment 5545637267) records the correction and rules the gate ships at the predicate's true width. A roster of four would have been a hand list demonstrably wrong on the day it shipped.

The predicate — derived, no roster

A vitest-running package is selected when its own test sources do any of:

signal spelling matched against
S1 constructs a registry — new SchemaRegistry( comment and string/template-masked source
S2 boots a stack through @objectstack/verify — imports bootStack from it, or exports function bootStack itself comment-masked source
S3 imports a real @objectstack/example-* app comment-masked source

Test sources are the package's own *.test.* / *.spec.* files plus everything under a test/, tests/ or __tests__/ directory — harness helpers boot stacks too (packages/qa/dogfood/test/shared-showcase.ts is the memoized boot the whole shared-showcase project runs on).

Comment masking is what makes the predicate honest rather than merely plausible. Measured on this tree, packages/cli names bootStack and @objectstack/verify in eight places, every one of them a comment or docblock. Unmasked, S2 selects cli — a package that boots no stack in any test — and the gate would then demand a declaration that quiets nothing. S1 additionally masks string and template content, so a spelling inside a literal is never the setting.

The walk is check-console-intercept-disarm's own exported workspacePackageDirs, and the verdict format is that gate's. Only the assertion and the population are new.

The census — 72 walked, 8 selected, zero over, zero under

The gate re-prints this on every green run, so a predicate that silently stops selecting names itself:

OK: 72 vitest-running package(s) walked, 8 selected as engine-booting, every one declares a recognised registry log level (debug/info/warn/error/silent).
    packages/client — S1 constructs a SchemaRegistry in its tests
    packages/objectql — S1 constructs a SchemaRegistry in its tests
    packages/rest — S1 constructs a SchemaRegistry in its tests
    packages/runtime — S1 constructs a SchemaRegistry in its tests
    packages/verify — S2 boots a stack through @objectstack/verify's bootStack
    packages/qa/dogfood — S2 boots a stack through @objectstack/verify's bootStack; S3 imports a real @objectstack/example-* app in its tests
    packages/services/service-automation — S1 constructs a SchemaRegistry in its tests
    examples/app-showcase — S1 constructs a SchemaRegistry in its tests

Twelve rejected candidate predicates and their over/under-selection are in the report comment on the card; the closest exact-4 hit was "the vitest config declares any env: block", which is circular and worthless as a ratchet (the only env key in any of those configs is OS_REGISTRY_LOG, so deleting the whole block passes silently — precisely the edit this gate exists to catch).

What is asserted, and what is deliberately not

Asserted: a package-root vitest config exists; it carries OS_REGISTRY_LOG as a key inside an env block in comment-masked source (a docblock about it never counts — load-bearing here, since all four original carriers carry a ~30-line rationale docblock naming the variable repeatedly); the value is a level the engine actually recognises; and for an inline-projects config, every project's own test block carries it, because a root-level setting is inert for project runs.

The level vocabulary is read from objectql's own REGISTRY_LOG_LEVELS rather than copied, because registry.ts resolves an unrecognised value to the 'info' DEFAULT silently — OS_REGISTRY_LOG: 'quiet' would read as a considered choice and quiet nothing. A vocabulary the gate cannot read is exit 2, never a pass.

Not asserted, and untouched: which level a suite picks; packages/objectql's shipped 'info' default (registry.ts:1265 stays exactly as it is, for every production reader); and any library awareness of a test runner. This gate reads harnesses only.

The four adopters

packages/client, packages/rest, packages/services/service-automation and examples/app-showcase adopt the declaration here, one commit each, at the same level the four carriers use — the shape PR #14016 landed for three packages at once. examples/app-showcase's own disableConsoleIntercept docblock had deferred exactly this question in as many words ("most of it [Registry] registration chatter. Quieting THAT is a separate question about @objectstack/objectql's own default log level"); this answers it in the harness.

Neither precedent PR carried a changeset (#13985 touched one vitest config, #14016 three, both without one): harness-only edits publish nothing from any package, so this PR is skip-changeset.

Verification

Every exit code captured before any pipe; each line below is the verdict the tool printed. Union re-run at final commit cf07c12ff.

The gate itself

run verdict
gate on the pre-adoption tree EXIT=1check-registry-log-declared: 4 engine-booting suite(s) declare no recognised registry log level: naming client, rest, services/service-automation, examples/app-showcase, and silent on the four carriers
gate on this branch EXIT=0 — the census block quoted above
--self-test EXIT=0self-test OK: 15 cases + level-vocabulary read + population declaration + real-tree selection floor.

The 15 cases carry both controls the card asked for: a selected package missing the key reds, an unselected package without the key is silent, a selected package with the key is green — plus prose-does-not-satisfy, prose-does-not-select (the packages/cli shape), unrecognised level, key outside any env block, each of S1/S2/S3 selecting, no-config, the two projects rows, and a template-literal spelling. Floors are #13799 recipe A: the table's own row labels are the declared batteries, registerCase(name) is the first statement of the loop body, and the roster is a literal (a derived one would delete a row's floor along with the row).

Ablation on the committed implementation — trap-guarded, absolute paths, blob-hash restore:

HEAD blob for packages/objectql/vitest.config.ts = f79c823d875a3df4906922bb2e4eb8a07aa89a21
before: env-declaration lines = 1
after:  env-declaration lines = 0
mutated blob = 5c838b5381bddd2970b034ff3127c1f559331c27
ABLATED EXIT=1
check-registry-log-declared: 1 engine-booting suite(s) declare no recognised registry log level:
packages/objectql/vitest.config.ts declares no OS_REGISTRY_LOG (a comment about it does not count). …
restored blob = f79c823d875a3df4906922bb2e4eb8a07aa89a21
git diff HEAD on target empty: exit=0
RESTORED EXIT=0

Both legs are confirmed on disk by grep counts and by blob hash, not by the editor's exit code.

The adopters' suites, and the rest delta

packages/rest is the audit's control, so it was measured in both directions — the before leg by the same trap-guarded revert:

leg suite verdict [Registry] lines
declaration removed (before) Test Files 178 passed (178) · Tests 3023 passed (3023) 528
declaration in place (after) Test Files 178 passed (178) · Tests 3023 passed (3023) 0

528 reproduces the audit's figure for this suite to the line, on a tree many commits younger.

package suite verdict
packages/client Test Files 33 passed (33) · Tests 437 passed (437)
packages/services/service-automation Test Files 105 passed (105) · Tests 1242 passed (1242)
examples/app-showcase Test Files 27 passed (27) · `Tests 374 passed

Those three runs leave 8 residual [Registry] lines, and all 8 are ADR-0005 [Registry] Collision diagnostics in service-automation — the bare console.warn the level never gates, and the very lines flow-name-shadowing.test.ts asserts on. The declaration quiets chatter, not diagnostics; that is measured here rather than asserted.

Wiring and repo gates

command verdict
pnpm check:self-test-wired EXIT=0
pnpm check:self-test-workflow-commands (node scripts/check-self-test-workflow-commands.mjs + --self-test) EXIT=0
pnpm check:declared-population-live EXIT=0
pnpm -s check:pm-dispatch-gates EXIT=0✓ dispatch-gates self-test: 1402 cases pass. (no case edited)
pnpm check:nul-bytes EXIT=0
pnpm lint (full repo, eslint . --no-inline-config) EXIT=0

The derived gate family. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (stderr: derived at commit cf07c12ff, --repo checked against this checkout's origin — it holds) yields 77 commands. All 77 were run. 76 PASS. Exactly one is NOT MEASURED, and it is recorded as such rather than as a pass:

  • pnpm check:dual-build-cjs-loadsEXIT=3, Run pnpm build first. ⛔ This is NOT a pass: nothing was measured. It needs a full-repo build, and it names dist directories in packages far outside this diff (service-cluster-redis, service-knowledge).

pnpm check:type-check-debt (whole-repo tsc) is in the 76: it outran a 400s budget on the first attempt and was re-run to completion under the verify lock — EXIT=0, surplus: none — every entry sits exactly at its measurement, so any new error is red.

Two more needed their environment before they measured anything, and did so once it was supplied: node scripts/check-required-contexts.mjs --verify-required-set answered EXIT=2 / required-set sweep: NOT VERIFIED — … HTTP 401 (its own text: "NOT VERIFIED is not a pass and not a failure of the tree"), then EXIT=0 re-run with NODE_OPTIONS=--use-env-proxy and a token; and pnpm --filter @objectstack/spec run check:skill-examples refused on an unbuilt packages/spec/dist, then EXIT=0 after pnpm --filter @objectstack/spec build✅ 257 prose examples type-check across 3 surface(s).

All heavy runs went through scripts/pm/os-verify-lock.sh; each printed VERDICT command-exit 0.

🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

`packages/rest` is the untouched CONTROL in
docs/audits/2026-09-test-log-volume-census.md: while PR #13985 and PR #14016
declared a registry log level in four harnesses, this suite got none, and the
audit measures 528 residual `[Registry]` lines here — eight times what declared
objectql still emits. Six test files in this package construct bare
`SchemaRegistry` instances, so the chatter is per registered item per case.

This declares the level in the harness only. objectql's shipped `'info'`
default is unchanged for every production reader, and no library code is made
aware of a test runner: `OS_REGISTRY_LOG` is the engine's own published seam
(`SchemaRegistryOptions.logLevel` / `REGISTRY_LOG_LEVELS`).

The ADR-0005 `[Registry] Collision` diagnostics ride a bare `console.warn` that
the level never gates, so a real shadowing still speaks here.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
`packages-write-envelope.test.ts` constructs bare `SchemaRegistry` instances
per case and installs a package manifest into them, so this suite pays a
`[Registry] Registered …` line per registered item at the engine's shipped
`'info'` default.

Harness-only, the same shape PR #14016 landed for three other suites:
objectql's shipped default stays `'info'` for every production reader, and no
library code learns it is under a test runner. `OS_REGISTRY_LOG` is the
engine's own published seam.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
`connector-reload-reingest.test.ts` and `flow-name-shadowing.test.ts`
construct bare `SchemaRegistry` instances and register connectors and flows
into them per case, so the registration chatter is per item per case at the
engine's shipped `'info'` default.

`flow-name-shadowing.test.ts` asserts on shadowing warnings, which ride a bare
`console.warn` this level never gates — the suite is measured green with the
declaration in place. Harness-only: objectql's shipped default is untouched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
This config's own `disableConsoleIntercept` docblock deferred the question in
as many words: "most of it `[Registry]` registration chatter. Quieting THAT is
a separate question about `@objectstack/objectql`'s own default log level, not
about this setting."

This answers it the way the four earlier harnesses did — the level is declared
HERE, in the harness, through the engine's own `OS_REGISTRY_LOG` seam.
`gap-fill.test.ts` constructs the registry it reaches. objectql's shipped
`'info'` default is unchanged for every production reader.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…ting suites

objectql's `SchemaRegistry` logs one `[Registry] Registered <kind>: <name>`
line per registered item per construction, at its shipped `'info'` default. A
suite that boots app stacks pays items x boots of that on a CI shard log nobody
reads. PR #13985 and PR #14016 declared `OS_REGISTRY_LOG` in four harnesses and
removed ~47,900 console-carried lines — and nothing held them there. Deleting
one `env` line restored five figures of output while every assertion stayed
green and every outcome was unchanged.

This gate asserts the declaration. It reuses `check-console-intercept-disarm`'s
exported `workspacePackageDirs` walk and its verdict format, so only the
assertion and the population are new.

THE POPULATION IS DERIVED, not a roster. A vitest-running package is selected
when its OWN TEST SOURCES construct a `SchemaRegistry`, boot a stack through
`@objectstack/verify`'s `bootStack`, or import an `@objectstack/example-*` app.
On this tree that selects 8 of 72 with zero over- and zero under-selection.

A roster of the four suites that already declared would have been a hand list
this repo could show to be wrong on the day it shipped:
docs/audits/2026-09-test-log-volume-census.md measures `packages/rest` — its
own named control — at 528 residual `[Registry]` lines, eight times declared
objectql's 66. The four packages the predicate newly selects adopt the
declaration in the four commits preceding this one.

Comment masking is what makes the predicate honest rather than merely
plausible: `packages/cli` names `bootStack` and `@objectstack/verify` in eight
places, all of them prose, and would otherwise be selected while booting no
stack in any test. The registry-construction signal additionally masks string
and template content, so a spelling inside a literal is never the setting.

The level vocabulary is READ from objectql's own `REGISTRY_LOG_LEVELS` rather
than copied, because `registry.ts` resolves an unrecognised value to the
`'info'` DEFAULT silently — `OS_REGISTRY_LOG: 'quiet'` would read as a
considered choice and quiet nothing.

Out of scope and untouched: which level any suite picks, objectql's shipped
`'info'` default, and any library awareness of a test runner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026
@github-actions github-actions Bot added size/xl ci/cd dependencies Pull requests that update a dependency file tests labels Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 3 changed file(s) yielded no anchor (packages/client/vitest.config.ts, packages/rest/vitest.config.ts, packages/services/service-automation/vitest.config.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 3 changed package(s)).

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/client/vitest.config.ts, packages/rest/vitest.config.ts, packages/services/service-automation/vitest.config.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 25 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json cf6b67164e37b92cf1fb6b172aa8f44e1fdce666packageMentionDocs.

@baozhoutao
baozhoutao marked this pull request as ready for review September 4, 2026 21:17
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

ACCEPT — PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk.

Reviewed against the three-dot diff origin/main...claude/issue-15425-registry-log-level-ratchet (merge base ed9d87653, head cf07c12ff): 7 files, +1025/−0, matching the PR file list; delivered under the ruling in comment 5545637267 (Q1 = A at true width, the four adopters in-PR; Q2 the card correction).

Fixes #15425 closes the card on merge. Flipping ready and arming auto-merge now (retried each tick while the MCP channel is rate-limited).


Generated by Claude Code

@baozhoutao
baozhoutao enabled auto-merge September 4, 2026 21:18
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 0ed66da Sep 4, 2026
40 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-15425-registry-log-level-ratchet branch September 4, 2026 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants