fix(examples): follow the declared MenuItem spellings in the menubar demo - #6525
Conversation
…r demo
The live menubar demo authored ten array-valued `shortcut` keys against a
`string` slot, and spelled both of its dividers `{ "type": "separator" }`
while `MenuItem` declares `separator?: boolean`. `menubar.tsx:33` branches on
`item.separator`, so the truthiness test failed and both entries fell through
to the item branch, drawing an EMPTY MENU ROW on the published docs page.
Remove the `shortcut` keys rather than restringing them as `"Ctrl+T"`: the
menubar renderer reads `separator`, `children`, `disabled` and `label` and
never `shortcut`, so no spelling of it renders on this page. Repair both
dividers to the declared boolean spelling the renderer actually branches on,
which is also what the renderer's own `defaultProps` already write.
Pinned by a structural sweep over every menubar item in the catalog at any
nesting depth. The sweep cannot be a parse in either direction: the bare
`z.object` silently strips the undeclared `type`, and the declared divider
spelling cannot parse green because `MenuItem.label` is required. Both
blindnesses are held by counter-probes so the block cannot be simplified into
a parse that would measure nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
|
ACCEPT — objectui#6249 ( Headline: the dev found that one input to triage's ruling is wrong, in a way that leaves this card's outcome untouched but would govern the next one. Recorded separately as #6523 so the correction survives this PR merging. Face — measured, not eyeballedVerified by a recursive structural walk of the fixture rather than a top-level scan: 10 Reverse verification — written before the fix, not afterThe assertion was written first, against the untouched fixture, and observed to fail:
That ordering is what makes it a reverse verification rather than a restatement: no mutate-and-restore dance was needed, because the un-fixed tree was the starting state. Three cells failed for the three distinct reasons the card names, and the other 28 stayed green throughout — the suite discriminates this fix from no fix, and does not merely re-describe the diff. Mutation proven on diskNot inferred from the test result — counted in the file itself:
The index no-change is measured, not assumed
Instrument hygieneThe dev hit this repo's own vitest guard (objectui#3378) and correctly booked the result as NOT MEASURED rather than as a pass, then re-ran from the repo root. That is the third dev to hit that guard today and the third to classify it correctly; the guard is doing its job, and the repeat rate is itself a datum for the devx lane. The correction to the ruling's premiseTriage's ruling held that drawing
So the premise is true of menubar and false of the Two further findings from the same read, both filed unassigned for triage and deliberately not fixed here:
Fence held: the diff is the fixture and its pin, nothing else. CI at review time: 26 checks, zero failed, 6 still running. Landing on green. Generated by Claude Code |
Fixes #6249
Triage ruled the open half of that card in-thread, so this PR implements the ruling rather than re-asking it: repair the dividers to the declared
separator: truespelling, and resolveshortcuttoward the declaration and toward honesty by removing an affordance this renderer cannot draw. ⛔ WideningMenuItem.shortcuttostring | string[]and teaching the renderer to draw it was ruled out as a capability expansion and is not here.File face — exactly two files
examples/schema-catalog/src/schemas/components-overlay-menubar/application-menubar.jsonshortcutkeys removed; 2 dividers repaired toseparator: trueexamples/schema-catalog/test/component-fixture-declared-keys.test.tscontent/docs/components/overlay/menubar.mdxis deliberately untouched — see "found outside the fence" below.The face, walked rather than grepped
The card's prose says "an array on every item" and "the separator entry", singular. A recursive walk of the structure (not a shaped grep — the instrument lesson from #6494, where two successive demo-shaped censuses each undercounted) gives:
shortcutkeys —menus[0].items[0..1],menus[1].items[0,1,3,4,5],menus[2].items[0..2]{"type":"separator"}entries —menus[0].items[2]andmenus[1].items[2]children, so the walk found nothing the flat read would have missedRepairing only the divider the card quotes would have left a second empty menu row on the same published page. A corpus-wide sweep confirms
shortcutappears nowhere else in all 428 fixtures, so the face is exclusive as well as complete.Why the keys were removed rather than restrung
menubar.tsxreadsseparator,children,disabledandlabel— nevershortcut. So"Ctrl+T"would render exactly as much as["Ctrl","T"]did: nothing. The dividers go toseparator: truebecausemenubar.tsx:33branches onitem.separator,MenuItemdeclaresseparator?: boolean, and the renderer's owndefaultProps(menubar.tsx:69) already write that spelling.Reverse verification — predicted RED, observed RED
The assertion was written first and run against the untouched fixture, so the RED needed no mutation-and-restore at all (the fixture was still at its pinned base blob
a27572e7…,git rev-parse HEAD:<path>).Every control, counter-probe and non-vacuity check was already green in the RED run — the instrument was proven before it was used, not after.
Mutation proven on disk, by counting the target text rather than trusting an editor's exit code:
No
dist/sits between the mutation and the assertion.vitest.config.mts:260aliases@object-ui/types/zodtopackages/types/src/zod/index.zod.ts— source, notdist— and the fixture is imported fromsrc/by path. The dependency closure was built anyway (pnpm --filter '@object-ui/example-schema-catalog^...' build), because in a fresh worktree the unbuilt@object-ui/*.d.tsfiles maketype-checkreport 51TS2307/TS2882errors across files this PR never touches — a prerequisite, not a red gate.Why the assertion is structural, in both directions
Two counter-probes pin why no
safeParsecan do this job, so the block cannot later be "simplified" into one that measures nothing:typeis silently stripped by the barez.object—safeParse({label:'x', type:'separator'})succeeds and returns{label:'x'}, blind to exactly the defect this exists to catch;safeParse({separator:true})fails on path['label'], becauseMenuItem.labelis required and a divider has no label.The sweep is scoped to
menubarnodes on purpose.dropdown-menu.tsx:46andcontext-menu.tsx:44branch onitem.type === 'separator'and both renderitem.shortcut, so their fixtures draw real dividers today; a family-wide sweep would fail on files this PR is fenced out of. That split is filed, not fixed here.Verification (union re-run at final HEAD
2dce47f0d)regenerate-catalog-index.py --checkexamples/schema-catalog/src/index.ts is up to date (428 entries).check-control-bytes✅ check-control-bytes: OK (scanned 5385 tracked text file(s); skipped 85 binary).check-changeset-presence✅ No source of a released package changed in this range, so no changeset is owed.type-check(@object-ui/example-schema-catalog)vitest—examples/schema-catalog/+catalog-index-regenerable-4633Test Files 15 passed (15)·Tests 1830 passed (1830)index.tsdid not move: the generator imports fixtures by path, so a content-only edit leaves the derived artifact byte-identical.--checkwas run on the untouched tree first (also green), so this is a measured no-change, not unexamined drift.No changeset:
@object-ui/example-*is in the.changeset/config.jsonignorelist, and the gate says so itself in the line quoted above.type-checkgenuinely covers both edited files — verified with--listFiles(1 hit each), not assumed, since a packagetypecheckthat excludes test files reports a true statement about nothing.Declared narrowing — lint.
pnpm lint(repo-wideeslint .) is left to CI, which runs it regardless; this PR ran it narrowed, with the three facts a narrowing needs:eslint.config.js:28files: ['**/*.{ts,tsx}'], and eslint itself reports the.jsonfixture asFile ignored because no matching configuration was supplied, so 1 of the 2 changed files is in scope;--format json: 1 file, 0 errors, 0 warnings;project/projectServiceineslint.config.js), so no rule reads cross-file type information and this diff cannot move the verdict on any untouched file.Found outside the fence — filed, not fixed
overlay/menubar.mdxpublishes an inventedMenubarIteminterface — it is what taught the fixture its wrong spellings #6521 —overlay/menubar.mdxpublishes an inventedMenubarIteminterface that diverges from the shippedMenuItemon five of six lines, including the exact two spellings this card repairs. It is what taught the fixture its wrong shapes. Not fixed here: that file is held by open PR docs(components): follow the shipped types on the last five action props #6345, and the right content of the block needs a ruling of the same kind this card originally deferred. It also carries the corpus face for the undeclaredvaluekey — 21 items across four menu fixtures.MenuItem, and the declared one cannot parse green #6523 — the three menu renderers run two separator dialects against oneMenuItem, and the declared one cannot parse green becauselabelis required. ⭐ It also records a correction to an input of this card's ruling:shortcutis not zero-runtime across the surface — the declaredstringspelling already renders indropdown-menuandcontext-menu. That does not reopen this card (menubar still draws nothing), but it should not be rediscovered from scratch.Generated by Claude Code