fix(devx): read surface-2 docblocks from the shared comment scanner, not a lazy regex - #12880
Merged
Merged
Conversation
…not a lazy regex `tsdocExampleBodies()` in check-doc-formula-expressions.mjs split docblocks with `/\/\*\*[\s\S]*?\*\//g` — the naive block-comment strip `scripts/js-comment-mask.mjs` exists to retire. A `/**` inside a string, template or regex literal opens a phantom docblock that runs to the next real terminator, so the gate read spans of live code as prose and could miss `@example` bodies it believed it had read. Measured on packages/spec/src (1,061 files, 13.7 MB) at 28a5c3e: 9 files where the regex's claimed spans hold characters the shared scanner does not call comment (13,139 of them in kernel/manifest.test.ts), 9 files — an overlapping but different set, 5 in common — where the docblock count moves, and 5 real docblocks the regex was swallowing. The gate's own verdict does not move: 416 `@example` bodies either way, byte identical, because none of the recovered docblocks carries an `@example`. Recorded rather than hidden, so nobody re-derives the fix from the unchanged count. Deletes this file's row from the shrink-only ledger in the same PR, and records the shrink in that ledger's header. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
Contributor
📓 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. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Aug 28, 2026
os-elon
marked this pull request as ready for review
August 28, 2026 06:51
os-elon
enabled auto-merge
August 28, 2026 06:51
This was referenced Aug 28, 2026
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 free
to 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 #12833
tsdocExampleBodies()inpackages/lint/scripts/check-doc-formula-expressions.mjssplit docblocks with/\/\*\*[\s\S]*?\*\//g— the naive block-comment strip thatscripts/js-comment-mask.mjsexists to retire. A/**inside a string, template or regex literal opens a phantom docblock that runs to the next real terminator, so surface 2 read spans of live code as prose and could miss@examplebodies it believed it had read. Docblock runs now come fromscanSource(text).comment, which is string-, template- and regex-literal-aware.The single matching row is deleted from the shrink-only ledger in
scripts/check-comment-mask-adoption.mjsin this PR, and the shrink is recorded in that ledger's header in the FIRST SHRINK's idiom.Premise re-measured on the branch base, not quoted from the card
The card's file lists were taken at
f75a38afa; this branch is cut from28a5c3e00. Everything below was re-measured there. Both of the card's numbers reproduce exactly, on a population that has grown to 1,061 files / 13.7 MB (the card read 1,053 / 13.4 MB).The two readings are two different sets, as the card and the triage comment both insist. They are both of size 9 and they overlap in 5 files, not 9.
Reading 1 — the regex's claimed docblock spans hold characters the shared scanner does not call comment (9 files):
Reading 2 — the docblock COUNT moves (9 files, regex count to scanner count):
A third reading the row could not have predicted: the scan recovers 5 real docblocks the regex was swallowing whole — in
api/plugin-rest-api.zod.ts,api/protocol.zod.ts(two),contracts/scoped-context.test.tsandsecurity/rls-predicate-grammar-docs.pin.test.ts.The gate does NOT get louder on this tree, and that is reported rather than hidden
The measuring round expected the
@examplecount to go UP and the new bodies to be the interesting part of the diff. Measured: it does not move. 416@examplebodies either way, byte for byte identical — same bodies, samestartLines, 0 files with any difference — because none of the 5 recovered docblocks carries an@exampleand none of the phantoms fabricated one.So the gate's own output is unchanged, and that was verified end to end rather than argued: the pre-change gate was run from a byte-identical copy of the base file (
git hash-objectmatchedHEAD's blob) placed at the same depth so itsREPO_ROOTresolved identically, and its full stdout+stderrdiffs empty against the patched gate's.⛔ This is explicitly not a reason to narrow the extractor back, and nothing here does. The swallowed span in
kernel/manifest.test.tsis 13 KB wide; the next@examplewritten behind one is invisible under the regex and judged under this scan."surface 2 admits 0 sites today"was the output of an extractor provably blind to part of its own population; it is a reading now. That reasoning is written into both files' headers so nobody re-derives the fix from the unchanged count.Because the count did not move, no formula site surfaced that had never been judged, so there is nothing to fix and no per-site card to file under the dispatch fence.
Instrument, falsified before it was trusted
Every zero here sits beside a non-zero from the same instrument in the same run.
--self-testcases were run against a re-injected lazy regex (markerABLATION_OLD_REGEX, mutation confirmed on disk by marker count and bygit hash-objectdiffering from theHEADblob): 4 of the 7 go red, including the SWALLOWED case, and the POSITIVE CONTROL stays green. Restored withgit checkout HEAD -- ..., then proved restored:git diff HEADempty and the blob hash back toHEAD's.1 recorded row(s) the scan no longer finds. Regex re-injected with the row deleted:1 NEW private comment-stripper(s). Both restored and proved restored by hash.No rebuild leg is owed by those ablations: both mutated files are
.mjsscriptsnodeexecutes from source, resolved by path and not through any package'sexportsordist, so no stale build output can mask a mutation. The dependency closurepnpm --filter '@objectstack/lint...' buildwas built first regardless, because the gate imports@objectstack/formulaand@objectstack/lintcompiled output and refuses loudly without it.Self-test
Seven cases added, both directions, reduced from shapes measured live rather than invented:
@examplebehind it is read. The regex returned nothing for this fixture.@examplequoted inside a string literal, and inside a template literal, is prose and not a site.//comment is one line comment, not a second docblock. This is the live over-count ondata/hook-body.zod.tsandui/action.zod.ts.@exampleis still extracted, at its own line. Without it an extractor that returned nothing at all would pass the block.57 cases passed, up from 50.Changeset: none, deliberately
Derived rather than assumed, because
packages/lintis a published package:packages/lint'sfileswhitelist isdist,README.md,CHANGELOG.md.packages/lint/scripts/ships to nobody, andpackages/lint/srcanddistare untouched —check:published-filesre-states that whitelist discipline in its own passing verdict.git logreceipt on the directly comparable change:904c0afe(the FIRST SHRINK) converted three files inside published packages onto this same shared mask and deleted their ledger rows, carrying zero changesets.f907fbe9(the measuring round on this same ledger) and833fd1ce(the ledger gate itself) likewise.lint.yml's own note calls a PR that edits a CI-internal script the textbookskip-changesetcase, so the label is applied rather than an empty changeset written.GitHub access is not enabled for this session), and the MCP issue-labels path cannot resolve a PR number, soskip-changesetwent on as a whole-set write with no usable pre-read. If a size or path label applied by automation in that window is missing, it was stripped by that write and should simply be re-added — the labelers here are additive and will restore what they own on their next run.Verification
Union run on the final commit,
d5a2b5e1, tree clean.Gate family re-derived from the actual diff with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack— it reproduced the dispatch brief's 20 families and added two the brief could not name, both convention-triggered by editing a gate script. Both were run and both pass:All 23 gates exit 0. Verdict lines quoted from the gates themselves, never from a bare shell status:
check:test-source-aliasandcheck:type-source-resolutionboth pass and are untouched — flagged in dispatch as PR #12768's surface.Repo-wide⚠️ Read honestly: that package's
pnpm lint(eslint . --no-inline-config) run in full, exit 0 — no narrowing to declare.pnpm --filter @objectstack/lint typecheckexit 0 andpnpm --filter @objectstack/lint test81 files / 2300 tests passed.tsconfig.jsonincludessrc/**/*only, andtsc --noEmit --listFilesreturns 0 hits for the edited.mjs— typecheck says nothing about it. The edited file's coverage isnode --check, its own--self-test,pnpm lint, and the base-versus-patched output diff above.No files outside the declared surface were touched.
Authored by a Claude Code dev seat in session
session_01CPrUz21stTFhJRUirdc4yw— https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw