Uh oh!
There was an error while loading. Please reload this page.
docs(components): follow the shipped MenuItem union on the dropdown-menu and context-menu Schema blocks - #7084
Conversation
…enu and context-menu Schema blocks Both pages' `## Schema` blocks published keys `MenuCommandItem` does not declare (`value` on both, `variant` on dropdown-menu) and hid two that it does declare and both renderers read (`shortcut`, `children`). context-menu also published `trigger` as required where the declaration is optional. Docs only; publishes nothing. Empty-frontmatter changeset, since `content/docs/**` is not published source of any released package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
os-sam
commented
Aug 31, 2026
Dispatching seat review ( The |
Closes#7073
Docs only, publishes nothing. The
## Schemablocks ofcontent/docs/components/overlay/dropdown-menu.mdxandcontent/docs/components/overlay/context-menu.mdxare corrected to the surfacepackages/types/src/overlay.tsactually declares. Same defect class PR #7074fixed on the third menu page, and more of it. Verified against
origin/main592acafbeed97c5aed81a18f4d848b6179d3c044; gate union re-run on the finalcommit
1d5bb9197.Premise verification — every load-bearing fact re-derived, and what drifted
The card and the dispatch were substantively correct on every claim. Two
classes of small drift, neither of which changes an outcome:
dropdown-menu.mdx:34-41publishesvalue?: stringandvariant?: 'default' | 'destructive':36,:38)dropdown-menu.tsx:58,66readsitem.childrenand renders a real submenu;:80readsitem.shortcutdropdown-menu.tsx:125registrydescriptionnames neithervaluenorvariant, namesshortcutandchildrendropdown-menu.tsx:130— the onlyvariantin the file is on abuttonnode insidedefaultProps.triggervariantacrossdropdown-menu.tsx,context-menu.tsxandmenubar.tsxreturns that one line and nothing elsecontext-menu.tsx:56,64readsitem.children;:78readsitem.shortcut;:117description names both and names novalue.value.valuereads across all three files. (context-menu.tsx:95contains the literalvalue:— inside{ type: 'text', value: 'Right click here' }, the renderer's own placeholder node. A different object, exactly like thevarianton the trigger button.)MenuCommandItematoverlay.ts:363-400,MenuDividerItemat:409-421363-401and409-419. The declarations are otherwise exactly as described.overlay.zod.ts:154,155packages/types/src/zod/overlay.zod.ts, notpackages/types/src/overlay.zod.ts. The line numbers are right.No premise was falsified, so there is a PR.
dropdown-menu.mdx— four rowsvalue?: string(:36)MenuCommandItem(overlay.ts:363-401), notMenuDividerItem(:409-419); absent from both zod arms (zod/overlay.zod.ts:149-166). No menu renderer reads a.value.variant?: 'default' | 'destructive'(:38)variantin the renderer isdropdown-menu.tsx:130—trigger: [{ type: 'button', label: 'Menu', variant: 'outline' }]— a button node insidedefaultProps.trigger, not a menu item.shortcut?: string—overlay.ts:383,zod/overlay.zod.ts:154. Read atdropdown-menu.tsx:80.shortcut?: string;addedchildren?: MenuItem[]—overlay.ts:387,zod/overlay.zod.ts:155. Read atdropdown-menu.tsx:58,66, and it draws a real submenu.children?: DropdownMenuItem[];addedcontext-menu.mdx— four rowsvalue?: string(:33)context-menu.tsxreads no.value.shortcut?: string—overlay.ts:383,zod/overlay.zod.ts:154. Read atcontext-menu.tsx:78, rendered throughContextMenuShortcut.shortcut?: string;addedchildren?: MenuItem[]—overlay.ts:387,zod/overlay.zod.ts:155. Read atcontext-menu.tsx:56,64.children?: ContextMenuItem[];addedtrigger: ComponentSchema(required) (:47)trigger?: SchemaNode | SchemaNode[]— optional atoverlay.ts:486,.optional()atzod/overlay.zod.ts:191. The renderer substitutes a placeholder (context-menu.tsx:95), so a trigger-less document is legal today.trigger?: ComponentSchemaDeliverable 3 — the read sites, quoted, per page
childrenandshortcutare added because the component reads them, not because the type declares them. Both, on both renderers:packages/components/src/renderers/overlay/dropdown-menu.tsxpackages/components/src/renderers/overlay/context-menu.tsxBoth renderers' own registry metadata already enumerates the correct key set —
dropdown-menu.tsx:125andcontext-menu.tsx:117both describe an item as{ label, icon, shortcut, disabled, onClick, children }. Neither namesvalue.Neither names
variant. The shipped metadata and the reference page beside itwere teaching different key sets, and the metadata was the one that was right.
Deliverable 4 — verdict on the two items the card flagged but did not measure
The discriminator the dispatch set: a doc row that disagrees with a declaration
is mine; a declaration that looks wrong is not.
context-menu.mdxpublishestriggeras required — FIXED HEREThis is a doc row disagreeing with a settled declaration, so it is the same
defect class as the other three rows and it is in scope.
overlay.ts:486declarestrigger?: SchemaNode | SchemaNode[], optional.zod/overlay.zod.ts:191carries.optional()and re-states the reason in its.describe().triggeris legal today and declaring it required would refuse them. Declared by objectui#6150."context-menu.tsx:95—renderChildren(schema.trigger || { type: 'text', value: 'Right click here' }).packages/types/src/__tests__/undeclared-but-consumed-keys-6150.test.ts:113pins the type invariantly, optional limb included.⇒ the declaration is deliberate, dated and pinned; the page is the side that is
wrong. PR #7074 fixed the exact analogue (
menus:tomenus?:), so this alsofollows an established precedent rather than inventing one.
ComponentSchema, where the declared type isSchemaNode— is a real butdifferent divergence spanning six pages; filed as #7082, untouched here, for the
same reason PR #7074 left the localized interface names alone.
ContextMenuSchema.childrenis required but unread — FILED, NOT DECIDED (#7080)Here the declaration is what looks wrong, so per the discriminator it is not
mine to settle. Measured:
overlay.ts:471—children: SchemaNode | SchemaNode[];, required.zod/overlay.zod.ts:190— required in the mirror too, no.optional().grep -rn 'schema\.children' packages/components/src/renderers/overlay/returns nothing.examples/schema-catalog/src/schemas/components-overlay-context-menu/basic-context-menu.json, hastype,trigger,itemsand nochildren— so a strict parse ofContextMenuSchemarefuses this repo's own document.The page therefore stays silent about it, deliberately: publishing a
required-but-unread key would teach authors to emit dead metadata, and
publishing it as optional would contradict the declaration. The page can be
completed once #7080 is decided. Three options are laid out there
(make optional / retire under ADR-0049 / give it a read site); I did not choose.
Deliverable 5 — changeset form, and the fence census
Empty frontmatter, not
patch.apps/siteis"private": true, socontent/docs/**is not published source of any released package. The gate saysso itself, on this diff:
A
patchbump would have been a false claim that a released package changed.Ruling taken from PR #7074, re-measured here rather than inherited.
⛔ The
skip-changesetlabel was not applied. It exists as a label object inthis repo but no workflow or script reads it, so it exempts nothing; the
empty-frontmatter changeset is this repo's real declaration form.
Fence census, both pages, before and after — these blocks are
plaintext,which
check:doc-snippetsnever compiles, so no gate would have caught amistake in them:
plaintextopeners beforecontent/docs/components/overlay/dropdown-menu.mdx:33,:57):33,:57)content/docs/components/overlay/context-menu.mdx:30,:51):30,:52)No fence added, removed or relabelled — objectui#5867's SHRINK-ONLY declared
population is unmoved, which
check:doc-fencesindependently confirms below(80 declared files, 90 blocks, unchanged).
Verification
Gate union re-run on the final commit
1d5bb9197, working tree clean. Everyverdict below is quoted from the gate's own output, not from an exit code read
through a pipe.
check:doc-fences✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) carrying 90 block(s) of objectui#5867's remaining population (⛔ SHRINK-ONLY).check:doc-types✅ Every documented component type is registered.docs:check-linksLinks are valid across 17 scan roots.check:control-bytes✅ check-control-bytes: OK (scanned 5861 tracked text file(s); skipped 85 binary).check:docs-route-closure✅ MEASURED_PAYLOAD is honest+✅ gauge: 1360 modules crawled from 149 route roots (145 MDX), every specifier resolvedcheck:skills-paths✅ check-skills-paths: OK (95/96 stated path(s) resolve across 18 guide file(s); 1 baselined).check:shell-escape-residue✅ check-shell-escape-residue: OK (4/4 root(s) resolved -- ... content/docs: 185 file(s), 1067 fence(s); ... 0 occurrence(s) outside a fence)changeset:check(fixed)✅ All workspace packages are in the changeset fixed group.changeset:check(no-major)✅ No changeset declares a major bump.check-changeset-presence✅ No source or published contract of a released package changed in this range, so no changeset is owed.check-changeset-overwrite✅ No pre-existing changeset was modified or deleted.Plus a control-byte self-scan over the three touched files beyond the gate:
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'on both pages and the changesetreturned no match.
Declared narrowings — two gates did NOT run or could not see this diff
Stated as narrowings, because "not run" and "green" have to stay
distinguishable.
check:doc-snippetsexits 2 here:PRECONDITION NOT MET (exit 2) — The snippet program was NOT run: the packages it resolves against are not built. Its own output says this is "I could not run", not "I ran and found errors". Building the 21 package closures it names would not move its answer: the gate's covered population is read from its own source —const TS_FENCE_LANGUAGES = new Set(['ts', 'tsx', 'typescript'])atscripts/check-doc-snippet-types.mjs:317, acted on at:600. This diff lives entirely insideplaintextfences and adds, removes and relabels zero fences (census above), and it changes no source and no.d.ts, so no untouched document's verdict can move either.eslint— narrowed to the diff, and the narrowing is measured rather than asserted. Population read from eslint's own configuration, not guessed:eslint.config.js:28scopes the TypeScript config tofiles: ['**/*.{ts,tsx}']. Count read from--format json: running eslint on both edited files yields 2 results,errorCount: 0each, both reportingFile ignored because no matching configuration was supplied.Invariance for untouched files: the diff contains no.ts,.tsxor config file, and no type-aware rule is in play, so no untouched file's verdict can move.CI runs the full farm regardless.
Out-of-scope findings, filed unassigned
ContextMenuSchema.childrenis declared REQUIRED, no read site consumes it, and the only shipped fixture omits it #7080 —ContextMenuSchema.childrenis declared required, no read site consumes it, and the only shipped fixture omits it. The card's second unmeasured item; measured and filed rather than decided.DropdownMenuSchema.triggerdeclares a singleSchemaNodewhile its zod mirror, its siblingContextMenuSchema, and its own shippeddefaultPropsall use the array form #7081 —DropdownMenuSchema.triggerdeclares a singleSchemaNodewhile its zod mirror, its siblingContextMenuSchemaand its own shippeddefaultPropsall use the array form.zod-mirror-parity.test.tsis one-directional and this asymmetry sits in its blind spot.trigger/content/actionasComponentSchema, a different shipped type than theSchemaNodethose keys actually declare #7082 — six component pages publishtrigger/content/actionasComponentSchema, a real but different shipped type, where the declaration isSchemaNode. Four sibling overlay pages already spell it correctly, so the family is split on the name of one concept.None of the three is addressed in this PR; all three remain open.
Refs: #7074 (the same fix on the third menu page, whose three conventions this
follows) · #7072 · #6521 · #6523 · #6150 · #5250 · #5867.
Generated by Claude Code