Uh oh!
There was an error while loading. Please reload this page.
fix(spec): docs category index cards the pages meta.json declares (security/misc was unreachable) - #11483
Merged
Merged
Conversation
…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
Contributor
📓 Docs Drift CheckNothing 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. |
os-steve
marked this pull request as ready for review
August 23, 2026 22:24
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#11260
content/docs/references/security/index.mdxcarded four of the five pages themeta.jsonbeside 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:docsrun (packages/spec/scripts/build-docs.ts), from two enumerations of "the pages of this category" that disagreed about exactly one bucket:meta.json(§2)PAGES_BY_CATEGORY— the pages the run emittedindex.mdxcard grid (§2.5)categoryZodFiles— page slugs derived from the.zod.tsfiles on diskmiscis the catch-all where a published schema that no.zod.tsaccounts for lands (security/declares two in plain.tsfiles). It has no.zod.tsbehind it by definition — the generator says so twice, andsourcePathForreturnsundefinedfor 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 thewasEmittedguard 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 waycategoryPageSchemasis handed to the root index) and keeps thewasEmittedguard: a.zod.tswhose 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
undeliveredand stops the build naming it, rather than quietly leaving the grid one card short — which is exactly howmiscwas lost. The stated invariant is now true by construction, closing the class instead of special-casingmisc.The rule moved to
packages/spec/scripts/lib/category-index.ts— the same extractionschema-section.ts(#7658) andformat-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.mdxcannot see.The all-
miscedge (the in-card question)No category in the repo is all-
misc— measured,securityis the only one declaringmiscat 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:.zod.tsfiles whose every published schema falls to the catch-all. The old loop iterated the zod slugs, every one filtered out bywasEmitted, and emitted a literally empty<Cards>grid — an overview linking nowhere. Now it cardsmisc..zod.tsfiles at all but published schemas (securityalready proves plain-.tsdeclarations reach the catch-all). The oldif (zodFiles.size === 0) return;skippedindex.mdxentirely, while §2 still wrote itsmeta.jsonand its page — a folder routed in the sidebar whose overview does not exist. The guard is now keyed off the same declared list, someta.jsonexists ⟺index.mdxexists.An empty grid is now unreachable from a non-empty declaration, and that is asserted rather than argued: non-empty
undeliveredfails the run. Since no such category exists to pin it in generated output, it is covered incategory-index.test.tsinstead.Regen audit
Output came from the generator (
pnpm --filter @objectstack/spec gen:docs), never hand-edited. Sweeping all 14references/*categories,git diff --stat -- content/docsis:<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 no
description— correct, becausemischas 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:
check:docson 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.gen:docsre-run:✅ Generated 229 files, the one-line diff above;check:docsgreen 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 withnode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not recalled.New unit test
packages/spec/scripts/category-index.test.ts— 7 passing, pinning themiscshape, separator handling, alphabetical grid order (so the 13 correct grids cannot be reshuffled by a future edit), the retainedwasEmittedguard, and both all-misccases.Full
@objectstack/specsuite green after the change — 11171 passed — andpnpm --filter @objectstack/spec typecheckgreen (tsc --noEmit+check:scripts-typecheck+check:test-typecheck, covering both new files). All readings are of commit5f28297c15: the gates ran against the working tree, whichgit statusreports identical toHEAD.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 nodist/entry point), and@objectstack/lint'scheck:doc-formula-expressionsandcheck:doc-security-posture(ERR_MODULE_NOT_FOUNDon@objectstack/formula/dist/index.mjsandpackages/lint/dist/index.js).check:type-check-debtis likewise unrun: its--re-measureneeds 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.#10834is 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.jsonfrom a third enumeration (.zod.tscounts), the same class one level up. Latent, no instance in the tree, and unchanged by this PR.Generated by Claude Code