Uh oh!
There was an error while loading. Please reload this page.
Watch the logger receiver-detach class repo-wide, on an anchored receiver vocabulary - #13132
Merged
Merged
Conversation
Anchors an explicit RECEIVER vocabulary -- never the channel name -- so the two legitimate populations #12820 measured (bound `console` methods and caller-supplied options callbacks) stay green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
This was referenced Aug 29, 2026
os-elon
marked this pull request as ready for review
August 29, 2026 06:15
os-elon
enabled auto-merge
August 29, 2026 06:15
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#12820
The first deliverable this card asked for is the false-positive surface, not a gate. It is measured below, on today's
main, and it turned out to be cheaply decidable — so the gate is here too. Every number is reproducible withnode scripts/check-logger-receiver-detach.mjs --census.1. Today's classified census, re-run
origin/mainhas moved from the card's23843d3f4toadf70f763b; the tracked.tspopulation grew from 5,096 to 5,169. Classified, non-test source, same four shapes:23843d3f4adf70f763b25exactly — my instrument counts call sites of a detached local. All six files the card names are still present, and three more appeared that the card's list does not carry (cli/commands/serve.ts,core/src/logger.ts,driver-mongodb/src/test-mongod.ts). I am reporting my own decomposition rather than asserting the two numbers are the same measurement.⭐ Triage restart condition #1 has NOT fired. There is still no fourth instance; this stays preventive,
p2,Task.2. The A2.2 return path, re-measured with a proved-non-zero control
Still 0 in-repo callers write
warn: someLogger.warninto an options bag. But the re-measurement found something the card could not have seen from one file: the naive instrument for that shape returns 36 hits repo-wide, and every one of them is a data-field copy —error: result.error,error: outcome.error,error: prep.error.erroris the most common result-envelope field name in the tree. So the return-path shape is unusable without a receiver filter, and with one it is exactly zero. That zero is now a ratchet, shape ⑤ of the gate.3. ⭐ The criterion (ruling 1), and why it cannot be the channel name
Measured over property reads whose NAME is a log channel, in call position, non-test source:
deps.error(...)— 117 sites — an error-envelope constructor,packages/runtime/src/domains/**this.error(...)— 91 sites — oclif'sCommand.error, which throwsMath.log(...)— 2 sites — arithmetic210 sites that are not logging at all, before detachment is even asked about. The name decides nothing.
The criterion is an anchored RECEIVER vocabulary, matched on the final name segment of the receiver expression — the same bargain
DURABILITY_CRITICAL_CALLEESmakes next door, with each entry naming why.logger/this.logger/ctx.logger/opts.logger/deps.logger/kernel.logger/(driver as any).loggerare one entry;optsandoptionsare not in the vocabulary at all, so the options-callback population is never reached. A second map,DECLINED_RECEIVERS, records what was considered and refused with the measurement (console: bound in Node and browsers;opts/options: caller-supplied plain functions;deps/this/math: not sinks), because the next author's first instinct is to add one of them.Honest limitations are in the file header: it is a ratchet, not a proof (a sink spelled a way the vocabulary lacks goes unwatched — the safe direction), it reads non-test source only, and it judges spelling, not reachability.
4. ⭐ A false-positive population the card could not measure
Lifted repo-wide as-is, the prototype's bare-argument shape produces 351 findings in test files — 329 of them
expect(someLogger.warn).toHaveBeenCalled()and 6vi.mocked(...). Worse: the two pin tests that document this defect class (logger-receiver-detach.test.tsindriver-sqlandplugin-auth) detach a channel deliberately, as their control sample. A gate that reds the tests proving the defect exists is the gate that gets deleted. Hence the non-test narrowing, declared with those numbers rather than as a style choice.5. The prototype was widened, not reinvented
driver-sql'slogger-receiver-detach.test.ts§3 is the judgement; this gate keeps its four shapes and its two-sided control literally (including the fallback split across lines and the docblock quoting the shape in prose), adds the receiver vocabulary and shape ⑤, and takes the reading surface from one file to 2,280. The package-local pin is untouched and still guards its own file.6. ⛔ Empty sweep refuses
This gate's success condition and its total-failure condition print the same green, so every run — not only
--self-test— scans a two-sided control corpus first and refuses unless the MUST-FIRE half produces exactly its expected findings and the MUST-NOT-FIRE half (the realconsole/ options-callback /.bind/.call/ guarded spellings from this tree) produces none. An empty walk is also refused.7. Ablations — predicted before running, with the miss reported
No build is involved: this is a
.mjsreading.tssource text, nothing resolves throughdist/. Each mutation was proved on disk by counting the deleted and injected text separately, and each restore was proved by comparing the working blob to its HEAD blob.driver-turso/src/turso-driver.ts(drop the.call(receiver, …))parenthesized-calleeonloggerloggerfromRECEIVER_SENSITIVE_SINKSconsoletoRECEIVER_SENSITIVE_SINKSconsolesitesconsoledefault" as meaning a?? console.warnleg sits in the same expression. It does not — the options sites readopts.warnwith noconsoleoperand in the expression at all, so addingconsolereaches only the 6 genuinely console-rooted sites. The card's phrase describes the semantic default, not the syntax. My prediction was wrong; the measurement corrected it.Ablation A's output is what the gate says when it fires:
8. Import-free where it counts, and the bare-root obligation
The gate does not import
scripts/pm/dispatch-gates.mjs(#12855's precedent): the import specifier would itself be a path literal in this file's source and would hand the derivation that module's population as this gate's own. Its self-test therefore holdsROOT_DIR_WATCH_HINTSto the walk with a local matcher, in both directions — every walked file is named by a hint, and no hint is dead. It does importtypescriptviaimport-prerequisite, unavoidably: this card exists because two regex instruments were weaker than the AST one.scripts/pm/bare-root-worklist.mjs --self-testfired FRESH on the new gate'sSCAN_ROOTS. ThreeDECLARED-NARROWERverdicts are recorded, each with its measured ratio (packages 4968/5485 = 90.6%, examples 204/241 = 84.6%, apps 28/40 = 70.0%).9. Side note — both halves or neither
The ADR-0120 D4 note at
driver-sql/src/sql-driver.tsrecords thatcheck-durability-degradation-log-level.mjscannot see a call on a parenthesized expression. The matcher blind spot is real and still unrecorded as fixed, AND #12792 measured that it costs zero findings today — none of its nine sites sat inside acatchguarding aDURABILITY_CRITICAL_CALLEESoperation, and the audit output was byte-identical before and after. Stating either half alone misleads. That file is untouched here; #12981 remains open on another of its blind spots, and that is a separate PR.Verification, at
be6fb46a82pnpm check:logger-receiver-detach— green: self-test, then 2,280 files, 0 detaches, control fired in the same run.pnpm lint(eslint . --no-inline-config, whole repo) — exit 0, 68s. No narrowing claimed.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack) — 41 rows, 37 green. Re-derived after rebasing ontoadf70f763b: the family list is byte-identical to the pre-rebase derivation (measured, not assumed).check-test-completenessneeds a turbo test log argument;check-half-statesexits 3PREREQUISITE NOT MET(no GitHub credential in this container);check:dual-build-cjs-loadsandcheck:type-check-debtexit 3/1 needing a built package closure — their own--self-testlegs passed, and this diff touches no package source.pnpm check:nul-bytes,check:watch-hint-literal,check:entry-guard,check:parse-guard,check:pm-dispatch-gates,bare-root-worklist --self-test,dispatch-gates --self-test(872 cases) — all green.No changeset:
check:published-filesreports every publishable package'sfileswhitelist asdist+README.md+CHANGELOG.md; the root package is private. This diff isscripts/**, rootpackage.jsonand.github/workflows/lint.yml— nothing publishes.skip-changesetapplies.Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
Generated by Claude Code
Generated by Claude Code