Found while implementing #7513 (re-typing TenantPlanSchema from a closed enum to an opaque z.string().describe(…)).
What happens
packages/spec/scripts/build-docs.ts's generateMarkdown() decides what to render for a top-level exported schema like this:
const defs = schema.definitions || schema.$defs || {};
let mainDef = defs[schemaName];
if (!mainDef && (schema.properties || schema.enum || schema.anyOf || schema.oneOf)) {
mainDef = schema;
}
if (!mainDef) {
mainDef = Object.values(defs)[0];
}
if (!mainDef) return ''; // <-- silently drops the entire "## SchemaName" section
The root-detection condition only recognizes object (properties), enum, and union (anyOf/oneOf) shapes. A schema whose JSON Schema is a bare primitive — {"type": "string", "description": "…"} with no enum, properties, anyOf, or oneOf — matches none of those, so mainDef stays undefined and generateMarkdown returns ''. Not just the "Allowed Values" bullets — the entire heading, including the schema's own .describe() text, disappears from the published page. The ## TypeScript Usage import list and the root content/docs/references/index.mdx table still name the export (they're driven by the export surface, not this function), so the page looks like it forgot to finish rendering an entry it just imported.
Confirmed on #7513
Before #7513, TenantPlan.json was {"type": "string", "enum": [...]}, which the schema.enum branch of the condition caught, so content/docs/references/cloud/tenant.mdx had a ## TenantPlan / ### Allowed Values section. #7513 widens it to {"type": "string", "description": "..."} (no enum) — and the whole section vanished on regeneration, taking the schema's new ownership-statement description with it. The JSON Schema itself (packages/spec/json-schema/cloud/TenantPlan.json) still carries the full description; only the rendered .mdx page silently lost it.
Scope — this is not just TenantPlan
Scanning packages/spec/json-schema/**/*.json for type ∈ {string,number,integer,boolean} with no enum/properties/anyOf/oneOf, 31 exported schemas match this shape today, 23 of them carrying a real .describe() that never reaches its reference page:
api/EventPattern, cloud/EnvironmentDriver, cloud/PackageCategory, cloud/PackageLocale,
cloud/Sha256Digest, cloud/TenantPlan, data/DriverSslToggle, data/DriverType,
kernel/OpsFilePath, shared/AppName, shared/EventName, shared/FieldName, shared/FlowName,
shared/ObjectName, shared/RoleName, shared/SnakeCaseIdentifier, shared/SystemIdentifier,
shared/ViewName, system/Locale, system/Sha256Digest, system/TraceFlags, ui/ViewItemName
(8 more have no description either way: data/CalendarDateValue, ClockTimeValue, ContextToken, ContextTokenPlaceholder, DateMacroPlaceholder, DateMacroToken, FieldNode, FileReferenceIdValue, InstantValue, ReferenceIdValue.)
Why finding, not a queued defect
Nothing breaks: check:docs compares the generated output to what's committed, so a doc that never had the section stays green — this has apparently been silently true for a while (EnvironmentDriver etc. predate #7513 and already showed the same gap before my change touched anything). No runtime path depends on the rendered docs. It's a documentation-quality gap — real .describe() text authors wrote to be read is invisible on the one page meant to show it — not a defect a user hits today. Filed unassigned/no pm:queue per the observation-class convention.
Suggested fix shape (not attempted here — out of scope for #7513)
Add an else if (mainDef.type) fallback in generateMarkdown() (packages/spec/scripts/build-docs.ts, ~line 368) that renders the description (already handled above the type-specific branches) plus a **Type:** \`line for any recognized root type that isn't object/enum/union, instead of falling through to theif (!mainDef) return ''` case. Would need a fixture pin (a bare-string schema whose description shows up on its page) so this doesn't silently regress again.
Filed while implementing #7513.
Generated by Claude Code
Found while implementing #7513 (re-typing
TenantPlanSchemafrom a closed enum to an opaquez.string().describe(…)).What happens
packages/spec/scripts/build-docs.ts'sgenerateMarkdown()decides what to render for a top-level exported schema like this:The root-detection condition only recognizes
object(properties),enum, and union (anyOf/oneOf) shapes. A schema whose JSON Schema is a bare primitive —{"type": "string", "description": "…"}with noenum,properties,anyOf, oroneOf— matches none of those, somainDefstaysundefinedandgenerateMarkdownreturns''. Not just the "Allowed Values" bullets — the entire heading, including the schema's own.describe()text, disappears from the published page. The## TypeScript Usageimport list and the rootcontent/docs/references/index.mdxtable still name the export (they're driven by the export surface, not this function), so the page looks like it forgot to finish rendering an entry it just imported.Confirmed on #7513
Before #7513,
TenantPlan.jsonwas{"type": "string", "enum": [...]}, which theschema.enumbranch of the condition caught, socontent/docs/references/cloud/tenant.mdxhad a## TenantPlan/### Allowed Valuessection. #7513 widens it to{"type": "string", "description": "..."}(no enum) — and the whole section vanished on regeneration, taking the schema's new ownership-statement description with it. The JSON Schema itself (packages/spec/json-schema/cloud/TenantPlan.json) still carries the full description; only the rendered.mdxpage silently lost it.Scope — this is not just
TenantPlanScanning
packages/spec/json-schema/**/*.jsonfortype ∈ {string,number,integer,boolean}with noenum/properties/anyOf/oneOf, 31 exported schemas match this shape today, 23 of them carrying a real.describe()that never reaches its reference page:(8 more have no description either way:
data/CalendarDateValue,ClockTimeValue,ContextToken,ContextTokenPlaceholder,DateMacroPlaceholder,DateMacroToken,FieldNode,FileReferenceIdValue,InstantValue,ReferenceIdValue.)Why
finding, not a queued defectNothing breaks:
check:docscompares the generated output to what's committed, so a doc that never had the section stays green — this has apparently been silently true for a while (EnvironmentDriveretc. predate #7513 and already showed the same gap before my change touched anything). No runtime path depends on the rendered docs. It's a documentation-quality gap — real.describe()text authors wrote to be read is invisible on the one page meant to show it — not a defect a user hits today. Filed unassigned/nopm:queueper the observation-class convention.Suggested fix shape (not attempted here — out of scope for #7513)
Add an
else if (mainDef.type)fallback ingenerateMarkdown()(packages/spec/scripts/build-docs.ts, ~line 368) that renders the description (already handled above the type-specific branches) plus a**Type:** \`line for any recognized root type that isn't object/enum/union, instead of falling through to theif (!mainDef) return ''` case. Would need a fixture pin (a bare-string schema whose description shows up on its page) so this doesn't silently regress again.Filed while implementing #7513.
Generated by Claude Code