Skip to content

fix(spec): docs category index cards the pages meta.json declares (security/misc was unreachable) - #11483

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-11260-security-index-misc
Aug 23, 2026
Merged

fix(spec): docs category index cards the pages meta.json declares (security/misc was unreachable)#11483
os-steve merged 1 commit into
mainfrom
claude/issue-11260-security-index-misc

Conversation

@claude

@claudeclaudeBot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Fixes#11260

content/docs/references/security/index.mdx carded four of the five pages the meta.json beside it declares. The fifth, misc, is generated and routed in the sidebar — and unreachable from the one page whose job is to reach it.

Mechanism

Both files come out of a single gen:docs run (packages/spec/scripts/build-docs.ts), from two enumerations of "the pages of this category" that disagreed about exactly one bucket:

built from
meta.json (§2)PAGES_BY_CATEGORY — the pages the run emitted
index.mdx card grid (§2.5)categoryZodFiles — page slugs derived from the .zod.ts files on disk

misc is the catch-all where a published schema that no .zod.ts accounts for lands (security/ declares two in plain .ts files). It has no .zod.ts behind it by definition — the generator says so twice, and sourcePathFor returns undefined for it precisely so the page prints no invented "Source:" line. So it was structurally absent from the second enumeration: the card loop never considered it, which also means the wasEmitted guard that the loop's own comment leaned on never ran for it.

That comment — "This aligns the index with meta.json, which already lists only generated pages" — was wrong in the shape that reads as verified. It named the invariant while the code held it by coincidence, for the 13 categories where two independent enumerations happen to agree.

The fix, and why by construction

§2.5 now iterates the list §2 declared (categoryMetaPages, handed over the same way categoryPageSchemas is handed to the root index) and keeps the wasEmitted guard: a .zod.ts whose schemas are all unrepresentable in JSON Schema still cannot be carded into a dangling 404. Nine such slugs across four categories are still correctly excluded.

Because both files now read one list, that guard can no longer thin the grid silently. A declared page the run did not emit is collected as undelivered and stops the build naming it, rather than quietly leaving the grid one card short — which is exactly how misc was lost. The stated invariant is now true by construction, closing the class instead of special-casing misc.

