Reject a dotted page slug in the locale-surface gate - #215
Merged
Conversation
middleware.ts's matcher exempts any path containing a dot, unanchored, so it also skips the locale rewrite for a docs page whose SLUG (not just an asset extension) has a dot in it. Because hideLocale is 'default-locale', that rewrite is what maps the unprefixed public URL onto the internal /en/... route -- skip it and the page builds, prerenders, and is advertised correctly everywhere, then 404s at its own public URL while every other locale still serves it fine (#208). Per the PM's adjudication on #208 (and #209's measurement that the matcher exemption has no other live consequence), this does not touch middleware.ts. Instead check-locale-surface.mjs now asserts, as a pure function of content/docs/, that no page's derived slug contains a dot -- converting the silent 404 into a build-time failure that names the offending file. The new dottedSlugPages() reuses the same page path readDocsPages() already derives for the sitemap/llms oracle, which strips the locale suffix (quickstart.zh-Hans.mdx -> docs/quickstart) before building that path -- so a real translated file never trips it, only a dot that survives into the derived URL segment does. Self-test fixtures: one red case (a dotted slug) and one explicit green case naming the #208 trap directly (a real locale-suffixed filename). Verdict counts move from 16 case(s)/9 rule(s)/3 artifact(s) to 18 case(s)/10 rule(s)/3 artifact(s). Fixes #208
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 #208
What
middleware.ts's matcher exempts.*\..*, unanchored, so it skips thelocale rewrite for any path with a dot anywhere — not just an asset path.
Because
hideLocale: 'default-locale'makes that rewrite the thing that mapsan English page's unprefixed public URL onto the internal
/en/...route, adocs page whose slug contains a dot would build, prerender, and be advertised
correctly everywhere, then 404 at its own public URL while every other
locale (which doesn't depend on the rewrite) still served it fine.
Per the grading comment on #208, and #209's measurement that the matcher's
dot exemption has no other live consequence, this does not touch
middleware.ts— the four generated artifacts and every.mdxroute dependon that exemption today, and a regression there would be caught by nothing.
middleware.tsis unmodified in this PR.Instead,
.github/scripts/check-locale-surface.mjsnow asserts, as a purefunction of
content/docs/, that no page's derived slug contains a dot —turning the silent 404-at-your-own-URL into a build-time failure that names
the offending file.
How
New
dottedSlugPages()reuses the same pagepathstringreadDocsPages()already derives for the sitemap/llms oracle — which strips the locale suffix
(
quickstart.zh-Hans.mdx→docs/quickstart) before building that path — soa real translated file never trips the new rule; only a dot that survives
into the derived URL segment does. New rule
dotted-slugis wired intoevaluate()next to the existingtranslation-orphancheck (also a purecontent-tree assertion, no build output needed), and the success/verdict
lines are extended in place rather than a new format being printed alongside.
Self-test fixtures (
--self-test)page slug contains a dot (the #208 shape)— a page with onlyprobe.dotted.mdxfires exactlydotted-slug(sitemap/llms bodies in thefixture are extended to match so this case isolates to the new rule alone).
a real locale-suffixed filename does not trip the dotted-slug rule—quickstart.mdx+quickstart.zh-Hans.mdx, the exact shape namedin the card, fires nothing.
Verdict counts move from
16 case(s) over 9 rule(s) and 3 artifact(s)to18 case(s) over 10 rule(s) and 3 artifact(s).Verification
pnpm turbo run type-check— pass.pnpm turbo run build— pass (996 pages generated).pnpm turbo run test(--force) — pass, 3 self-tests, locale-surface at18/10/3 above.
node .github/scripts/check-locale-surface.mjson the unmodified tree —exit 0, 79 logical pages / 335 docs entries, zh-Hans at 62 (matches the
card's "62 existing translated files").
content/docs/probe.dotted.mdx, rebuilt, ran the gate —exit 1, naming
docs/probe.dotted has a dot in its slug (content/docs/probe.dotted.mdx). Removed the probe file —git status --shortshows only the gate script modified. Rebuilt again — gate back toexit 0.
(
content/docs/operate/upgrade.zh-Hans.mdx) is part of every clean gaterun above and does not trip the new rule.
File surface:
.github/scripts/check-locale-surface.mjsonly, as scoped.middleware.tsuntouched.Generated by Claude Code