Split out of #9604, which fixed the services.sms half of that card and was explicitly told not to guess the Security half. This card records the measurement so a maintainer can decide.
What was measured
#9604 asked which of three outcomes applies to the Security row in content/docs/kernel/runtime-services/index.mdx: the accessor is documented elsewhere (mis-filed row), documented nowhere (bigger gap), or internal and not meant to be public (drop the row). Measured against main at e8dba8a8a:
| probe | result |
|---|
grep -rn 'services\.security' content/docs/ | 0 hits |
grep -rn 'contracts/security-service' content/docs/ | 1 hit — runtime-services/index.mdx:39, the row itself |
security-service.mdx anywhere under content/docs/ | does not exist |
ISecurityService in content/docs/ | kernel/contracts/index.mdx:44 (interface table) and a v17 release note |
getService('security') in content/docs/ | permissions/explain.mdx:53, spelled kernel.getService('security') |
So the answer is outcome 2: documented nowhere. The slot is real and registered — packages/plugins/plugin-security/src/security-plugin.ts:1157 runs ctx.registerService('security', registeredSecurityService), and packages/spec/src/contracts/security-service.ts:18 names that registration in its own header — but no page in content/docs/ introduces the services.security accessor.
The two near-misses are worth naming because neither closes the gap:
kernel/contracts/index.mdx documents the interfaceISecurityService in the contracts chapter. That is the "what must an implementation provide" surface, not the "how do I call it" accessor surface the runtime-services chapter owns.permissions/explain.mdx shows kernel.getService('security') for one specific task (access explanation). It is a task recipe in another chapter, not an accessor reference.
Why this is larger than the row
The Source-of-Truth list states its own purpose: "Each page links the canonical TypeScript source used to derive signatures." For the Security row there is no page, so the sentence is false for that row — a reader following it lands on a contract file with nothing explaining the accessor. The chapter is advertising a canonical source for a service it never introduces.
Needs a maintainer decision
The three outcomes are mutually exclusive and only one is a docs edit:
- Give it a page —
security-service.mdx in the chapter, plus meta.json, the chapter list and the kernel/index.mdx table. Correct if services.security is meant to be a public runtime accessor. Largest option; the contract is wide (getReadFilter, getReadableFields, canExport, checkAuthoredRowWrite, resolvePermissionSetNames, explain, ...). - Move the row — cheapest, but the measurement above says there is no destination page documenting the accessor, so this is only viable together with deciding which chapter should own it (
permissions/ is the nearest neighbour). - Drop the row — right if the accessor is internal and callers are meant to reach security through
permissions/ docs and kernel.getService rather than a documented services.* slot.
Which one is right depends on whether services.security is intended to be a documented runtime accessor at all. That is a product-surface call, not a docs cleanup.
Note on the gate
PR for #9604 adds pnpm check:runtime-services-index, which holds the chapter list, meta.json and the kernel/index.mdx table to the pages on disk. It deliberately leaves the Source-of-Truth list out of scope, precisely so it does not pre-judge this card — an allowlist entry for Security would be one of the three answers above, encoded in a gate. Once this is decided, extending that gate to the Source-of-Truth list is the natural follow-up and is a small change.
Refs: #9604 · #9588
Split out of #9604, which fixed the
services.smshalf of that card and was explicitly told not to guess theSecurityhalf. This card records the measurement so a maintainer can decide.What was measured
#9604 asked which of three outcomes applies to the
Securityrow incontent/docs/kernel/runtime-services/index.mdx: the accessor is documented elsewhere (mis-filed row), documented nowhere (bigger gap), or internal and not meant to be public (drop the row). Measured againstmainate8dba8a8a:grep -rn 'services\.security' content/docs/grep -rn 'contracts/security-service' content/docs/runtime-services/index.mdx:39, the row itselfsecurity-service.mdxanywhere undercontent/docs/ISecurityServiceincontent/docs/kernel/contracts/index.mdx:44(interface table) and a v17 release notegetService('security')incontent/docs/permissions/explain.mdx:53, spelledkernel.getService('security')So the answer is outcome 2: documented nowhere. The slot is real and registered —
packages/plugins/plugin-security/src/security-plugin.ts:1157runsctx.registerService('security', registeredSecurityService), andpackages/spec/src/contracts/security-service.ts:18names that registration in its own header — but no page incontent/docs/introduces theservices.securityaccessor.The two near-misses are worth naming because neither closes the gap:
kernel/contracts/index.mdxdocuments the interfaceISecurityServicein the contracts chapter. That is the "what must an implementation provide" surface, not the "how do I call it" accessor surface the runtime-services chapter owns.permissions/explain.mdxshowskernel.getService('security')for one specific task (access explanation). It is a task recipe in another chapter, not an accessor reference.Why this is larger than the row
The Source-of-Truth list states its own purpose: "Each page links the canonical TypeScript source used to derive signatures." For the
Securityrow there is no page, so the sentence is false for that row — a reader following it lands on a contract file with nothing explaining the accessor. The chapter is advertising a canonical source for a service it never introduces.Needs a maintainer decision
The three outcomes are mutually exclusive and only one is a docs edit:
security-service.mdxin the chapter, plusmeta.json, the chapter list and thekernel/index.mdxtable. Correct ifservices.securityis meant to be a public runtime accessor. Largest option; the contract is wide (getReadFilter,getReadableFields,canExport,checkAuthoredRowWrite,resolvePermissionSetNames,explain, ...).permissions/is the nearest neighbour).permissions/docs andkernel.getServicerather than a documentedservices.*slot.Which one is right depends on whether
services.securityis intended to be a documented runtime accessor at all. That is a product-surface call, not a docs cleanup.Note on the gate
PR for #9604 adds
pnpm check:runtime-services-index, which holds the chapter list,meta.jsonand thekernel/index.mdxtable to the pages on disk. It deliberately leaves the Source-of-Truth list out of scope, precisely so it does not pre-judge this card — an allowlist entry forSecuritywould be one of the three answers above, encoded in a gate. Once this is decided, extending that gate to the Source-of-Truth list is the natural follow-up and is a small change.Refs: #9604 · #9588