Uh oh!
There was an error while loading. Please reload this page.
docs(permissions): list the six module pages the landing index omitted - #10736
Conversation
#10339) `content/docs/permissions/meta.json` ships 21 pages; the "What's in this module" list in `index.mdx` named 14 of them. The six absent pages — system-context, delegated-administration, rls, attachments-access, access-matrix, explain — were routed and in the sidebar, and two were even described in the overview prose without a link, so nothing was unreachable. What was wrong is that the one list presenting itself as the module's index was a partial one with nothing marking it partial. Each new row is placed at its meta.json position rather than appended: the existing 14 were already exactly meta.json's order minus the six, so the order is derived, not invented. Link text is each page's own title (the card body's "Access Matrix" and "Explain" are slug prettifications; the pages are titled "Access-Matrix Snapshot Gate" and "Explain Engine"). Three of the six carry a gloss, matching the existing texture where a gloss is the exception reserved for a title that under-describes its page. Answers the card's option (b): the list stays hand-kept, with a comment naming meta.json as the source of truth and a one-line drift note. meta.json stores slugs only, so a derived list would have to synthesize link text from page frontmatter — which measurably regresses at least one existing row, and loses hand-written glosses that exist in no source file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
PM review + ruling — verified against both files and the sibling pages, not the report. Approving. ⏳ Arming deferred: GraphQL exhausted (0/5000, resets ~10:13Z). ⛔ Not reaching for The reconciliation is the proof, and it is completeDistinct pages linked 14 → 20, missing set 6 → 0, extras 0 → 0, list order still equals That last clause matters. "20 of 21" invites someone to file a follow-up for the missing one. ⭐ You corrected the card, and I checked all three correctionsThe card names two of the six rows "Access Matrix" and "Explain". Those are slug prettifications, not titles:
Using each page's own title instead is right, and it is the kind of thing that would have shipped wrong from a card read literally. And the same check is what kills option C. Ruling on (b): A — hand-kept, as you shipped it. C is ruled out on evidence.Placement derived rather than appended (the existing 14 were exactly ⭐ The precedent check, which corrects my framingI offered you a binary: derive it, or leave a comment. You read #9604 and found it did neither exactly — it topped up by hand and added One correction to your reasoning on B, in its favour. You note B needs "a root package.json I agree it is a maintainer call at three pages, and I have filed it as its own card with your population measurement, the #9604 precedent, and that fence correction — so it reaches someone who can decide rather than sitting in a PR comment. Not shipping it here was right. Reported rather than hiddenTwo self-inflicted flag errors — The separator inconsistency (1 em dash, 2 hyphens among the three pre-existing glossed rows) — new rows use the em dash to match the page's prose and the sibling And the dismissals are the part I want to name: #10737 correctly filed and correctly labelled. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Closes#10339
What was wrong
content/docs/permissions/meta.jsonships 21 pages. The "What's in this module" list inindex.mdxnamed 14 of them. The six absent pages were routed, in the sidebar, and two of them (rls,delegated-administration) were even described in the overview prose without a link — so nothing was unreachable. The defect is narrower and worth stating exactly: the one list on the page that presents itself as the module's index was a partial one, with nothing marking it partial.The reconciliation (this is the proof, not "I added six rows")
Both files parsed, before and after, by the same script:
meta.jsonpages.mdx)meta.jsonvs disk symmetric difference[][]indexexcluded)system-context,delegated-administration,rls,attachments-access,access-matrix,explain[]meta.jsonmeta.jsonorder20 rather than 21 is correct:
indexis the landing page itself and is not self-linked.How the six were written
Placement is derived, not invented. The existing 14 were already exactly
meta.json's order minus the six, so each new row goes at itsmeta.jsonposition rather than being appended. That is the same convention the sibling change in #9604 used, and it is why the order row above still readstrueafter the edit.Link text is each page's own title. Worth flagging for the reviewer: the card body names the last two "Access Matrix" and "Explain", which are slug prettifications — the pages are actually titled Access-Matrix Snapshot Gate and Explain Engine. Using the slug-derived names would have made two of six rows point at pages whose headings do not match the link the reader clicked.
Three of six carry a gloss, three do not — matching the existing texture, where a gloss is the exception (3 of 14) reserved for a title that under-describes its page.
Delegated Administration,Row-Level Security (RLS)andAttachments Accessare self-carrying, exactly like the bareSharing Rules/Field-Level Security/Permission Setsrows.System Context (isSystem),Access-Matrix Snapshot GateandExplain Engineare not, so each got one.Separator. The three existing glossed rows are inconsistent (one em dash, two hyphens — mixed inside a single commit). New rows use the em dash: it is what the page's own prose uses for this construction throughout, it is what the sibling
ai/index.mdxmodule list uses uniformly for all seven of its glosses, and a hyphen reads as a compound-word connector after titles that already contain hyphens ("Access-Matrix Snapshot Gate - the committed…"). The two existing hyphen rows were left alone rather than churned — noted here rather than fixed, since separator style is not this card's defect class.Answering the card's option (b): the list stays hand-kept
The card asked whether the two lists should be related mechanically at all. Ruling: leave it hand-kept, with the source-of-truth comment and drift note now in the file. Three reasons, in order of weight:
meta.jsoncannot supply what the list carries. It stores slugs only — no titles, no descriptions. A derived list must synthesize link text from each page's frontmattertitle, and that measurably regresses an existing row today:access-recipesis titled "Who can see data / automation / interface" and would render as that instead of the curated "Access Recipes". The glosses exist in no source file at all; the frontmatterdescriptionfields are long SEO sentences, wrong in both length and voice for a landing list. Deriving would trade a hand-written index for a worse-reading generated one.meta.jsonis routing. They restate one fact — the page set — but the list is not a second copy of only that fact.meta.jsonis routing config; changing how the page is built is a bigger change than a docs card, and the mechanical wiring a checker needs (a rootpackage.jsoncheck:entry) sits inside the Migrate the release toolchain to @changesets/cli v3 — one atomic PR carrying the bump, the pre-mode restructure, and the gates that model v2's semantics #9465 epic fence. So it is reported below as a proposal, not shipped here.What the precedent actually says.#9604 is the same class one section over, and it is worth reading closely: it did not derive its list either. It topped the list up by hand and added a checker (
pnpm check:runtime-services-index) holding the hand-written list tometa.json. So the precedent's answer to "should these be related mechanically" is check them, don't generate them — which preserves the hand-written layer while closing the drift in both directions. That is the right long-term shape here too, and it is the proposal below rather than a rider on this PR.Proposal (not shipped here): generalize the precedent's checker
scripts/check-runtime-services-index.mjsis ~1000 lines and bespoke toruntime-services(it also checks stability labels, registry slots and canonical-source rows), so it is not a parameterization away from coveringpermissions. The generalizable core is small: for every section landing page that carries a## What's in this modulebullet list, hold the set and order of that list to the directory'smeta.json. Measured against the tree today, exactly two sections have such a list and are in sync (permissionsafter this PR, andapi), and one has drifted — see the finding below. A gate that small would have caught this card's defect on the PR that introduced it, and would catch the reverse direction (a row for a page that was deleted) which nothing catches today.Sweep of other sections — one real instance, and two false positives worth naming
The card left "do other section index pages have the same gap" uninvestigated. Measured read-only across
content/docs, without widening this PR's diff:ui,automation,capabilities,data-modeling,kernel,protocol,protocol/objectql,protocol/kernel,concepts) present their pages through a<Cards>component, not a hand-written bullet list. Different object — no claim made about them.getting-startedandprotocol/objectui. Both are false positives, and I checked rather than filed:getting-started's bullet list is a "Next Steps" pointer list that deliberately links out of the module, andprotocol/objectui's is a curated "For Implementers" reading list mixing in/docs/references/links. Neither presents itself as the module's index.ai/index.mdxis the one genuine instance: a literal## What's in this modulelist, 7 of its 8 content pages present,connect-mcpabsent and linked nowhere else on the page — and it ismeta.json's first content page, not a recently-added tail entry. Filed unassigned as afinding, not fixed here.Verification
Gate family re-derived at the final commit with
node scripts/pm/dispatch-gates.mjs(no paths — the script takes its own change set from the merge base). It reports one changed path,content/docs/permissions/index.mdx, and 13 families. All 13 green atc8e5a560db, each self-test included where the gate has one:check:doc-anchors·check:doc-authoring·check:docs-redirects·check:role-word·check:docs-audit-scope·check:published-readme-links·check:cross-package-test-inputs·check:doc-formula-expressions· speccheck:empty-state/check:liveness/check:strictness-ledger/check:variant-docs·check:nul-bytesThe load-bearing one is
check:doc-anchors, since this PR adds six internal links:✅ check-doc-anchors: 272 internal #fragment link(s) across 408 source file(s) all resolve to a real heading. Andcheck:role-wordmatters because ADR-0090 D3 makes "role" reserved and this file is baselined at 1 occurrence:check-role-word: OK, no new occurrences of the reserved word.One gate needed a fix that was not about this diff:
check:doc-formula-expressionsfailedERR_MODULE_NOT_FOUNDon@objectstack/formula/dist— a fresh worktree with an unbuilt dependency closure, not a defect in the change. Green afterpnpm --filter '@objectstack/formula...' build.No changeset
Docs-only;
@objectstack/docspublishes nothing. Carries theskip-changesetlabel instead.Generated by Claude Code