fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(scripts): collect TypeScript fences opened inside a blockquote - #7100

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector
Sep 1, 2026
Merged

fix(scripts): collect TypeScript fences opened inside a blockquote#7100
os-warren merged 1 commit into
mainfrom
claude/issue-7086-blockquoted-fence-collector

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#7086

check-doc-snippet-types collects blocks with scanFences, whose fence-opening anchor accepted a run of leading spaces and tabs and nothing else. A fence opened inside a Markdown blockquote carries a > prefix, so the anchor never matched, the block was never collected, and the gate compiled nothing for it. There was no diagnostic — an uncollected block appears in no count, and its page still reports as covered. A callout is a natural home for an import example, which is exactly the snippet class that rots when an export is renamed: the one class this gate exists to catch.

Took option (a) of the three the card left open, per the dispatching PM's ruling. This is gate strengthening — restoring declared-equals-enforced on a gate that claimed to compile the docs' TypeScript and silently did not.

What changed

The opener now tolerates a blockquote prefix and carries the opener's quote depth through the rest of the walk:

  • the search for the closing fence reads candidate lines at that same depth;
  • every body line is stripped of that many markers before it reaches the compiler;
  • stripQuotePrefix consumes at most one space after each marker, per CommonMark, so indentation belonging to the snippet survives.

Depth 0 takes an identity path that returns the line unchanged byte for byte. That is what keeps the other 773 collected blocks in the corpus scanning exactly as before, and it is pinned.

Carrying the depth to the closing fence is what makes this safe in both directions. Without it, a blockquoted fence would find no close and swallow the rest of the file; and a plain fence would be closed early by any quoted backtick line sitting inside it as prose. Both directions have a test.

The ledger movement, measured

The card warned that widening the anchor "may pull previously-invisible blocks into the compiled population, which is a ledger movement rather than a one-line edit". It is, and it is exactly one block:

beforeafter
collected blocks, whole 224-document population773774
gate's own covered blocks383384
of those, to compile271272
declared fragments112112
semantic phase failures00

Newly collected: 1 — the import callout at content/docs/api/schema-reference.md line 12. Its disposition: compiles clean. No longer collected: 0; nothing left the population. Block identity was compared by document, fence line, language and a hash of the body, so a block whose body merely changed shape would have shown as one removal plus one addition rather than silently matching.

The card's sharpest handle reproduces and flips: importing the gate's own exported scanFences and running it over that page returned 2 collected blocks against 3 typescript fences before, and returns 3 now.

Verification

Re-derived against main @ 2c3cd1b before editing — every line number and count in the card still held: TS_FENCE_LANGUAGES at :317, the anchor at :587, acted on at :600; 224 documents; exactly 1 blockquoted ts/tsx/typescript fence, on the page the card named. The card's three controls all reproduce.

Gate and tests, run on the final commit e463ae1:

Scanned 224 document(s): 181 covered (80 of them hold a ts/tsx block), 43 ungated
Covered blocks: 384 — 272 to compile, 112 declared fragment(s).
Semantic phase: 272 of 272 block(s) judged, 0 failed.
Every covered documentation snippet compiles against the built types.
Test Files 1 passed (1)
Tests 48 passed (48)

eslint on both changed files: exit 0. All four changeset gates: exit 0. check-changeset-presence verdict, quoted: ✅ No source or published contract of a released package changed in this range, so no changeset is owed. — so the changeset here is the empty-frontmatter form, not a patch bump that would falsely claim a released package moved.

Ablation. With the fix reverted to the 2c3cd1b blob (mutation confirmed on disk by hash and by stripQuotePrefix dropping to 0 occurrences), 3 of the 4 new pins fail and the gate's covered count falls back to 383/271. The fourth — the depth-0 identity guard — passes in both trees, which is correct: it pins pre-existing behaviour that this change must not move. Restore was proved byte-identical to the HEAD blob, with a clean git diff HEAD. No rebuild leg is owed here: the gate runs as node scripts/check-doc-snippet-types.mjs and the test imports '../check-doc-snippet-types.mjs', both source paths, neither resolved through a package dist.

Scope

Confined to the collector's anchor and its prefix-stripping; the gate is not refactored. One bounded gap is deliberately left alone and filed separately as #7099: FRAGMENT_MARKER and the marker-attachment walk are still blockquote-unaware, so a blockquoted block that legitimately cannot compile has no reachable escape hatch. Population there is 0 today (measured, with controls at 2900 plain openers and 112 plain markers), and a correct fix needs a second mechanism — the blank-line walk — which was outside this card's dispatched scope.

Generated by Claude Code


Generated by Claude Code

`scanFences` anchored a fence opener on leading spaces and tabs only, so a
fence opened inside a Markdown blockquote carried a `> ` prefix the anchor
never matched. The block was never collected and the gate compiled nothing
for it, with no diagnostic: an uncollected block appears in no count and its
page still reports as covered.
The opener now tolerates a blockquote prefix and carries the opener's quote
depth through the rest of the walk — the search for the closing fence reads
candidates at that same depth, and body lines are stripped of that many
markers before reaching the compiler. Depth 0 takes an identity path that
returns the line unchanged byte for byte, so every unquoted fence in the
corpus scans exactly as before.
Measured over the gate's own 224-document population: 773 -> 774 collected
blocks, nothing dropped. The one newly-visible block compiles.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(gate): check-doc-snippet-types cannot see a TypeScript fence opened inside a blockquote — 1 block today, silently uncompiled

2 participants

@os-warren@claude