The rule moved to packages/spec/scripts/lib/category-index.ts — the same extraction schema-section.ts (#7658) and format-type.ts (#4912) made, for the same reason: the generator is a top-level script with side effects, and this defect's output is an absent card, which grepping emitted .mdx cannot see.

The all-misc edge (the in-card question)

No category in the repo is all-misc — measured, security is the only one declaring misc at all, and it does so alongside four zod-derived pages. But the edge is reachable, and it was broken in two shapes, both closed here:

  1. A category with .zod.ts files whose every published schema falls to the catch-all. The old loop iterated the zod slugs, every one filtered out by wasEmitted, and emitted a literally empty <Cards> grid — an overview linking nowhere. Now it cards misc.
  2. A category with no .zod.ts files at all but published schemas (security already proves plain-.ts declarations reach the catch-all). The old if (zodFiles.size === 0) return; skipped index.mdxentirely, while §2 still wrote its meta.json and its page — a folder routed in the sidebar whose overview does not exist. The guard is now keyed off the same declared list, so meta.json exists ⟺ index.mdx exists.

An empty grid is now unreachable from a non-empty declaration, and that is asserted rather than argued: non-empty undelivered fails the run. Since no such category exists to pin it in generated output, it is covered in category-index.test.ts instead.

Regen audit

Output came from the generator (pnpm --filter @objectstack/spec gen:docs), never hand-edited. Sweeping all 14 references/* categories, git diff --stat -- content/docs is:

 content/docs/references/security/index.mdx | 1 +
1 file changed, 1 insertion(+)
 <Card href="/docs/references/security/explain" title="Explain" description="Source: packages/spec/src/security/explain.zod.ts" />
+ <Card href="/docs/references/security/misc" title="Misc" />
<Card href="/docs/references/security/permission" title="Permission" description="Source: packages/spec/src/security/permission.zod.ts" />

Exactly one card, in exactly the category the issue measured, with nodescription — correct, because misc has no source file to point at. The other 13 grids are byte-identical. Post-regen, cards == declared pages for all 14 categories (was 13/14).

Verification

Reverse verification, both legs from committed source:

  • beforecheck:docs on the unmodified generator: green, ✅ 229 generated files in sync with packages/spec, with the grid at four cards. The omission is live generator behaviour, not stale committed output.
  • aftergen:docs re-run: ✅ Generated 229 files, the one-line diff above; check:docs green again on the regenerated tree.

Green: pnpm --filter @objectstack/spec build, check:docs, check:generated (14/14 artifacts current), check:empty-state, check:liveness, check:strictness-ledger, check:variant-docs, check-section-landing-index, check-doc-frontmatter, check:doc-anchors, check:doc-authoring, check:docs-audit-scope, check:docs-redirects, check:quick-reference-counts, check:role-word, check:published-readme-links, check:published-files, check:merge-driver, check:slot-lookup, check:test-source-alias, check:type-source-resolution, check:cross-package-test-inputs, check-ci-filter-parity, check-plugin-teardown-shape, check-affected-docs, the five changeset gates, and the test-file convention family (check:query-options-erasure, check:type-check-coverage, check:engine-double-contract, check:where-matcher, check:nul-bytes). Gate list derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not recalled.

New unit test packages/spec/scripts/category-index.test.ts — 7 passing, pinning the misc shape, separator handling, alphabetical grid order (so the 13 correct grids cannot be reshuffled by a future edit), the retained wasEmitted guard, and both all-misc cases.

Full @objectstack/spec suite green after the change — 11171 passed — and pnpm --filter @objectstack/spec typecheck green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck, covering both new files). All readings are of commit 5f28297c15: the gates ran against the working tree, which git status reports identical to HEAD.

Three gates in the derived list could not be run here and are declared rather than silently skipped — all three fail on unbuilt dist/ in this worktree, before reading anything this PR touches: check-dev-prereqs.mjs (67 of 67 workspace packages have no dist/ entry point), and @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture (ERR_MODULE_NOT_FOUND on @objectstack/formula/dist/index.mjs and packages/lint/dist/index.js). check:type-check-debt is likewise unrun: its --re-measure needs the whole workspace closure built. CI runs all four on a built tree.

Scope

No packages/spec/src/** in the diff — generator plus regenerated output only, no contract acceptance change.

#10834 is a separate open finding on a different defect in this same generated index; it is untouched here and stays independent, as dispatched.

One out-of-scope finding filed while in here: #11482 — §3 builds the rootreferences/meta.json from a third enumeration (.zod.ts counts), the same class one level up. Latent, no instance in the tree, and unchanged by this PR.


Generated by Claude Code

…1260)
The generated `content/docs/references/security/index.mdx` carded four of the
five pages its own `meta.json` declares. The fifth, `misc`, was generated and
routed in the sidebar but unreachable from the category overview.
Both files come out of one `gen:docs` run from two enumerations of "the pages
of this category": `meta.json` from the pages the run emitted, the card grid
from the `.zod.ts` files on disk. `misc` is the catch-all for a published
schema no `.zod.ts` accounts for, so it has no source file by definition and
was structurally absent from the second enumeration — the card loop never
considered it, and the `wasEmitted` guard its comment leaned on never ran for
it.
The grid now iterates the list `meta.json` was built from and keeps the
`wasEmitted` guard, so a page that produced no reference file still cannot be
carded into a dangling 404 — but a declared page the run did not emit now
stops the build instead of silently thinning the grid. The invariant the
comment claimed is true by construction rather than by coincidence, which also
closes the all-`misc` category edge: it can no longer render an empty grid, and
its overview is emitted exactly when its `meta.json` is.
Regenerated output is one line: security/index.mdx gains its `misc` card, with
no "Source:" line since there is no file to point at. The other 13 category
grids are byte-identical.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9cDbY2NBiVJWYx3BpWfH2
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

@github-actionsgithub-actionsBot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 23, 2026
@os-steve
os-steve marked this pull request as ready for review August 23, 2026 22:24
@os-steve
os-steve added this pull request to the merge queueAug 23, 2026
Merged via the queue into main with commit 9fa70d7Aug 23, 2026
33 checks passed
@os-steve
os-steve deleted the claude/issue-11260-security-index-misc branch August 23, 2026 23:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(references): the generated security category index omits misc, the one page with no .zod.ts behind it

2 participants

@os-steve@claude