Skip to content

Commit fd03e32

Browse files
os-trumpclaude
andauthored
docs(spec): state at the renderer that section-grammar headings are not stable anchors (#13199)
The four unqualified section-grammar headings emitted by the reference-page renderer (### Properties, ### Allowed Values, ### Union Options, #### Option N) repeat by design: one page carries many schema sections and, unlike the per-key ### Nested Shape: / ### Allowed Values: headings, they carry no qualifier by construction. Measured: 1316 excess occurrences across 162 of 214 pages. They do not collide -- the docs site's slugger (remarkHeading + github-slugger@2.0.0) de-duplicates them into properties, properties-1, ... on all three consumer surfaces -- but that suffix is positional, so a section-grammar anchor is unstable even though it is unique. Source-side note only; the emitted pages are byte-unchanged. Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 795d14e commit fd03e32

2 files changed

Lines changed: 63 additions & 0 deletions

File tree

packages/spec/scripts/lib/format-type.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,20 @@ function formatEnum(values: unknown[], budget: number | null): string {
547547
* element/value/one-variant vocabulary — so a bullet list under the table would
548548
* state something the schema does not. They keep their full spelling, exactly
549549
* as #5340 left them.
550+
*
551+
* ## Two `### Allowed Values` renderings, only one of them addressable (#12862)
552+
*
553+
* The relocation this function decides is printed by `schema-section.ts` under a
554+
* QUALIFIED heading — `### Allowed Values: \`Owner.key\`` — which is unique on its
555+
* page by construction, and that qualifier is the point of it (#12590). The BARE
556+
* `### Allowed Values` this file's prose above keeps naming is the other one: the
557+
* whole-schema `type: 'string'` + `enum` branch, one of the four section-grammar
558+
* headings that repeat by design. Those are de-duplicated by the docs site's
559+
* slugger into positional `-1` / `-2` suffixes and are **not stable anchors**;
560+
* nothing should link to one. The measurements and the decision behind accepting
561+
* that live on `renderSchemaSection` in `schema-section.ts` — this note exists so
562+
* a reader weighing the relocation budget here does not go looking for a defect
563+
* that was decided rather than overlooked.
550564
*/
551565
export function formatPropertyType(prop: any, ctx?: TypeContext): RenderedProperty {
552566
if (prop && prop.type === 'string' && Array.isArray(prop.enum)) {

packages/spec/scripts/lib/schema-section.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,51 @@ function carriesDescription(shape: NestedShape): boolean {
236236
* through `ctx.schemaHref`, which the generator closes over the rendering
237237
* category with (`schemaHrefFrom`) precisely because a bare name is not a
238238
* schema identity (#4696).
239+
*
240+
* ## The section grammar is NOT addressable — decided, not overlooked (#12862)
241+
*
242+
* Four of the headings below carry no qualifier by construction: `### Properties`,
243+
* `### Allowed Values` (the whole-schema vocabulary branch), `### Union Options`
244+
* and `#### Option N`. One page carries many schema sections, so these **repeat by
245+
* design** — and that is the whole difference between them and the per-key
246+
* headings emitted beside them. `### Nested Shape: \`Schema.key\`` and
247+
* `### Allowed Values: \`Owner.key\`` are qualified *precisely* so that one page
248+
* cannot mint the same anchor twice (#12590); those stay addressable. This
249+
* grammar never was.
250+
*
251+
* Measured on the emitted tree: **1316 excess section-grammar headings across 162
252+
* of the 214 reference pages** — 1133 `### Properties`, 145 `### Allowed Values`,
253+
* 12 `### Union Options`, 26 `#### Option N`. `content/docs/references/ui/view.mdx`
254+
* alone carries 45 `### Properties`.
255+
*
256+
* They do not COLLIDE. Measured by driving the docs site's own compile path
257+
* (`fumadocs-mdx/node` `register` configured by `apps/docs/source.config.ts`, ids
258+
* read out of the compiled module — never inferred from library docs):
259+
* `remarkHeading` plus the workspace's single copy of `github-slugger@2.0.0`
260+
* de-duplicates them into `properties`, `properties-1`, `properties-2`, …,
261+
* identically on all three surfaces that consume an anchor — the rendered HTML
262+
* `id`, the fumadocs TOC url, and the search index. `ui/view.mdx` renders 215
263+
* headings with 215 distinct ids and 0 duplicates.
264+
*
265+
* ⛔ **So nothing should link to them**, and the missing qualifier is not a bug to
266+
* repair. That suffix is **positional**: `properties-17` means *the 18th
267+
* `Properties` heading in document order*, so inserting a schema section earlier
268+
* on the same page silently renumbers every anchor below it. A section-grammar
269+
* anchor is therefore unstable even though it is unique — only qualifying the
270+
* headings could buy stable addressing. Nothing in the repo links to one today
271+
* (measured: 0 hits across all 7296 tracked files, with a positive control and a
272+
* pattern control), and `check:doc-anchors` verifies that links RESOLVE, never
273+
* that anchors are UNIQUE — so its green says nothing about this in either
274+
* direction.
275+
*
276+
* Disposition: **accepted on the measurement.** The two alternatives were
277+
* qualifying the section grammar (rewriting every heading on 162 pages) and
278+
* demoting it to a non-heading rendering (changing the published rendering shape);
279+
* both pay a large price for a defect that has zero correctness harm — no
280+
* collision exists — and zero measured demand — no inbound link exists. Not closed
281+
* forever: should stable addressing of the section grammar ever become a product
282+
* requirement, qualification returns to the table, and the counts above are what
283+
* price it.
239284
*/
240285
export function renderSchemaSection(schemaName: string, schema: any, ctx: SectionContext = {}): string {
241286
const defs = schema?.definitions || schema?.$defs || {};
@@ -259,6 +304,10 @@ export function renderSchemaSection(schemaName: string, schema: any, ctx: Sectio
259304
const renderProperties = (
260305
props: any,
261306
required: Set<string> = new Set(),
307+
// The largest section-grammar population on the tree — 1133 of the 1316
308+
// excess headings (#12862). It repeats once per schema section on the page
309+
// and is deliberately unqualified; see the anchor note on
310+
// `renderSchemaSection` above for why, and for why nothing may link to it.
262311
heading = '### Properties',
263312
// A nested-shape table does not open tables of its own. ONE level, matched
264313
// to the ONE shape level `SHAPE_DEPTH_LIMIT` lets a cell open: the table

0 commit comments

Comments
 (0)