Measured 2026-08-26 by the dev seat implementing the refusal-message strip (#12124 — scope note below, no closing keyword intended for it here). Observation and a scoping question, not a defect claim: the populations below were deliberately left alone, and this card exists so that decision is visible rather than silent.
What was measured
An AST census over packages/spec/src (all .ts, string literals only, the check-doc-authoring internal-id matcher) buckets every id-bearing string literal by the construct it sits in:
| bucket | literals | what it is | in the refusal-message strip? |
|---|
message | 16 | zod message: + positional validator messages | yes — now 0 |
strictObject | 181 | unknown-key error-map options: guidance, guidanceSets, history, aliases, retiredForms, surface | no |
tombstone | 176 | retiredKey(<prescription>) and the *_RETIRED_KEY_GUIDANCE maps | no |
describe | 182 | .describe() docs prose | no |
| other / test bodies | 2364 | conversion-registry summaries, conformance tables, TSDoc, test assertions | no |
Heaviest files per bucket — strictObject: data/object.zod.ts (19), automation/flow.zod.ts (14), ui/chart.zod.ts (12), system/translation.zod.ts (12). tombstone: data/object.zod.ts (22), ui/component.zod.ts (19), ui/app.zod.ts (13). describe: api/protocol.zod.ts (50), ui/view.zod.ts (14), data/field.zod.ts (11).
Why this is a question and not just a backlog item
The first three buckets are the same audience as the messages that were stripped. A strictObjectguidance entry and a retiredKey prescription are printed at the author verbatim when their metadata is refused — the guidance map is consulted on unrecognized_keys, the tombstone prescription IS the parse error. By the ruling's own reasoning ("the ban follows the audience, not the file type") they look like the same population.
Three things make widening a separate decision rather than a rider, which is why the dev seat did not take it:
- Size and shape. 539 literals across three constructs, each larger than the whole refusal-message population, with their own class-wide pin tests (
retired-key-migrate-sentence.test.ts pins the tombstone sentence shape). - AGENTS.md positively asks the tombstone prescription to carry a durable reference — "the FROM → TO mapping, the ADR the removal rests on, or the migration command". ADR ids are customer-resolvable and stay either way; whether the issue id beside them goes is exactly the call to make here, not to assume.
.describe() is a third audience again — it projects into content/docs/references/** and the generated skill artifacts, so it is docs prose rather than refusal prose, and the 2026-08-23 follow-up already covered the slice of it that reaches skills/**. The remaining 182 are the slice that reaches the docs site only.
What holds today
check:doc-authoring Rule 3 holds the message population mechanically (531 refusal-message strings scanned, 0 violations) and its header names these three buckets as deliberately out of scope with a pointer here. Widening the convention means widening that rule's recognised positions — not adding an exemption; the rule has none by design.
The question for triage
Does the #11052 inheritance reach the unknown-key guidance and tombstone prescriptions (same audience, same moment) — and separately, does it reach .describe() prose that lands on the docs site rather than in a customer context window? Either answer is cheap to act on; what is expensive is discovering later that half a convention was held.
Generated by Claude Code
Measured 2026-08-26 by the dev seat implementing the refusal-message strip (
#12124— scope note below, no closing keyword intended for it here). Observation and a scoping question, not a defect claim: the populations below were deliberately left alone, and this card exists so that decision is visible rather than silent.What was measured
An AST census over
packages/spec/src(all.ts, string literals only, thecheck-doc-authoringinternal-id matcher) buckets every id-bearing string literal by the construct it sits in:messagemessage:+ positional validator messagesstrictObjectguidance,guidanceSets,history,aliases,retiredForms,surfacetombstoneretiredKey(<prescription>)and the*_RETIRED_KEY_GUIDANCEmapsdescribe.describe()docs proseHeaviest files per bucket —
strictObject:data/object.zod.ts(19),automation/flow.zod.ts(14),ui/chart.zod.ts(12),system/translation.zod.ts(12).tombstone:data/object.zod.ts(22),ui/component.zod.ts(19),ui/app.zod.ts(13).describe:api/protocol.zod.ts(50),ui/view.zod.ts(14),data/field.zod.ts(11).Why this is a question and not just a backlog item
The first three buckets are the same audience as the messages that were stripped. A
strictObjectguidanceentry and aretiredKeyprescription are printed at the author verbatim when their metadata is refused — theguidancemap is consulted onunrecognized_keys, the tombstone prescription IS the parse error. By the ruling's own reasoning ("the ban follows the audience, not the file type") they look like the same population.Three things make widening a separate decision rather than a rider, which is why the dev seat did not take it:
retired-key-migrate-sentence.test.tspins the tombstone sentence shape)..describe()is a third audience again — it projects intocontent/docs/references/**and the generated skill artifacts, so it is docs prose rather than refusal prose, and the 2026-08-23 follow-up already covered the slice of it that reachesskills/**. The remaining 182 are the slice that reaches the docs site only.What holds today
check:doc-authoringRule 3 holds the message population mechanically (531 refusal-message strings scanned, 0 violations) and its header names these three buckets as deliberately out of scope with a pointer here. Widening the convention means widening that rule's recognised positions — not adding an exemption; the rule has none by design.The question for triage
Does the
#11052inheritance reach the unknown-key guidance and tombstone prescriptions (same audience, same moment) — and separately, does it reach.describe()prose that lands on the docs site rather than in a customer context window? Either answer is cheap to act on; what is expensive is discovering later that half a convention was held.Generated by Claude Code