diff --git a/scripts/validate-nav-and-redirects.mjs b/scripts/validate-nav-and-redirects.mjs index dc01a3f..54d02e2 100644 --- a/scripts/validate-nav-and-redirects.mjs +++ b/scripts/validate-nav-and-redirects.mjs @@ -115,7 +115,35 @@ function main() { } } - // --- 3. Nav entries with no file behind them --- + // --- 3. A page file sitting beside a directory of the same name --- + // + // `jobs/compose.mdx` next to `jobs/compose/` shipped on 2026-09-24 and broke + // EVERY page under that directory in production: all 24 children served the + // parent's content. The sitemap and llms.txt listed them, so the build saw + // them; only the routing collapsed. `mint dev` does not reproduce it, which + // is why it reached the live site. + // + // The working shape is `/index.mdx`, which is what `storage/` and + // `automation/` already use. `/docs/` still serves it, so no URL moves. + for (const slug of [...pageSlugs].sort()) { + const asDir = join(ROOT, slug); + let isDir = false; + try { + isDir = statSync(asDir).isDirectory(); + } catch { + // No directory of that name: nothing to collide with. + } + if (isDir) { + violations.push( + `"${slug}.mdx" sits beside the directory "${slug}/". On Mintlify's production build ` + + `every page under that directory serves "${slug}" instead of its own content, and ` + + `\`mint dev\` does not reproduce it. Move it to "${slug}/index.mdx" and list that ` + + `as the group's first page (see storage/index and automation/index).` + ); + } + } + + // --- 4. Nav entries with no file behind them --- for (const slug of [...navSlugs].sort()) { if (!pageSlugs.has(slug)) { violations.push(`Navigation lists "${slug}", but no matching .md/.mdx file exists.`);