Skip to content

Commit 83ea500

Browse files
claude[bot]claude
andauthored
fix(gate): assert the OG card URL escapes proxy.ts's matcher, instead of only reporting it (#13932)
`check-docs-locale-catch-all.mjs` already computed the reading that matters -- `stats.ogUrlSkipsProxy = !compiled.runsFor(probe)` -- and only printed it in the summary line. The same file's `stats.dottedBypassesProxy` was worse than inert: it LICENSES two relaxations (`:385` skips the catch-all requirement, `:409` skips the i18n predicate) while asserting nothing itself. So widening proxy.ts's matcher until it covers dotted paths took the whole gate green over a fully broken surface: the catch-all limb relaxed, the i18n limb relaxed, and the OG limb still saw a dotted marker and stayed silent -- while every live `og:image` URL was now locale-rewritten to a path `app/og/` does not serve. Measured on the script's own fixture shape before this commit: widened matcher, `ogUrlSkipsProxy = false`, findings = 0. The relaxation is kept: it is correct on its own terms, and it is what self-test case 6 pins. What changes is that it is no longer the whole story -- the OG limb now asserts the invariant on the BUILT URL from both ends (the marker still carries a dot, AND that URL still escapes today's matcher), so it fires whichever side moves. It is wired to the URL rather than to the flag, so a widening that still excludes the `/og/` prefix relaxes the catch-all requirement and correctly stays green (new self-test case 6c). Self-test: 21 -> 28 assertions. Case 6 now pins that the relaxation holds (no catch-all finding) AND that the run is red anyway; 6b is the proxy-side ablation with the marker untouched; 6c is the green control. Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC Co-authored-by: Claude <noreply@anthropic.com>
1 parent 77d4b3c commit 83ea500

1 file changed

Lines changed: 92 additions & 10 deletions

File tree

