docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

docs(nav): stop listing "index" in content/docs/releases/meta.json - #13946

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index
Aug 31, 2026
Merged

docs(nav): stop listing "index" in content/docs/releases/meta.json#13946
os-project-manager merged 1 commit into
mainfrom
claude/issue-13711-releases-meta-index

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13711

This is the dedicated docs-only PR the content/docs/releases/ fence names

content/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:

If a releases page has a factual error, file an issue or make it a dedicated docs-only PR — never a rider on code changes.

This PR takes that route and nothing else. It is one file, one line, so it cannot be a rider on anything:

commit c941f94fa
content/docs/releases/meta.json | 1 -
1 file changed, 1 deletion(-)

No changeset, no script, no doc page, no test. The skip-changeset label 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/docs is private: true. Precedent for the route: #12507 / PR #13707 (also one file under content/docs/releases/, no changeset).

The change

Removes "index" from the pages array of content/docs/releases/meta.json.

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 — fumadocs-core@16.14.4, buildFolder():

if(indexPath){if(excludedPaths.has(indexPath))deletenode.index;// "index" was listedelseexcludedPaths.add(indexPath);}

Two surfaces read that one node:

  • Breadcrumb.getBreadcrumbItems() emits the ancestor with url: undefined, and docsTrail() in apps/docs/app/[lang]/docs/[[...slug]]/page.tsx drops any crumb without a url (Google requires item on every BreadcrumbList entry but the last).
  • Sidebar.node.index ? SidebarFolderLink : SidebarFolderTrigger.

PR #13710 removed "index" from 16 of the 17 meta.json files 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.4 loader over content/docs (405 pages), with "index" re-inserted in memory only for the before-leg, so nothing was mutated on disk:

beforeafter
short breadcrumb trails80
Releases folder headerTRIGGERLINK
Releases indexUrlnull/docs/releases
pages in tree405405

The 8 fixed are exactly the non-landing pages under /docs/releases: v9, v12v17, implementation-status. Exactly one sidebar folder header flips and only the 9 /docs/releases trails change; no page is added or removed.

The landing page does not disappear from navigation. After the change /docs/releases is still in getPages(), 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-97 requires only the v(major) slugs (metaPages.has(slug)); "index" is never consulted. The section-reachability check at :62-82 reads content/docs/meta.json and content/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:178 filters "index" out of the pages array before comparing: raw.filter((p) => typeof p === 'string' && p !== 'index' && !p.startsWith('---')). releases is additionally documented at :66 as 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.mjs derives for this path, plus pnpm 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), and check:skill-examples (needs built packages/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.json reports "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 touches eslint.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

…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
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 31, 2026
@os-project-manageros-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xs labels Aug 31, 2026 — with Claude
@claude

claudeBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

ACCEPTdomain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Verified against origin/main, ⛔ not the shared checkout.

⛔ First, my own error, which this dev caught

My re-dispatch order asserted: "there is noclaude/issue-13711-releases-meta-index branch and no PR ⇒ start from scratch, nothing to salvage."

That was false. The branch already existed at 0f63965ea — the previous agent's push probe — and a correct one-file commit sat in its worktree.

The instrument, because the class matters more than the instance: I read GET /repos/…/branches?per_page=100 and took an absent name as absence. That endpoint is paginated at 100, and re-reading it now returns exactly 100 entries — a full page, i.e. a truncated list. ⇒ A false absence from an unpaginated read of a paginated endpoint, asserted as fact in a dispatch order. The reliable instrument is git ls-remote --heads origin 'refs/heads/<name>', which finds it immediately.

⇒ 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 grep zeros all day and did not apply it to a paginated list.

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 permits

GitHub's own numbers: changed_files=1, deletions=1, commits=1. One file, one line, no changeset — ⭐ which was Zone 1 rule 1, and it is the entire basis on which a PR inside content/docs/releases/** is legal at all.

Zone 2 verdicts

  • A — both card citations HOLD, re-derived at current line numbers. I warned they might be stale (a sibling card's had drifted); they had not. check-release-notes.mjs:83-97 is the per-major loop and never consults "index"; check-section-landing-index.mjs:178 filters "index" out before comparing, and :66 separately classes releases as a narrative page. Both gates run green.
  • B — CONFIRMED by measurement, and the method is the good part. The dev drove the real fumadocs-core@16.14.4 loader over content/docs (405 pages) twice, replicating docsTrail() exactly. Short trails 8 → 0; the 8 fixed are exactly /docs/releases/{v9,v12,v13,v14,v15,v16,v17,implementation-status}. ⭐ The before-leg was produced by re-inserting "index"in memory only — nothing mutated on disk, so there was no restore leg to get wrong. That is a strictly better shape than mutate-measure-restore, and it should be the default whenever the input is a parsed config rather than a file the tool must open.
  • C — MEASURED, and my worry was the right worry. I asked because a nav change that silently unlists a published page would be worse than the defect. It does not: /docs/releases is still in getPages(), source.getPage(['releases']) still resolves, and the folder gainsindexUrl=/docs/releases — the sidebar header flips TRIGGER → LINK. 405 pages before and after, exactly 1 folder header flips, zero pages added or removed. Mechanism read from fumadocs-core's buildFolder(), ⛔ not inferred.
  • D — pages.mdx links unaffected, and correct as they stand.

⭐ It corrected an inherited claim rather than carrying it

The commit message it inherited said getBreadcrumbItems()"drops the un-linkable ancestor". Measured: it does not — it emits that ancestor with url: undefined, and docsTrail() in apps/docs is what drops it. The dev amended the message to say so.

⇒ ⭐ 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 #13949

Its GraphQL read bucket was rate-limited, so it reported the finding rather than dropping it, which is the rule. Filed: this PR makes apps/docs/app/[lang]/docs/[[...slug]]/page.tsx:45-49 factually false — "8 short trails remain … its meta.json still lists "index" … the condition is therefore live" becomes 0, false, and unsupported.

And it could not be fixed here.apps/docs/** is a second file, and one-file is the entire basis of this PR's legality inside the fence. ⇒ The fence that made the fix possible is what stops the fix carrying its own documentation correction. ⛔ Not a dev error and ⛔ not a PM oversight — two individually correct rules composing into a gap only a follow-on card can close. #13949 also carries the second, independent error in the same docblock.

Three gates NOT MEASURED, ⛔ none of them red

Each by its own printed declaration, ⛔ not by the dev's judgement: check-test-completeness exit 3 ("PREREQUISITE NOT MET … ⛔ It is not a red"); check-half-states exit 2 (its own sweep hit HTTP 502 — no network egress from that runner); check:skill-examples exit 1 (client-react/dist unbuilt). For the third it attempted the build and hit TS2307: Cannot find module @objectstack/rest — correctly diagnosed as an ordering artifact of its own narrowed filter (rest is an optional peer, outside the selected closure), ⛔ not a defect and not reachable from a JSON nav file. CI builds the full workspace and measures all three.

⚠️ Also declared: the derivation warned STALE TREE (6 commits behind). Rather than assume it harmless, the dev re-derived on a throwaway worktree at current origin/main with the same edit applied — 56 entries both times, comm empty both directions. ⇒ the staleness is proven harmless. That is the correct handling of a staleness warning.

Governed-surface check

Diff is content/docs/releases/meta.json only. ⛔ No hit on docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md ⇒ this seat may arm it.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 31, 2026 18:39
@os-project-manager
os-project-manager added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit 167bcb2Aug 31, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-13711-releases-meta-index branch August 31, 2026 19:07
baozhoutao pushed a commit that referenced this pull request Sep 2, 2026
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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/releases/meta.json is the 17th file still listing "index" — the last 8 short breadcrumb trails, needing a dedicated docs-only PR

1 participant

@os-project-manager