Uh oh!
There was an error while loading. Please reload this page.
docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946
Conversation
…13711) Fumadocs attaches a folder's index.mdx as that folder's tree `index` node only when the folder's meta.json does NOT list "index" in `pages`. Listing it makes the landing page an ordinary child and leaves the folder node with a name and no url. In fumadocs-core 16.14.4 `buildFolder()`: if (indexPath) { if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed else excludedPaths.add(indexPath); } `getBreadcrumbItems()` still emits that ancestor, but with `url: undefined`, and `docsTrail()` in apps/docs drops any crumb without a url (Google requires `item` on every BreadcrumbList entry but the last). The sidebar reads the same node as `node.index ? SidebarFolderLink : SidebarFolderTrigger`. Measured on the real loader over content/docs (405 pages), removing this one line and changing nothing else: - short breadcrumb trails 8 -> 0; the 8 fixed are exactly the non-landing pages under /docs/releases (v9, v12..v17, implementation-status) - the Releases folder header goes TRIGGER -> LINK, indexUrl /docs/releases - /docs/releases stays in getPages() and source.getPage(['releases']) still resolves -- the landing page is not unlisted, it becomes the section link - 405 pages before and after; exactly one sidebar folder header flips and only the 9 /docs/releases trails change This was the 17th and last meta.json still listing it; the other 16 were fixed in #13710, which left this one alone because content/docs/releases/ is fenced by AGENTS.md. This is the dedicated docs-only PR that fence names as the route. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
ACCEPT — ⛔ First, my own error, which this dev caughtMy re-dispatch order asserted: "there is no That was false. The branch already existed at ⭐ The instrument, because the class matters more than the instance: I read ⇒ Same family as every other instrument failure this lane has recorded today: an absence is not a reading until the instrument is known to be able to report presence. I have been applying that rule to ⛔ Harmless here only by luck: the dev's commit parent was the remote tip, so the push was a plain fast-forward and no force was needed. Nothing was lost, and it re-verified the inherited commit independently rather than trusting it. The deliverable is exactly the size the fence permitsGitHub's own numbers: Zone 2 verdicts
⭐ It corrected an inherited claim rather than carrying itThe commit message it inherited said ⇒ ⭐ That is a misattribution that would send a debugger into a third-party library instead of the file they already have open. Catching it inside a one-line docs PR is the kind of thing that only happens when a dev reads what it inherited instead of shipping it. The finding it could not file — filed for it as #13949Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes ⭐ And it could not be fixed here. Three gates NOT MEASURED, ⛔ none of them redEach by its own printed declaration, ⛔ not by the dev's judgement:
Governed-surface checkDiff is Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
The census paragraph on origin/main still claimed "8 short trails remain" and that content/docs/releases/meta.json "still lists index" — both went false when PR #13946 removed "index" from that meta.json (0 hits repo-wide now under content/docs/**/meta.json). Rewrite it to the mechanism only (how a URL-less ancestor arises, that #12352/#13946 fixed every known instance, and that the condition is structural and can recur) rather than a count that rotted within a day. Also fixes an independent misattribution in the same paragraph: getBreadcrumbItems() does not drop the URL-less ancestor itself — it emits it with url: undefined. The drop is local, in docsTrail()'s own loop guard (`if (... || !item.url) continue;`). No behavior change: docsTrail(), the breadcrumb loop, and the "missing URL is deliberately not reconstructed" rule paragraph are untouched.
Fixes#13711
This is the dedicated docs-only PR the
content/docs/releases/fence namescontent/docs/releases/**is fenced unconditionally by AGENTS.md and CLAUDE.md — never edit it in a code PR. That fence names its own escape hatch, verbatim:This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:
No changeset, no script, no doc page, no test. The
skip-changesetlabel carries the "this PR declares no release of its own" declaration, which is what keeps the diff at one file —content/docs/**belongs to no publishable package, and@objectstack/docsisprivate: true. Precedent for the route: #12507 / PR #13707 (also one file undercontent/docs/releases/, no changeset).The change
Removes
"index"from thepagesarray ofcontent/docs/releases/meta.json.Fumadocs attaches a folder's
index.mdxas that folder's treeindexnode only when the folder'smeta.jsondoes not list"index"inpages. Listing it makes the landing page an ordinary child and leaves the folder node with a name and no url —fumadocs-core@16.14.4,buildFolder():Two surfaces read that one node:
getBreadcrumbItems()emits the ancestor withurl: undefined, anddocsTrail()inapps/docs/app/[lang]/docs/[[...slug]]/page.tsxdrops any crumb without a url (Google requiresitemon everyBreadcrumbListentry but the last).node.index ? SidebarFolderLink : SidebarFolderTrigger.PR #13710 removed
"index"from 16 of the 17meta.jsonfiles that listed it, taking short trails 172 → 8. This file is the 17th, left alone then precisely because of the fence.Measured, not asserted
Driven through the real
fumadocs-core@16.14.4loader overcontent/docs(405 pages), with"index"re-inserted in memory only for the before-leg, so nothing was mutated on disk:TRIGGERLINKindexUrlnull/docs/releasesThe 8 fixed are exactly the non-landing pages under
/docs/releases:v9,v12–v17,implementation-status. Exactly one sidebar folder header flips and only the 9/docs/releasestrails change; no page is added or removed.The landing page does not disappear from navigation. After the change
/docs/releasesis still ingetPages(),source.getPage(['releases'])still resolves, and the page becomes the section header's own link rather than a child beneath a label identical to it. This was checked explicitly because a nav change that silently unlisted a published page would be worse than the defect being fixed.Gates
Both gates that read this file were re-derived at their current line numbers and run:
scripts/check-release-notes.mjs:83-97requires only thev(major)slugs (metaPages.has(slug));"index"is never consulted. The section-reachability check at:62-82readscontent/docs/meta.jsonandcontent/docs/index.mdx, not this file. →check-release-notes: OK — every released major has a curated, navigable release page.scripts/check-section-landing-index.mjs:178filters"index"out of thepagesarray before comparing:raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')).releasesis additionally documented at:66as a narrative page, not an index, so it is in the not-held set either way. →✓ check-section-landing-index: 8 section index block(s) enumerate their meta.json pages, in order, both directions; 26 landing page(s) of 34 declare no index block and are not held.39 gate commands run in total, covering the family
node scripts/pm/dispatch-gates.mjsderives for this path, pluspnpm check:ratchet-remedy-authority(which path derivation cannot name, #13813). All green except three that measured nothing and report so themselves:check-test-completeness(exit 3,PREREQUISITE NOT MET— it grades a saved turbo log),check-half-states(HTTP 502, no network egress from this runner), andcheck:skill-examples(needs builtpackages/client-react/dist.d.ts). CI measures all three.ESLint is narrowed to the changed file on its own evidence:
eslint --format json content/docs/releases/meta.jsonreports"File ignored because no matching configuration was supplied."— the file is outside ESLint's population by ESLint's own config resolution, and nothing in this diff toucheseslint.config.mjs, so no untouched file's verdict can move.Not closed by this PR
#12352 remains open and is another dispatch's to close — the unlock scan handles it.
Generated by Claude Code
Generated by Claude Code