Skip to content

test: repo-wide vitest console-intercept disarm + arrival gate (#10374) - #13522

Merged
os-project-manager merged 3 commits into
mainfrom
claude/issue-10374-console-intercept-shape
Aug 30, 2026
Merged

test: repo-wide vitest console-intercept disarm + arrival gate (#10374)#13522
os-project-manager merged 3 commits into
mainfrom
claude/issue-10374-console-intercept-shape

Conversation

@claude

@claude claude Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Fixes #10374

The amplifier itself is vitest's and stays upstream (raising it there was ruled optional and non-blocking by triage); this PR closes the repo's exposure to it, completing the card's re-graded scope: measure the per-suite cost, choose the shape, implement with the pin intact.

What this does

  1. Disarms vitest's console interception in every vitest-running packagedisableConsoleIntercept: true in each package-root vitest.config.ts: 42 configs edited, 29 created for packages that ran vitest with no config at all, 1 already disarmed (examples/app-showcase, CI flake: @objectstack/example-showcase#test fails on mass sys_* Find operation failed + Acquire connection error: operation timed out — hit a merge-queue build and a PR run within 2h on unrelated prose-only diffs #10293 / PR test(showcase): disarm the vitest console-forwarding teardown race that reddens a green suite (#10293, #10374) #10605, untouched). packages/qa/dogfood carries the setting per project: measured on vitest 4.1.10, inline projects do NOT inherit a root-level disableConsoleIntercept (probe: root disarm + inline project + logging test — the console RPC still arrived, byte-identical to the armed control), so a root-only spelling there would be declared-but-not-enforced.
  2. Adds the arrival gate scripts/check-console-intercept-disarm.mjs + a lint.yml step: every package whose scripts run vitest must carry the package-root disarm; disableConsoleIntercept: false at package root is refused; a projects config must disarm every project block; fixture configs below the package root (the pin's positive control) are exempt by scope. Self-tests pin the verdict directions — a comment about the setting does not satisfy it, a string literal spelling it does not satisfy it, and the root-inert projects trap fails loudly.

The measurement (the shape decision rests on it)

Population, re-derived on origin/main 240aad5 — the card's denominator was stale in both directions:

  • 72 packages run vitest, not 43: 43 have a config, 29 run vitest with no config file (invisible to any vitest.config.ts count). All 72 verified as real invocations — every test script is plain vitest run [--passWithNoTests].
  • Disarmed set: exactly 1 (showcase). Grep control: defineConfig hits 43/43 config files.
  • Growth: exactly 38 configs at the devx scoping comment (2026-08-21T06:34Z) → 43 on 2026-08-30; five arrivals in nine days (6d5c4fa, 047ac86, 12e306a, 1524927, 4bd6faa), every one with the intercept armed. Triage's 2026-08-26 "37 of 38" relayed the 08-21 reading; the tree at that moment already held 42.

Per-suite cost of disarming — one full run of each of the 72 suites with a counting reporter on onUserConsoleLog (the traffic the disarm removes). Instrument controls: negative — showcase as-is reads 0 calls; calibration — showcase with the intercept forced back on reads 93 calls / 340 lines against the 72 / 285 recorded on 2026-08-21 (same magnitude; the suite grew). All 72 suites passed during measurement (52,268 tests, 0 failures).

Totals: 8,066 intercepted console RPCs per full-repo run, carrying 61,086 lines — every one previously serialized to the main thread and then discarded by the non-TTY default reporter (silent: 'passed-only').

Distribution (lines of previously-discarded console output per run; cum% of total):

suite lines cum% calls
packages/qa/dogfood 41,115 67.3 1,572
packages/objectql 5,077 75.6 2,419
packages/rest 2,902 80.4 775
packages/verify 2,544 84.5 187
packages/runtime 1,987 87.8 702
packages/cli 1,563 90.3 355
packages/plugins/plugin-auth 1,131 92.2 216
next 32 suites (each ≤ 658) 4,767 100.0 1,840
33 suites with zero traffic 0 0

The full per-suite table is in the card's os-dev-report comment.

Why repo-wide, against the other two shapes:

  • Targeted application loses on its own selection criterion. The distribution's sharpest fact: examples/app-showcase — the ONE suite that actually flaked, twice — sits mid-tail at Migrate documentation site to Fumadocs with monorepo structure and shared content #11 with 340 lines. Volume does not predict the trigger; the trigger is a single console write landing in a ~1ms load-widened window, and 39 of 72 suites emit at least one. A targeted shape needs an oracle for "logs during teardown", which is precisely the load-dependent, statically-invisible property that made the original defect take two sightings and a reproduction to diagnose. It also narrows the trigger rather than removing the mechanism — the weaker answer the landed CI flake: @objectstack/example-showcase#test fails on mass sys_* Find operation failed + Acquire connection error: operation timed out — hit a merge-queue build and a PR run within 2h on unrelated prose-only diffs #10293 disarm was explicitly chosen against. And the population outruns any target list: five new configs in nine days, all armed.
  • A shared/base config loses on mechanics, not intent. An imported vitest.shared.ts lives outside every package's turbo test inputs ($TURBO_DEFAULT$ is package-local), so editing it re-runs nothing unless turbo.json globalDependencies also grows; it adds a cross-package import edge to all 72 configs (the input-radius class check:cross-package-test-inputs exists to police); and it still needs the same arrival gate for config-less packages. Its single-source-of-truth benefit is had cheaper: the mechanism docblock lives once (showcase config), each added line carries a two-line pointer, and the gate's failure text carries the recognition signature.
  • Repo-wide cost, honestly: +61,086 lines across CI shard logs (a 31,839-line shard was the recorded baseline; the shard carrying dogfood grows by ~41k), and console output loses vitest's stdout | file > test attribution header and per-task buffering. 33 suites pay nothing; 26 more pay ≤ 500 lines each. The heavy emitters are heavy because registry/engine loggers default loud under test — filed separately as finding: test-suite console chatter measured at 61k lines per full repo run — dogfood 41k and objectql 5k dominate, and the loudness is a logger-default question #13517 (a logger-default question, per the boundary the showcase docblock already records; re-arming interception would not remove that cost, only hide it again while paying an RPC per write and re-exposing every suite to the race).

Verification

  • Gate self-test (10 cases + real-tree population floor) green; real scan: OK: 72 vitest-running package(s), every one disarms console interception at the package root.
  • Reverse verification, from committed state: removing the line from one config → gate exit 1 naming that package; restore proven by git hash-object == HEAD blob and empty git diff HEAD; gate green again.
  • Teardown-race pin: full showcase suite green post-sweep (26 files, 364 passed — premise probe, guarded leg included). The pin and the fixture exclude are untouched, so it still fails if showcase's disarm is removed.
  • Post-sweep behaviour: objectql (was 2,419 calls) → 0; app-todo (created config, was 205) → 0; dogfood two files spanning both projects → 0; all suites pass.
  • All 71 touched configs parse (esbuild, the loader family vitest uses).
  • Derived gate union at d0154fd: green (engine-split-ratio required a deepened fetch per its own remedy text; result recorded in the report). check-test-completeness.mjs: NOT MEASURED locally (exit 3 PREREQUISITE NOT MET by design).
  • Local narrowing, declared: the full 72-suite population ran green once pre-edit (the measurement itself) and 4 representative suites (3 edit shapes + the pin) re-ran green post-edit; the full post-edit population run is Test Core's job on this PR.

Out of scope, recorded: #13517 (test-log console volume is a logger-default question). Raising the two upstream fix shapes with vitest stays optional per triage and is not done here.

Generated by Claude Code


Generated by Claude Code

claude added 3 commits August 30, 2026 15:10
…cept (#10374)

The late-console teardown race (#10374) is removed per suite by
disableConsoleIntercept: true; this gate makes the invariant hold for the
whole moving population — 38 vitest configs on 2026-08-21 were 43 by
2026-08-30, every arrival with the intercept armed, and 29 more packages run
vitest with no config file at all. The sweep that applies the setting to all
of them follows in this branch; the gate is what keeps the next arrival from
undoing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
…rypoint (check:entry-guard)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
…running packages (#10374)

Measured across the whole population (8,066 intercepted console RPCs per
full-repo run carrying 61,086 lines, every one discarded by the non-TTY
default reporter): 33/72 suites emit nothing and are disarmed for free;
dogfood alone carries 67% of the volume; and the one suite that actually
flaked (showcase) sits mid-tail at 340 lines — volume does not predict the
trigger, so the mechanism is removed everywhere rather than the trigger
narrowed anywhere. 42 configs edited, 29 created for packages that ran
vitest with no config; dogfood's setting is per-project because inline
projects do not inherit the root value (measured on vitest 4.1.10).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 68 changed file(s) yielded no anchor (packages/adapters/hono/vitest.config.ts, packages/cli/vitest.config.ts, packages/client-react/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 68 changed package(s)).

What this run could not see
  • 68 changed file(s) yielded no anchor (packages/adapters/hono/vitest.config.ts, packages/cli/vitest.config.ts, packages/client-react/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 — 158 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 c074c57e452734821caf6f43329a20e873926f16packageMentionDocs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding: any late console.* in a vitest worker can fail a fully green suite — the #9371 amplifier is upstream and still live

2 participants