docs(nav): stop listing "index" in meta.json pages — it detaches the folder index from the tree - #13710
Merged
os-project-manager merged 1 commit intoAug 31, 2026
Conversation
…folder index (#12352) 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 page an ordinary child and leaves the folder node with a name and no url, which degrades both surfaces built from that node: `getBreadcrumbItems()` drops the un-linkable ancestor, and the sidebar renders an inert `SidebarFolderTrigger` instead of a `SidebarFolderLink`. Removes "index" from 16 of the 17 meta.json files that listed it. content/docs/releases/ is fenced by AGENTS.md and is left untouched. Measured on the real fumadocs-core 16.14.4 loader over content/docs: short breadcrumb trails 172 -> 8 (the 8 are all under /docs/releases), and the sidebar delta is exactly 16 folder headers TRIGGER -> LINK plus 16 index children leaving the child list, with no other entry moved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
This was referenced Aug 31, 2026
os-project-manager
marked this pull request as ready for review
August 31, 2026 08:33
os-project-manager
deleted the
claude/issue-12352-meta-index-breadcrumb
branch
August 31, 2026 08:51
os-project-manager
added a commit
that referenced
this pull request
Aug 31, 2026
…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
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.
Part of #12352
Removes
"index"from thepagesarray of 16 of the 17meta.jsonfiles undercontent/docsthat list it. Producer-side only: no consumer-side URLreconstruction, in
page.tsxor anywhere else.Mechanism (fumadocs-core 16.14.4,
buildFolder()indist/loader-*.js)A folder's
index.mdxbecomes that folder's treeindexnode only while thefolder's
meta.jsondoes not list"index"inpages. Listing it makes thepage an ordinary child and then deletes the folder's index:
Two surfaces read that one node:
"index"listedgetBreadcrumbItems()links a folder crumb toitem.index?.urldocsTrail()drops itnode.index ? SidebarFolderLink : SidebarFolderTriggerRe-derived on current
origin/main(not inherited from the card)Measured by driving the real pinned
fumadocs-coreloader overcontent/docsand applying both consumers to the resulting tree.
meta.jsonfiles list"index"— unchanged from the card.production-build numbers row for row (ai 8 · api 11 · automation 9 ·
capabilities 10 · concepts 5 · data-modeling 17 · deployment 11 ·
getting-started 8 · kernel 22 · permissions 20 · plugins 4 · protocol 24 ·
releases 8 · ui 15).
/docsitself, whose trail was already complete.404 = 232 + 172against thecard's
403 = 231 + 172, so the two harnesses agree exactly.After: short trails 172 to 8. The remaining 8 are every page under
/docs/releases.Per-file decisions — checked individually, not blanket-edited
"index"was the firstpagesentry in 15 files and the first entry afterthe
---Start Here---separator ingetting-started. No file placed it betweenother entries, so no entry's position depends on it. Each edit asserted, per
file, that
pageshad exactly one"index", that the resulting array equals theoriginal minus that one element, and that no other key changed.
content/docs/releases/meta.jsonis not touched:content/docs/releases/isfenced by AGENTS.md and by this card's dispatch. It still lists
"index", whichis why this is
Part ofand not a closing reference — #12352 stays open for thatone file, and whether it should be swept in a dedicated docs-only PR is the
maintainer's call.
Sidebar — verified rendered, before and after
The ruling requires the sidebar, not only the JSON-LD. Captured from a running
dev server, with
content/docsreverted to this branch's parent commit for the"before" pass and restored from
HEADafterwards (git diff HEADempty, blobhashes back to the
HEADblobs)./docs/getting-started/glossary, sidebar entries in document order:/docs/data-modeling/objects:FOLDER-LINK | Reference | /docs/referencesrenders identically in both passes —a folder that never listed
"index", i.e. the control.Over the whole tree the delta is exactly 16 headers
TRIGGERtoLINKplus 16index children leaving the child list, and nothing else: every removed child's
URL is now its folder header's
href(set equality, checked mechanically), andno other line moved in either direction.
SidebarFolderLinkstill renders thecollapse chevron, so no section loses collapsibility.
Six of the 16 removed a child whose label was identical to the section header
(
Automation,What Can It Do?,Core Concepts,Data Modeling,Kernel & Services,Permissions & Identity) — a duplicate row, now gone. Theother ten swap the page title for the folder title on the same link:
/docs/getting-started/docs/ui/docs/plugins/docs/protocol/kernel/docs/protocol/docs/deployment/docs/kernel/runtime-services/docs/kernel/contracts/docs/ai/docs/apiNo folder is judged worse: the page stays in the sidebar at the same tree
position, one click away, and this is already how the 18 folders that never
listed
"index"render (references,protocol/objectql,protocol/objectui,…).
/docs/getting-startedis the widest label gap and is flagged for reviewrather than decided here.
Breadcrumb — rendered
BreadcrumbList, afterThe first is the card's own example, which shipped three crumbs with the section
missing. The third is the card's control: it was already linking
/docs/protocol/objectqland now also links/docs/protocol, becausecontent/docs/protocol/meta.jsonlisted"index"too.One comment-only edit outside
content/apps/docs/app/[lang]/docs/[[...slug]]/page.tsxcarries a doc comment thatstates this defect as live and quantifies it ("17 of the 35 …", "172 of 403 …").
Landing this would make that text false, so the paragraph is rewritten to the
post-fix state and to name the one folder still affected. No executable line
changes — every changed line in that file starts with
*, checkedmechanically. The ⛔ fence against reconstructing the URL consumer-side is kept
verbatim and is untouched.
Verification
At
1a5ba4fa4, the branch head:node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackderives for this change set: 42 green, 1 NOT MEASURED. The exception is
scripts/check-test-completeness.mjs, which grades a savedturbo run testlog and exits 3 with
PREREQUISITE NOT METwhen the family names it with noargument — its own header says to record it as NOT MEASURED locally. Three
gates first returned
PREREQUISITE NOT METfor unbuilt workspace packages(
@objectstack/formula,@objectstack/lint,packages/spec/json-schema) andone for a missing
@objectstack/client-reactbuild; all four were rebuilt andre-run green, and none of those first readings is reported as a result.
pnpm lint(eslint . --no-inline-config, whole repo, no narrowing) — clean.pnpm --filter @objectstack/docs run typecheck(
fumadocs-mdx && next typegen && tsc --noEmit) — clean.node scripts/check-section-landing-index.mjsgreen, and by construction: thatgate already filters
'index'out of thepagesarray it reads, so thelanding-page index blocks are unaffected.
Every exit code was captured before any pipe.
Not in scope
The inbound-links work from the sibling card of the same sweep is untouched here.
Generated by Claude Code
Generated by Claude Code