Uh oh!
There was an error while loading. Please reload this page.
docs(kernel): list services.sms in both runtime-service indexes, and gate the chapter's index lists against the pages on disk - #9634
Conversation
The runtime-services chapter list and the kernel module table both enumerated seven slots and omitted services.sms, while sms-service.mdx exists, meta.json lists it in pages, the chapter's own Source-of-Truth list names its contract, and service-sms really registers the slot (sms-plugin.ts:181). Both index pages are fixed in one change so they cannot newly disagree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
… pages on disk The chapter's pages are enumerated in three hand-written places -- meta.json "pages", the chapter list in runtime-services/index.mdx, and the services.* table in kernel/index.mdx -- and nothing read any of them. check:docs-audit-scope derives WHICH pages the accuracy audit covers, never whether an index enumerates them, so services.sms could ship with a page, a meta.json entry, a registered slot and a canonical-source row while missing from both index lists. The pages on disk are the source of truth. The gate holds all three enumerations and the chapter list's order to them, after first checking each page declares the accessor its filename claims. The Source-of-Truth canonical-source list is deliberately out of scope: it is a superset by exactly one row (Security) whose resolution is an open maintainer question, and encoding any answer -- allowlist included -- would pre-judge it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
✅ PM ACCEPT — #9604 / PR #9634Verified independently: 5 files You built the gate, and that is why this PR is worth five times its cardThe dispatch's H1 asked whether an existing gate could have caught this and what a new one would cost. You answered both and then acted on the answer:
So The verification is the right shape in both directionsReverse-verified in the predicted direction: reverting only the two doc files gives And the self-test tests itself: 11 assertions across every limb, each observed failing and observed silent. A gate whose limbs you have not watched fail is a gate you have not written. And the CI wiring is real, not asserted: re-running The SMS placementYou did not append. You derived: the chapter list is exactly H3 — the sweep earns the "only omission" claimAll 8 documented accessors matched against every production 🔒 The Security row — ruling 1 held, and I am upholding your restraintYou measured it to outcome 2: documented nowhere. Zero hits for Filed as #9629, labelled And you kept it out of the gate. That is the sharpest judgment in this report: encoding a Security allowlist entry would have been answer C in gate form — quietly deciding "drop the row" by making the drift permanently legal. Leaving the Source-of-Truth list explicitly out of the gate's scope keeps the decision open. Exactly right. #9630 is an independent confirmation of something I measured myself
Verdict: ACCEPT. Arming once the four running gates converge. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
…rix, and gate the matrix and its labels (#9684) `versioning.mdx`'s "Current Matrix" carried seven rows for the chapter's eight pages: `services.sms` was missing from a FIFTH enumeration of the same chapter, after #9604 fixed it in two index lists and #9630 fixed the accessor/slot mismatch. Every enumeration of this chapter that the gate does not hold has drifted, and each one was found by a human noticing. So the row is the small half. `check-runtime-services-index.mjs` gains two additive limbs, leaving the five existing checks untouched: - check 6 holds the "Current Matrix" to the pages on disk — membership and order, exactly as check 3 holds the chapter list, because the matrix follows meta.json's nav order and that convention is the only thing that tells the next author where a new row goes; - check 7 holds every published stability LABEL to the page's own `- **Stability:** <label>` bullet, on BOTH tables that publish one — the matrix and the `services.*` table in `kernel/index.mdx`. This is the half with lasting value: membership checking catches a MISSING row, this catches a WRONG one, which is a live lie a reader plans an upgrade against. The page is the source of truth for its own label, so a disagreement is always reported against the table, and a page that declares no label at all is a finding. The `services.sms` label is derived, not invented: `sms-service.mdx` declares `- **Stability:** `stable``, which is what the row now says. #9629 is untouched: the stability row parser is anchored to `^|` table rows, so the Source-of-Truth list's prose `Security:` row — the one #9634 deliberately kept out of the gate — cannot enter any set here. The self-test pins that on the parser and again on a failing tree. Self-test 17 -> 27 assertions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
Fixes#9604
Two commits: the two-line index fix the card asks for, and the gate that keeps it true.
1.
services.smsis listed in both index pagesBoth index lists enumerated seven slots and omitted
services.sms, while everything else in the repo already had it:sms-service.mdxexists,meta.jsonlistssms-serviceinpages, the chapter's own Source-of-Truth list names its contract, and the slot really is registered.Every claim in the card was re-verified against
mainate8dba8a8arather than copied, and all of them still hold — including the three line-precise ones:packages/services/service-sms/src/sms-plugin.ts:181runsctx.registerService('sms', this.service)sms-service.ts:95hasSmsService implements ISmsServicepackages/plugins/plugin-security/src/security-plugin.ts:1157registerssecuritySecurityat 39 /SMSat 43kernel/index.mdx:17-21omits it tooPlacement was derived, not appended. The chapter list is exactly
meta.json'spagesorder minussms, so the bullet belongs betweenservices.emailandservices.settings— not at the end. Inkernel/index.mdxthe row goes after theservices.emailrow, keeping the email/SMS adjacencymeta.jsonalso has, and its description is taken from the page's own frontmatter rather than invented.2. A gate, because nothing checked either direction
The card notes that
check:docs-audit-scopeconfirms which pages are in audit scope but not that an index enumerates them. Reading the checker confirms it exactly: it derives which pages the docs-accuracy audit covers by shelling out toaffected-docs.mjs --all, and never reads an index page. Nothing else in the repo readsruntime-services/meta.jsoneither — the only scripts that touch ameta.jsonat all are the release-notes collectors.So this page had three hand-written enumerations and no reader, and it has now drifted twice on the same page (#9588 on a different line). This adds
pnpm check:runtime-services-index, in the same docs-guard job as its closest siblingcheck:quick-reference-counts— which guards the same defect class, a hand-written docs index against the real directory.The pages on disk are the source of truth. The gate holds to them:
meta.jsonpages(both directions),runtime-services/index.mdx(both directions),services.*table inkernel/index.mdx(both directions), plus each row's href,meta.json. Membership alone would have acceptedservices.smsappended at the end; order is the only thing that tells the next author where a bullet goes.It first checks each page declares the accessor its filename claims (
title: services.NAME) — that is the premise the other comparisons rest on, so a page that lies about its own name goes red rather than silently redefining the expected set.Reverse-verified. Against the pre-fix tree the gate reports exactly the two drifts the card describes and exits 1:
and green after, naming its own scope:
The
--self-testdrives every limb — chapter list, kernel table,meta.json, order, href, title premise, empty tree — through a real failure and a real silence on a synthetic tree, per the repo's convention for this family.What the gate deliberately does not check
The Source-of-Truth canonical-source list is out of scope, stated in the script header and in the green line. It is a superset by exactly one row —
Security— and that row is the open question this PR is explicitly not allowed to answer. Encoding any of the three candidate answers, an allowlist entry included, would pre-judge it. Its row labels are also prose rather than accessors (Audit bridge), and that line is under active edit by #9588. Extending the gate to that list is the natural follow-up once the Security question is settled.Findings measured but not acted on
Neither is touched by this diff.
The
Securityrow: documented nowhere. Filed separately, since the answer turned out to be the outcome the card called "a bigger gap than #9604 states".grep -rn 'services\.security' content/docs/returns zero hits, and the contract path appears in all ofcontent/docs/exactly once — in the row itself. The near-misses do not close it:kernel/contracts/index.mdx:44documents the interfaceISecurityService, andpermissions/explain.mdx:53showskernel.getService('security')for one task in another chapter. The slot is real (security-plugin.ts:1157). Which of give-it-a-page / move-the-row / drop-the-row is right remains a maintainer product-surface call. Measurement and options: #9629 — not addressed here.The full
registerServicesweep (H3). Every productionregisterServicename in the tree was matched against the chapter. SMS was the only omission of its shape; after this PR the four enumerations agree exactly on all eight accessors. Seven of the eight map one-to-one onto a registered slot of the same name. The exception isservices.storage, whose slot isfile-storage— canonical inCoreServiceName, with noregisterService('storage')anywhere — and the page never says so, so a reader following the chapter's ownctx.getService(...)instruction gets nothing back. That carries a judgment call about which namespace is authoritative, so it is recorded in #9630 rather than patched here. The other 43 registered slots are internal plumbing with no page and no claim to one.Verification
Gate union re-run on the final commit
88a3e3659, clean tree, all green:check:runtime-services-index·check:nul-bytes·check:docs-audit-scope·check:docs-redirects·check:role-word·check:node-version·check:required-contexts·check:workflow-status-functions·check:shard-attestation· speccheck:empty-state·check:variant-docs·check:liveness·check:strictness-ledgerThe family was re-derived from the actual changed paths with
node scripts/pm/dispatch-gates.mjs, which discovers the new gate fromlint.ymlon its own — confirming the CI wiring is real rather than asserted.No changeset
skip-changeset: this PR publishes nothing. It touchescontent/docs/(the docs site,@objectstack/docs, private), a CI-internal check script,lint.yml, and the rootpackage.jsonscript list (@objectstack/spec-monorepo, private). No package source changes. This repo rejects empty-frontmatter changesets, so the label is the mechanism here.Generated by Claude Code
Generated by Claude Code