scripts/check-docs-locale-catch-all.mjs

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,28 @@
9292
// no type. Silent by construction, which is the same reason the catch-all guard
9393
// above needed a gate rather than a comment.
9494
//
95-
// This limb asserts the half that was asserted nowhere: the URL `getPageImage()`
96-
// builds ends in a final segment containing a dot. It deliberately does NOT
97-
// re-assert that the matcher excludes dotted paths -- that condition is read
98-
// once, above, and both halves are reported in the summary line.
95+
// This limb asserts the invariant on the URL itself, from BOTH ends, because
96+
// the two ends are one surface and either one moving breaks it:
97+
//
98+
// 1. the URL `getPageImage()` builds ends in a final segment containing a
99+
// dot -- the marker side; and
100+
// 2. that URL, compiled against the matcher `proxy.ts` carries TODAY, is not
101+
// matched by it -- the proxy side.
102+
//
103+
// (2) is the direct reading, and it is what makes the conditional catch-all
104+
// requirement below safe to keep. That requirement relaxes when dotted paths
105+
// stop bypassing the proxy, which is correct on its own terms -- but the same
106+
// widening 404s every `og:image`, so a gate that only read the flag could go
107+
// ENTIRELY green on the change that breaks the whole surface: catch-all limb
108+
// relaxed, i18n limb relaxed, and this limb still seeing a dotted marker. A
109+
// reading that licenses a relaxation and is asserted nowhere is not a check; it
110+
// is a statistic with a veto. So the flag keeps its licensing role and this
111+
// limb holds the surface, measured on the built URL rather than on either side.
112+
//
113+
// The two are not redundant: a matcher that widened its dot exclusion but still
114+
// excludes the `/og/` prefix relaxes the catch-all requirement AND leaves the
115+
// cards served, and this limb correctly stays green there. It fires on the
116+
// break, not on the flag.
99117
//
100118
// The assertion is made on the URL the function RETURNS, not on the array
101119
// literal alone. The marker is the URL's final segment only while the returned
@@ -347,8 +365,12 @@ export function checkApp({ appDir, proxyPath, i18nPath, sourcePath }) {
347365
// Unconditional, unlike the catch-all guard below -- a matcher that stopped
348366
// excluding dotted paths would not relax this requirement, it would break the
349367
// surface outright, so there is no condition under which a dotless marker is
350-
// the right answer. The matcher half is read once above and reported, never
351-
// re-asserted here.
368+
// the right answer. Asserted from BOTH ends on the built URL: the marker must
369+
// still carry a dot, AND the URL must still escape the matcher `proxy.ts`
370+
// carries today. The second is the one the `dottedBypassesProxy` flag alone
371+
// could never make -- the flag LICENSES relaxations below, so leaving its
372+
// consequence for this surface unasserted is what let a widened matcher take
373+
// every limb green at once.
352374
if (!existsSync(sourcePath)) {
353375
findings.push(`missing ${sourcePath}`);
354376
} else {
@@ -371,6 +393,24 @@ export function checkApp({ appDir, proxyPath, i18nPath, sourcePath }) {
371393
+ "final segment containing a dot in apps/docs/lib/source.ts (the marker's NAME is free; its "
372394
+ 'dot is not).',
373395
);
396+
} else if (!stats.ogUrlSkipsProxy) {
397+
// The break from the OTHER direction: the marker still carries its dot,
398+
// but the matcher moved under it. Reported here rather than left to the
399+
// `dottedBypassesProxy` flag, which merely relaxes two limbs below and
400+
// asserts nothing -- the whole reason this widening could land green.
401+
findings.push(
402+
`the OG card URL \`${OG_BUILDER}()\` builds -- \`${probe}\` -- IS matched by proxy.ts's `
403+
+ `matcher, even though its final segment \`${finalSegment}\` still contains a dot. The `
404+
+ 'exclusion the marker relies on moved on the PROXY side: this URL is now locale-rewritten '
405+
+ `to \`/<locale>${probe}\`, a path app/og/ does not serve, because that tree is top-level `
406+
+ 'and not under app/[lang]/. Every `og:image` on the site 404s at once, and nothing fetches '
407+
+ 'these URLs, so no other check sees it. Note this is NOT relaxed by the same widening '
408+
+ 'relaxing the catch-all requirement below: rewriting dotted paths removes the need for the '
409+
+ `locale guard and breaks the OG cards, both at once. Restore an exclusion in `
410+
+ `apps/docs/proxy.ts that covers this URL -- the dot limb (\`.*\\..*\`) is what covered it, `
411+
+ `and excluding the \`/og/\` prefix outright is the narrower alternative. Matcher(s) read: `
412+
+ `${JSON.stringify(read.matchers)}.`,
413+
);
374414
}
375415
}
376416
}
@@ -545,14 +585,54 @@ function selfTest() {
545585
assert(run.stats.segments === 2 && run.stats.guarded === 1, `both segments must be counted -- got ${summarise(run.stats)}`);
546586

547587
// 6. The condition is LIVE, not decorative: a matcher that DOES cover dotted
548-
// paths makes the guard unnecessary, and the missing guard goes green.
588+
// paths makes the locale guard unnecessary, and the missing guard is NOT
589+
// demanded. That relaxation is kept -- it is correct on its own terms.
590+
// What is no longer allowed is for it to be the WHOLE story: the same
591+
// widening takes every `og:image` to 404, so the OG limb reports it here
592+
// and the run as a whole is red. Before that limb existed this fixture
593+
// was silent, which is the hole this case now pins from both sides.
549594
paths = writeFixture(dir, {
550595
proxy: `export const config = { matcher: ['/((?!api|_next/static).*)'] };\n`,
551596
layout: FIXTURE_LAYOUT.replace(' if (!isSupportedLanguage(lang)) notFound();\n', ''),
552597
});
553598
run = checkApp(paths);
554-
assert(run.findings.length === 0, `a proxy that rewrites dotted paths must not demand the guard -- got ${JSON.stringify(run.findings)}`);
555599
assert(run.stats.dottedBypassesProxy === false, 'the widened matcher must be read as covering dotted paths');
600+
assert(
601+
!run.findings.some((f) => /never calls|is a top-level catch-all|does not read/.test(f)),
602+
`a proxy that rewrites dotted paths must still not demand the locale guard -- got ${JSON.stringify(run.findings)}`,
603+
);
604+
assert(
605+
run.findings.length === 1 && /IS matched by proxy\.ts's matcher/.test(run.findings[0]),
606+
`widening the matcher must be reported by the OG limb, not left green -- got ${JSON.stringify(run.findings)}`,
607+
);
608+
609+
// 6b. RED, THE ABLATION FROM THE PROXY SIDE. Nothing but the matcher moves:
610+
// the guard is present, the marker still ends in `image.png`, every
611+
// other limb is satisfied and the two conditional limbs have relaxed
612+
// themselves. The surface is broken anyway, and this is the reading that
613+
// says so -- taken from the built URL, not from either side alone.
614+
paths = writeFixture(dir, { proxy: `export const config = { matcher: ['/((?!api|_next/static).*)'] };\n` });
615+
run = checkApp(paths);
616+
assert(run.stats.ogFinalSegmentDotted === true, 'the marker must be untouched in the proxy-side ablation');
617+
assert(run.stats.ogUrlSkipsProxy === false, 'the widened matcher must be read as now covering the OG card URL');
618+
assert(
619+
run.findings.length === 1 && /IS matched by proxy\.ts's matcher/.test(run.findings[0]),
620+
`a matcher that swallowed the OG card URL must be reported once -- got ${JSON.stringify(run.findings)}`,
621+
);
622+
623+
// 6c. GREEN control: the limb fires on the BREAK, not on the flag. This
624+
// matcher drops the dot exclusion -- so the catch-all requirement
625+
// relaxes exactly as in 6 -- but still excludes the `/og/` prefix, so
626+
// the cards are still served and there is nothing to report. A limb
627+
// wired to `dottedBypassesProxy` instead of to the URL would cry here.
628+
paths = writeFixture(dir, {
629+
proxy: `export const config = { matcher: ['/((?!api|_next/static|og/).*)'] };\n`,
630+
layout: FIXTURE_LAYOUT.replace(' if (!isSupportedLanguage(lang)) notFound();\n', ''),
631+
});
632+
run = checkApp(paths);
633+
assert(run.stats.dottedBypassesProxy === false, 'the og-excluding matcher must still be read as covering dotted paths');
634+
assert(run.stats.ogUrlSkipsProxy === true, 'an excluded `/og/` prefix must be read as still escaping the matcher');
635+
assert(run.findings.length === 0, `a widening that still excludes /og/ must stay green -- got ${JSON.stringify(run.findings)}`);
556636

557637
// 7. RED: a matcher that stops rewriting the dotless probe is reported, not
558638
// silently read as "everything bypasses".
@@ -625,8 +705,10 @@ function selfTest() {
625705
`✓ check-docs-locale-catch-all --self-test: ${checked} assertions over a temp fixture (real checkApp path); `
626706
+ 'every limb -- deleted guard, guard behind the return, hollowed predicate, a new unguarded segment, '
627707
+ 'an uncompilable matcher, an OG marker stripped of its dot, an OG marker dropped, an OG url that '
628-
+ 'stopped ending in its segments, a missing builder -- observed FAILING, the proxy condition observed '
629-
+ "flipping the catch-all requirement off, and the OG marker's NAME observed free while its dot is not.",
708+
+ 'stopped ending in its segments, a missing builder, and a matcher widened until it swallows the OG '
709+
+ 'card URL with the marker untouched -- observed FAILING, the proxy condition observed flipping the '
710+
+ "catch-all requirement off WITHOUT taking the run green, the OG marker's NAME observed free while "
711+
+ 'its dot is not, and a widening that still excludes /og/ observed staying green.',
630712
);
631713
}
632714

0 commit comments

Comments
 (0)