Uh oh!
There was an error while loading. Please reload this page.
feat(scripts): hold every section landing index to its meta.json, and top up the two drifted ones - #11259
Merged
Merged
Conversation
#10738) Adds check-section-landing-index.mjs. A section's meta.json is the routing source fumadocs builds the sidebar from; the landing page's "## What's in this module" block is hand-kept beside it and nothing read the two against each other, so it drifted in both directions one edit at a time with every gate green (#9604 runtime-services, #10339 permissions, #10737 ai). The heading is the opt-in, not the rendering shape: 8 sections declare it, 4 as bullet lists and 4 as Card grids, and the gate reads both identically. 26 landing pages that declare no index block are not held. Committed before the docs fixes so the red is reproducible at this commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPBxLsqQGCVL5z5UXvgipH
…gate into lint.yml (#10738) content/docs/ui/index.mdx omitted react-pages, actions, reports and translations, and listed views before pages. The react-pages omission is the residual half of the P0 #10638 symptom: the deploy fix restored the page and the sidebar, but the hand-kept grid never got its row, so objectstack.ai/docs/ui still does not show React Pages. content/docs/data-modeling/index.mdx omitted field-type-decision-tree and validation-rules — a second real drift, found by the gate, outside the population the card had measured. permissions/index.mdx's drift note said nothing checks the two against each other; that is no longer true, so it now names the gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPBxLsqQGCVL5z5UXvgipH
This was referenced Aug 23, 2026
os-zhuang
marked this pull request as ready for review
August 23, 2026 07:57
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#10738
Adds
scripts/check-section-landing-index.mjsand repairs the two landing pages it found drifted.The population is 8, not 3 or 4 — and the discriminator is the heading, not the shape
The card measured 3, corrected itself to 4, and left open whether the
Cards-grid sections were covered, noting thatapi/index.mdxcarries both shapes so the two categories "cannot be treated as disjoint". Re-measured onorigin/mainunder the card's own stated parse method, shape is simply the wrong discriminator. The right one is the heading itself: writing## What's in this moduleis the author declaring "this block is the index of this module".Exactly 8 sections declare it, in one spelling (ASCII apostrophe, no
in this chapter/in this sectionvariant anywhere undercontent/docs, and no non-indexpage carries it):aiapiautomationdata-modelingkernelpermissionspluginsuiThe other 26 landing pages under
content/docsdeclare no index block and are not held. That is what keeps the deliberately curated ones curated —protocol/objectui's "For Implementers" reading list mixing in/docs/references/links,getting-started's "Next Steps" pointing out of its module, and the narrativeconcepts/protocol/protocol/kernelpages. None can be caught by accident; they would have to write the heading first.One strength, not two
The dispatch suggested two strengths — set-and-order for the bullet lists, coverage-only for the grids. Measurement beat it: order already holds on 7 of the 8, and the eighth is
ui, the page this gate was written for. So set and order holds for all 8, both shapes read identically, and no shape-dependent branch exists to get wrong.Out-of-section links are ignored entirely, never counted and never ordered. That clause is what lets an editorially curated block stay curated:
ai,api,permissionsandpluginseach close their block with cross-references into/docs/protocol/and/docs/references/, and all four are green.Hrefs only. Link text, glosses, bolding and
Carddescriptions stay hand-written, becausemeta.jsonstores slugs only — a generated block would synthesize link text from frontmatter and regress a row that exists today (permissions/access-recipes.mdxis titled "Who can see data / automation / interface" and would render as that instead of the curated "Access Recipes"). Check them, don't generate them — the #9604 precedent, re-measured.The
uiomission is a live customer-visible symptomcontent/docs/ui/index.mdxomittedreact-pages,actions,reportsandtranslations, and listedviewsbeforepages. Thereact-pagesrow is the residual half of the P0 #10638 report — "https://objectstack.ai/docs/uidoes not show the React Pages entry". That card's deploy half already landed: the page serves andreact-pagesis in the sidebar payload. What was still missing in production is its row on the landing page, because the hand-kept grid never got one.Demonstrated red, not a belief
Same command, same real tree, before and after the docs commit:
The gate is committed before the docs fixes on purpose, so that red is reproducible at
f5a52e13b.--self-testadds 31 assertions over the realjudge()/run()path: both shapes in sync, missing page, undeclared row, wrong order, the pre-fixuigrid reproduced, foreign-link curation,###sub-heading vs same-level heading, fence and MDX-comment masking,index/---Group---filtering, opt-in skipping, and all seven refusals.Refusing rather than passing
This gate computes its own population, so a parser that stopped matching would print a confident green over a tree it never read (#4690's family). Seven refusals close that: empty index block, a
meta.jsonpage with no file on disk (reported as ameta.jsondefect, not an index defect — the set rule would otherwise order an author to link a dead route), unparseablemeta.json, nopagesarray, unreadable section, empty census, and a census belowEXPECTED_MIN_SECTIONS.content/docs/data-modeling/index.mdxThe dispatch surface named
content/docs/{permissions,api,ai,plugins,ui}/index.mdx.data-modelingwas not on it, because at dispatch time nobody knew it was in the population — it was one of the nineCardssections the card had set aside. The gate found it drifted by two real pages (field-type-decision-tree,validation-rules, both real.mdxfiles), so leaving it would have shipped a gate red onmain.Taken as a bounded in-place fix: same defect class as this card, mechanical with the correct form pinned by
meta.json, no other claim on the file (7 open PRs checked by file list — only #11244 touchescontent/docs, atui/pages.mdx, noindex.mdxand nometa.json), and the same gate family with no new verification surface. Weakening the gate to exclude it was the alternative and was rejected: a baseline written to make CI green is the defect this class is about.content/docs/permissions/index.mdxalso loses its drift note, which said "nothing checks the two against each other in either direction" — no longer true, so it now names the gate instead.Wiring
A direct
node scripts/…step inlint.ymlwith no rootpackage.jsonalias, on the #9465 fence precedent set by PR #10698.dispatch-gates.mjsderives gate families from either spelling and discovers it:node scripts/check-section-landing-index.mjs [lint.yml]. Self-test first, then the gate — the dominant sanctioned shape, and explicitly not the multi-script patterncheck:step-collectorsflags.No changeset: the diff touches
scripts/,.github/workflows/lint.ymlandcontent/docs/**only.@objectstack/docsisprivate: trueandcontent/docssits in no package, so nothing publishes. Labelledskip-changeset.Verification
All gates below run at
28d591a68, the final commit, and every verdict is the gate's own printed line.check:entry-guard·check:parse-guardcheck:doc-anchors·check:doc-authoring·check:doc-frontmattercheck:docs-audit-scope·check:docs-redirects·check:published-readme-links·check:role-wordcheck:node-version·check:required-contexts·check:shard-attestation·check:pnpm-filter-targets·check:workflow-status-functionscheck:cross-package-test-inputs·check:aggregator-roster·check:ci-filter-parity·check:step-collectors(+ self-test)check:empty-state·check:liveness·check:strictness-ledger·check:variant-docscheck:doc-formula-expressions·check:doc-security-posturecheck:nul-bytesOK (scanned 6528 text file(s) … no raw ASCII control bytes)check:type-check-coverageOK — 65/78 workspace packages type-checkedcheck:type-check-debt33 ledger entr(ies) re-measured in 225.0s, 1897 raw tsc error(s) total, none above its recorded number(workspace closure built first:72 successful, 72 total)node scripts/check-section-landing-index.mjs(+ self-test)pnpm turbo run buildalso compiled@objectstack/docs:✓ Compiled successfully in 71s,✓ Generating static pages (1220/1220)— the edited MDX parses and its routes resolve.ESLint — declared narrowing, measured not skipped. Full-repo
pnpm lintwas attempted under the shared verify lock and diedexit 134, a V8 heap OOM at--max-old-space-size=4096with two sibling agents holding heavy work; that is a resource verdict, not a lint verdict. The narrowing is proven on three readings:ESLint#isPathIgnoredovergit ls-files, not a guess): 4899 of 6533 tracked files.--format json: 5 changed files,errorCount: 0. Exactly one —scripts/check-section-landing-index.mjs— is in the population (E0 W0); the other four are config-ignored, their single warning apiece being ESLint's own "file ignored" notice, not a finding.eslint.config.mjswhich "never enables type-aware linting (noparserOptions.project, no typed@typescript-eslintrules) for ANY file" — its own words, backed by its own planted positive control — and this diff changes no ESLint config. Each file's verdict therefore depends only on that file plus config, so nothing in this diff can move the verdict of any of the 4898 untouched in-population files.CI runs the full farm regardless.
Generated by Claude Code