Repository navigation
finding(docs): six component pages publish trigger/content/action as ComponentSchema, a different shipped type than the SchemaNode those keys actually declare #7082
Description
Activity
Claim: PM loop round 2 (
domain:uiseat)
Session:session_012wwHa4aaFybxXrfmfHioDM(GitHub identityos-warren)
Branch:claude/issue-7082-docs-schemanode-type-name
Worktree:objectui-issue-7082
Domain:domain:ui
File surface:content/docs/components/— the six named pages only, plus a pin test (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus— the rename is mechanical, but the per-page array question and the open sibling ruling are judgement.
Clause-②: no — documentation rows. ⛔ Do not change any declaration; if a page and its type disagree in a way a docs edit cannot honestly resolve, that is a finding, not a docs fix.
Serial constraints cleared:content/docs/components/**— no in-flight card names it.⚠️ My sibling dispatch #7086 is widening a docs-gate collector and touchescontent/docs/api/schema-reference.md; its census bounds the newly-collected population at 1 block on that page, which is not one of your six. Disjoint. #7073/#6521/#6347's docs PRs have landed, so re-read every page on currentmain(2c3cd1b), ⛔ not on the card's592acafb.ZONE 1 — the correct form is fixed, and the card establishes it
Nine rows on six pages spell a node slot as
ComponentSchema. That is a real shipped export (packages/types/src/blocks.ts:388) and it is not a node slot — it is the concretetype: 'component'block. The keys are declaredSchemaNode(base.ts:398).⭐ This is not a house-convention question: four sibling overlay pages (
tooltip,popover,drawer,dialog) already publish the same concept asSchemaNode. The family is split 4-to-5 and the minority spelling is the correct one.⛔ THE TRAP — do not pre-empt an open ruling
The card warns:
⚠️ Check per page whether the array form is also owed (SchemaNode | SchemaNode[]where the declaration carries the union) rather than doing a blind string replaceFollow that per page, from the declaration, and here is the part the card cannot tell you: whether
DropdownMenuSchema.triggershould be singular or the array form is #7081, which is open and sits on the human floor (it is a published-type widening awaiting a maintainer decision).⇒ For each row, publish what the declaration says on
maintoday:ContextMenuSchema.triggeris declaredSchemaNode | SchemaNode[]⇒ publish the union.DropdownMenuSchema.triggeris declaredSchemaNode(singular) ⇒ publish singular, even though its zod mirror, its sibling, and its owndefaultPropsall use the array form.
⛔ Do NOT "fix" the dropdown-menu row to the array form. That would silently pre-empt #7081's ruling and put a claim in the docs that the shipped type refuses. If you think the docs are then documenting something incoherent — you are right, and that incoherence is #7081. Note it and leave it.
⚠️ Green will not tell you that you are rightThese are all
plaintextfences.check:doc-snippet-typescompilests/tsx/typescriptonly, so no gate parses these rows (#5250 / #5867). ⇒ A green CI means "nothing else broke", ⛔ not "the correction is correct".⭐ So bring your own evidence. PR #7078 added the first pin test that closes exactly this for one page and the seat's handover calls it the model — follow it: pin the corrected rows against the shipped declarations so the next rename cannot silently re-diverge. If you conclude a pin is not feasible for these six, say why explicitly rather than shipping an unverifiable docs edit.
⚠️ Changeset — the trap the previous seat hit twice in one shiftapps/siteis"private": true, socontent/docs/**publishes nothing andcheck-changeset-presencewill report that no changeset is owed. The correct artifact is then an empty-frontmatter changeset, ⛔ not apatchbump — apatchfalsely claims a released package changed. Quote the gate's verdict line in your report.⛔
majoris refused byscripts/check-changeset-no-major.mjs; do not setOBJECTUI_ALLOW_MAJOR=1.
vitest: root-relative form ONLY (a package-dir run silently re-roots ontoapps/console). eslint: plain form, ⛔ never--no-inline-config.ZONE 2 — PM MECHANISM ASSUMPTIONS (
⚠️ the card's, unmeasured by me, and its tree has moved)Every line number in the card's two tables is from
592acafb.mainis now2c3cd1band three docs PRs landed in between, at least one of which editedcontext-menu.mdxanddropdown-menu.mdx. Re-derive the nine rows; some may already be fixed, and that half is then a with-evidence no-op, not a diff to manufacture.Premise-first
Read the card and its comments on GitHub yourself; check for sanitizer truncation and say you checked.
premise_still_valid: falseis a legitimate delivery. Leave your own claim comment with your own session ID and branch; ⛔ do not touch the assignee field.
Generated by Claude Code
Dev claim (os-dev subagent,
domain:uidispatch)Session:
session_012wwHa4aaFybxXrfmfHioDM(GitHub identityos-warren)
Branch:claude/issue-7082-docs-schemanode-type-name
Worktree:objectui-issue-7082, based on2c3cd1b(not the card's592acafb)
Assignee: untouched — PM owns that field.Re-read the card body and all 11 timeline items via the issue page's embedded JSON payload (raw
body+frontTimelineItems). No sanitizer truncation: the body is 2992 chars and terminates in its full_Generated by …_footer with every section and both tables intact; the PM claim comment likewise terminates in its footer.Scope taken: the nine
ComponentSchemarows on the six named pages, plus a pin test. Per the dispatch's ⛔,DropdownMenuSchema.triggerwill be published singular, aspackages/types/src/overlay.ts:433declares it — #7081 is not pre-empted here. Any row where a docs edit cannot honestly follow the declaration is reported as a finding, not patched.
Generated by Claude Code
os-dev-report
{ "issue": 7082, "status": "done", "branch": "claude/issue-7082-docs-schemanode-type-name", "pr": "https://github.com/objectstack-ai/objectui/pull/7107", "premise_still_valid": true, "premise_notes": "Re-derived on 2c3cd1b, not the card's 592acafb. All nine rows were STILL PRESENT — no with-evidence no-op half. Only one line number moved: context-menu.mdx 47 to 48 (a heading was added above it). BUT the card's stated premise — 'the keys these pages spell as ComponentSchema are declared SchemaNode' — is FALSE for two of the nine rows: AlertDialogSchema.actions and EmptySchema.action are declared NOWHERE, on neither the TS interface nor the zod mirror. Those two are reported, not patched. Seven rows are corrected.", "commit": "5ba929b", "base": "2c3cd1b", "files_changed": [ "content/docs/components/overlay/alert-dialog.mdx", "content/docs/components/overlay/context-menu.mdx", "content/docs/components/overlay/dropdown-menu.mdx", "content/docs/components/overlay/hover-card.mdx", "content/docs/components/overlay/sheet.mdx", "packages/types/src/__tests__/overlay-node-slot-doc-types-7082.test.ts", ".changeset/7082-overlay-node-slot-doc-type-names.md" ], "per_row": [ { "row": "alert-dialog.mdx:30 trigger", "before": "trigger: ComponentSchema;", "declaration": "trigger?: SchemaNode (overlay.ts:91)", "after": "trigger: SchemaNode;", "note": "type name corrected; requiredness divergence left and filed as 7106" }, { "row": "alert-dialog.mdx:33 actions", "before": "actions?: ComponentSchema[];", "declaration": "NOT DECLARED — absent from overlay.ts:78-127 and zod/overlay.zod.ts:42-55, and schema.actions is read nowhere in the renderer", "after": "UNCHANGED", "note": "no honest docs-only edit follows a declaration that does not exist; filed as 7104" }, { "row": "context-menu.mdx:48 trigger", "before": "trigger?: ComponentSchema;", "declaration": "trigger?: SchemaNode | SchemaNode[] (overlay.ts:486)", "after": "trigger?: SchemaNode | SchemaNode[];", "note": "union published, per the declaration" }, { "row": "hover-card.mdx:17 trigger", "before": "trigger: ComponentSchema;", "declaration": "trigger: SchemaNode (overlay.ts:296)", "after": "trigger: SchemaNode;", "note": "singular; its zod mirror says union — same asymmetry as 7081" }, { "row": "hover-card.mdx:18 content", "before": "content: ComponentSchema;", "declaration": "content: SchemaNode | SchemaNode[] (overlay.ts:292)", "after": "content: SchemaNode | SchemaNode[];", "note": "union published" }, { "row": "dropdown-menu.mdx:51 trigger", "before": "trigger: ComponentSchema;", "declaration": "trigger: SchemaNode (overlay.ts:433) — SINGULAR", "after": "trigger: SchemaNode;", "note": "SEE dropdown_menu_resolution below" }, { "row": "sheet.mdx:26 trigger", "before": "trigger: ComponentSchema;", "declaration": "trigger?: SchemaNode (overlay.ts:150)", "after": "trigger: SchemaNode;", "note": "type name corrected; requiredness left and filed as 7106" }, { "row": "sheet.mdx:29 content", "before": "content: ComponentSchema;", "declaration": "content?: SchemaNode | SchemaNode[] (overlay.ts:146)", "after": "content: SchemaNode | SchemaNode[];", "note": "type name corrected; requiredness left and filed as 7106" }, { "row": "empty.mdx:28 action", "before": "action?: ComponentSchema;", "declaration": "NOT DECLARED on EmptySchema (feedback.ts:210-224) nor its mirror (zod/feedback.zod.ts:120-125); READ by the renderer via (schema as any).action behind a typeof-object guard", "after": "UNCHANGED", "note": "SchemaNode admits string/number/boolean, which that guard drops — renaming it would have been a NEW false claim, not a correction; filed as 7105" } ], "dropdown_menu_resolution": "Published SINGULAR — 'trigger: SchemaNode;' — exactly as packages/types/src/overlay.ts:433 declares it, and NOT widened to the array form. #7081 is not pre-empted. I confirmed all four of its counter-witnesses on 2c3cd1b (zod mirror overlay.zod.ts:176 is the array union, sibling ContextMenuSchema declares the union, and the renderer's own defaultProps at dropdown-menu.tsx:130 is an array) and left every one of them alone. The docs are therefore locally incoherent with the validator, which is correct: that incoherence IS #7081. The pin test makes the boundary mechanical rather than a comment — widening the declaration turns both its runtime leg and its type-level leg red, so whoever lands #7081 is told these pages owe the union. Ablation proving that is in the tests field. I also posted the measurement #7081 explicitly asked for and did not have (it says 'I did not measure those' for AlertDialogSchema, HoverCardSchema and SheetSchema): all three carry the same asymmetry, so it is four-for-four, plus DrawerSchema as an unmentioned fifth, and AlertDialogSchema has the same array-defaultProps evidence.", "summary": "Seven of the card's nine rows are corrected, each re-derived from its own declaration on current main rather than by a string replace — the declarations disagree with each other on the array form, so context-menu's trigger and both content rows take 'SchemaNode | SchemaNode[]' while the rest are singular. Five whitespace-only lines move where a corrected row outgrew its fence's comment column. The other two rows are NOT type-name defects at all: both keys are declared nowhere, so they keep their rows and are filed instead. A pin test in packages/types asserts the corrected rows against the TS declarations — deliberately NOT the zod mirror, which disagrees on four trigger rows and would have published #7081's answer — and records the two undeclared rows plus three requiredness divergences so a fix on either side turns it red.", "tests": "All on commit 5ba929b (final commit; git status clean at run time), objectui has no scripts/pm/dispatch-gates so the family was derived by hand from package.json + .github/workflows for the changed paths. Exit codes captured by redirect-then-capture, never through a pipe. GATES: check:doc-snippets exit=0 'Semantic phase: 271 of 271 block(s) judged, 0 failed.' — NOTE its first run was exit=2 'PRECONDITION NOT MET (exit 2) — The snippet program was NOT run', which is NOT MEASURED rather than red; I built its 21-package closure (turbo, 3m15s, 32/32 tasks) and re-ran for the real reading. check:doc-types exit=0 'Every documented component type is registered.' check:doc-fences exit=0 'every TypeScript block in 224 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) carrying 90 block(s)' — unchanged, no fence moved. check:docs-route-closure exit=0. docs:check-links exit=0 'Links are valid across 17 scan roots.' check:changeset-presence exit=0. check:changeset-no-major exit=0 'No changeset declares a major bump.' check:changeset-fixed exit=0. check:changeset-overwrite exit=0 'No pre-existing changeset was modified or deleted.' check:control-bytes exit=0 'OK (scanned 5885 tracked text file(s); skipped 85 binary)'. PACKAGE: pnpm --filter @object-ui/types type-check exit=0, echoed script 'tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json'. pnpm --filter @object-ui/types lint exit=0, '260 problems (0 errors, 260 warnings)', all pre-existing — zero findings in the new file (grepped by filename). pnpm vitest run packages/types/ exit=0 'Test Files 82 passed (82) / Tests 1040 passed (1040)'; the new pin alone is 34 passed. All heavy runs went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-7082-dev; longest hold 196s, longest wait 0s. ABLATION (two legs, implementation COMMITTED FIRST so restore had a real reference): no build leg is owed here and none was run — the pin's imports are type-only and its readings are readFileSync, so nothing resolves through dist. Leg A, revert the dropdown-menu docs row to ComponentSchema: mutation confirmed on disk by grep counts in BOTH directions (injected=1, removed=0) and a hash-object change from the HEAD blob; vitest exit=1, 'Tests 3 failed | 31 passed' — the two corrected-row assertions plus the #7081 no-pre-empt one. Leg C, simulate #7081 landing by widening DropdownMenuSchema.trigger at overlay.ts:433: mutation confirmed on disk (injected=1, singular occurrences 3 to 2) and by hash change; vitest exit=1 'Tests 4 failed | 30 passed' AND tsc -p tsconfig.test.json exit=2 with 'error TS2344: Type false does not satisfy the constraint true' at the _DropdownAdmitsArray assertion — which also proves the type-level leg is live, not vacuous, since the error is inside the new file. Both restores done with 'git checkout HEAD -- ABSOLUTE_PATH' (never the bare form) from a trap using an absolute REPO_ROOT, and both PROVEN by observed state, not exit code: git diff HEAD name-only empty and git hash-object back to the recorded HEAD blob in each case.", "mcp_calls": "11 — 1 claim comment, 3 search_issues (2 dedupe + 1 known-hit control that returned #7081/#7082, so the empty dedupe results are a real reading and not a silently-zeroed session), 3 issue_write for the findings, 1 comment on #7081, 1 create_pull_request, 1 pull_request_read for the mandated body read-back, 1 this report. All bulk reading — the card body, all 11 timeline items, #7081's body — went through the public-repo embedded-JSON payload channel at zero quota; repo-scoped REST is 403 in this session ('GitHub access is not enabled for this session'), and there is no gh CLI.", "sanitizer_check": "Checked, both directions. Card read from the issue page's embedded JSON payload (raw body plus frontTimelineItems), NOT a rendered scrape: body is 2992 chars and terminates in its complete Generated-by footer with both tables and every section intact; the PM claim comment likewise terminates in its footer. No truncation. The PR body was read back IN FULL after creation via pull_request_read and is intact — first line 'Fixes #7082', draft true, base main, and nine content probes all present. Self-scanned every changed file for control bytes beyond the gate as well: zero hits.", "open_questions": [], "out_of_scope_findings": [ "filed as #7104: ui:alert-dialog's three surfaces name three DISJOINT key sets — the renderer reads content/cancelText/actionText/onAction which the type declares nowhere, while the type declares cancelLabel/confirmLabel/confirmVariant/onConfirm/onCancel which the renderer never reads, and the page publishes a third spelling (actions) that neither carries. A dialog authored strictly against the shipped type renders an EMPTY FOOTER. Concrete instance of the general class #4631.", "filed as #7105: EmptySchema.action is read by the shipped renderer through an (schema as any).action cast and declared by neither the type nor its mirror — a 14th key #6150's sweep missed, plausibly because the cast hides it from a schema.KEY scan. Worth re-running that census for the cast spelling.", "filed as #7106: alert-dialog.mdx:30 and sheet.mdx:26,29 publish three node slots REQUIRED against declared OPTIONAL (mirrors are .optional() too, so trigger-less documents parse green today). Exactly #7073's class, which fixed the same defect on context-menu.mdx but was fenced to two pages.", "commented on #7081 rather than filing a duplicate: it says 'The same question applies to AlertDialogSchema, HoverCardSchema and SheetSchema, which also carry a trigger; I did not measure those' — I measured all three and they all carry the same TS-singular vs zod-array asymmetry, making it four-for-four (plus DrawerSchema, a fifth it does not mention), and AlertDialogSchema ships the same array-defaultProps evidence the card cites for dropdown-menu." ], "notes_for_pm": [ "Sibling dispatch #7086 disjointness CONFIRMED: my diff touches content/docs/components/ only, never content/docs/api/schema-reference.md. No overlap found.", "Changeset: the gate answers DIFFERENTLY before and after the pin test is committed. On the docs half alone it said '0 of them published source of a package the release covers ... no changeset is owed' — the dispatch's prediction, and correct for that half. With packages/types/src/__tests__/ in the diff it says '1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s) ... Every one of them has an EMPTY frontmatter — declared as releasing nothing, which is the explicit exemption and a complete answer to this gate.' So the empty-frontmatter changeset is not merely allowed here, it is REQUIRED; a patch bump would have falsely claimed a released package changed. packages/types/tsconfig.json excludes test files from the build, so packages/types/dist is byte-unchanged.", "skip-changeset label deliberately NOT applied: in objectui that label object exists from a historical mis-tagging but no workflow or script reads it and it exempts nothing. The empty-frontmatter changeset is this repo's mechanism, and the gate verdict line above is the authority.", "The assignee field was not touched. My claim comment carries the session id and branch.", "CI convergence is not awaited, per the standing clause. Gate status at report time: in_progress on GitHub's side; every gate I could derive and run locally is green on 5ba929b." ] }
Generated by Claude Code
ACCEPT — PR #7107. Seven rows corrected, two refused with cause, and the #7081 fence turned from prose into a compiler error.
domain:uiseat, sessionsession_012wwHa4aaFybxXrfmfHioDM. Reviewed against GitHub andorigin/main, ⛔ not against the report's self-description.⭐ The card's premise is false for 2 of its 9 rows — verified here, not relayed
The card asserts the nine keys "are declared
SchemaNode". Two of them are declared nothing at all. I re-measured both with in-query controls:probe reading actionsinAlertDialogSchema(overlay.ts:78-127)0 hits control — trigger/cancelLabelin that same span✅ both present actioninEmptySchema(feedback.ts:210-224)0 hits control — interface EmptySchema,title,description✅ all present the renderer reads it anyway ✅ renderers/feedback/empty.tsx:30—(schema as any).action as ComponentSchema | undefined⇒ A string replace across all nine — which is what "mechanical rename with a fixed correct form" invites — would have swapped one false claim for another on two rows.
⭐ And the sharpest reasoning in the delivery is why
empty.actionin particular could not be renamed: the renderer guards ontypeof === 'object', whileSchemaNodeadmitsstring | number | boolean. PublishingSchemaNodethere would document a wider surface than the shipped code accepts — a new defect wearing a correction's clothes. Refusing a row is the harder call than fixing it, and it was the right one.⭐ #7081 was not pre-empted, and the fence is now mechanical rather than a comment
I fenced this in prose: publish
DropdownMenuSchema.triggersingular, because whether it should widen is #7081 and sits on the human floor. That was honoured — and improved on.The pin's type-level leg carries
AdmitsArray<DropdownMenuSchema['trigger']>assertedfalse. Ablation leg C simulated #7081 landing by widening the declaration:tsc -p tsconfig.test.jsonexit 2,TS2344raised inside the new file, plus 4 runtime failures.⇒ Whoever lands #7081 is now told by the compiler that these pages owe an update. My fence would have decayed into a stale comment; this one cannot. ⭐ That TS2344 also proves the type-level leg is live rather than vacuous — a type-level assertion that can never fail is the classic silent no-op, and the ablation shows this one fails.
And it supplied the measurement #7081 itself declined to take ("I did not measure those"): all three named siblings carry the same TS-singular vs zod-array asymmetry — four for four, plus
DrawerSchemaas an unmentioned fifth. Posted to #7081 rather than filed as a duplicate. Correct routing.⭐ The pin's authority is the TS declaration, NOT the zod mirror
A deliberate departure from the #7078 model, and the reasoning is right: on this tree the two disagree on four
triggerrows, so pinning against the mirror would have published #7081's answer by the back door. The pin reads both sides — page row and declaration row — so neither can drift alone.Counter-probes, including the one most people skip
interfaceBodythrows rather than returning an empty body ·schemaFencethrows when a page stops holding exactly one fence · the extractors are asserted to have parsed more than one row per subject · the pre-fix spelling is shown to be caught · a blind replace to the array form is shown to be caught on dropdown-menu · JSDoc stripping is shown not to eat real rows while an@examplefence's lines do not become fake ones.⭐ And the
AlertDialogSchema.actions is read by nothingassertion carries its own in-test control — it checks that the scan can findComponentRegistry.register('alert-dialog'andrenderChildren(schema.trigger)in the same file. A "reads nothing" assertion without that is just a grep that might be pointed at the wrong file.Changeset — the nuance is worth recording
The gate answers differently before and after the pin test enters the diff. Docs alone: "no changeset is owed". With
packages/types/src/__tests__/in the diff: "1 source file(s) of 1 released package(s) changed … Every one of them has an EMPTY frontmatter — declared as releasing nothing, which is the explicit exemption."⇒ So the empty-frontmatter changeset is not merely allowed here, it is required, and a
patchbump would have falsely claimed a released package changed.packages/types/tsconfig.jsonexcludes test files from the build, sodistis byte-unchanged. ⭐ Quoting the gate's verdict rather than reasoning about it is what makes this checkable.Checklist
✅ Draft, base
main,Fixes #7082first line · ✅ 7 files, fence honoured — andfeedback/empty.mdxis correctly absent from the diff · ✅ not governed (content/docs/**andpackages/types/**are both outsideGOVERNED_SURFACES, which I read from the guard itself) · ✅ vitest root-relative · ✅ eslint plain form, 0 errors in the new file · ✅check:doc-fencesunchanged, so #5867's shrink-only population did not move · ✅ firstcheck:doc-snippetsrun was exit 2PRECONDITION NOT MET, read as NOT MEASURED, closure built, re-run for the real reading · ✅ both ablation restores proven by observed state, not exit code · ✅ sibling disjointness with #7086 confirmed by measurement rather than assumed.Three findings filed and correctly not folded: #7104 (alert-dialog's three surfaces name three disjoint key sets — a dialog authored strictly against the shipped type renders an empty footer), #7105 (
EmptySchema.action— undeclared-but-consumed through a cast, a 14th key #6150's sweep missed, plausibly because the cast hides it from aschema.KEYscan), #7106 (three requiredness divergences, #7073's class).Landing
Read by name just now: 30 checks — 24 success, 3 skipped, 6
in_progress(Type Check,Test (shard 1–4/4),Build Docs), 0 failure. ⛔in_progressis not a pass. Holding ready + enqueue until every check is green.
Generated by Claude Code
LANDED — PR #7107 merged as
215e235c8(2026-09-01T00:33:51Z). Verified onmain, not from the queue.domain:uiseat, sessionsession_012wwHa4aaFybxXrfmfHioDM.probe reading SchemaNodeincontent/docs/components/overlay/hover-card.mdxonorigin/main2 (was 0) control — interface HoverCardSchemain the same file (must hit)1 ✅ ⇒ The corrected rows are in the tree. ⛔ A drained queue would not have shown that;
mainadvancing and the string being present does.Paired state write, same action as this comment:
pm:dispatchedremoved, assignee cleared. The card auto-closed on the PR'sFixesline and must not keep carrying a pm state.What landed, and what deliberately did not
Seven rows corrected, each derived from its own declaration rather than by string replace — which is why
context-menu'striggerand bothcontentrows publish the union while the rest stay singular.Two rows deliberately left, because no honest docs-only edit resolves them:
AlertDialogSchema.actionsandEmptySchema.actionare declared nowhere. I re-verified both with in-query controls before accepting that call. ⭐ Forempty.actionthe reasoning is sharper than "undeclared": the renderer guards ontypeof === 'object'whileSchemaNodeadmitsstring | number | boolean, so publishing it would have been a new false claim, not a correction.⭐ The durable part: #7081's fence is now a compiler error
DropdownMenuSchema.triggerstays singular on the page, matching the declaration and ⛔ not pre-empting #7081. The pin's type-level leg assertsAdmitsArray<DropdownMenuSchema['trigger']>isfalse, and the ablation showed that widening the declaration raises TS2344 inside the pin file.⇒ Whoever lands #7081 is told by the compiler that these pages owe an update. My prose fence would have decayed into a stale comment; this one cannot.
Follow-ups filed and now live
#7104 (alert-dialog's three surfaces name three disjoint key sets — a dialog authored strictly against the shipped type renders an empty footer) · #7105 (
EmptySchema.action, undeclared-but-consumed through a cast — a 14th key #6150's sweep missed, plausibly because the cast hides it from aschema.KEYscan) · #7106 (three requiredness divergences, #7073's class).
Generated by Claude Code
- added a commit that references this issue
on Sep 5, 2026 - added a commit that references this issue
on Sep 6, 2026
Found while implementing #7073, which corrects the
triggerrow onoverlay/context-menu.mdxfor a different reason (requiredness). The type name on that row is a separate divergence, spanning six pages, and was left untouched there.Measured on
origin/main592acafbeed97c5aed81a18f4d848b6179d3c044.The divergence
ComponentSchemais a real shipped export —packages/types/src/blocks.ts:388— and it is not a node slot:It is the concrete
type: 'component'block. The keys these pages spell asComponentSchemaare declaredSchemaNode(packages/types/src/base.ts:398), which admits anyBaseSchemaplusstring | number | boolean | null | undefined. So a reader who looks the name up finds a narrow, unrelated type.Six pages use the wrong name:
content/docs/components/overlay/alert-dialog.mdx:30,33trigger,actionscontent/docs/components/overlay/context-menu.mdx:47triggercontent/docs/components/overlay/hover-card.mdx:17,18trigger,contentcontent/docs/components/overlay/dropdown-menu.mdx:51triggercontent/docs/components/overlay/sheet.mdx:26,29trigger,contentcontent/docs/components/feedback/empty.mdx:28actionIt is not house convention — the house already spells it the other way
Four sibling overlay pages publish the same kind of slot with the declared name:
content/docs/components/overlay/tooltip.mdx:16—children: SchemaNode;content/docs/components/overlay/popover.mdx:15,16—trigger: SchemaNode; children: SchemaNode[];content/docs/components/overlay/drawer.mdx:15,17—trigger: SchemaNode; children: SchemaNode[];content/docs/components/overlay/dialog.mdx:15,18,19—trigger: SchemaNode; children: SchemaNode[]; footer?: SchemaNode[];So the overlay family is split 4-to-5 on the name of the same concept, and the minority-by-page-count spelling is the correct one. This is a mechanical rename with a fixed correct form, not a judgement call — but it is nine rows across six pages in a family #7073 does not own, so it belongs on its own card.
Why nothing red covers it
These are all
plaintextfences.check:doc-snippetsonly compilests/tsx/typescript(TS_FENCE_LANGUAGES,scripts/check-doc-snippet-types.mjs:317, acted on at:600), so no gate parses them — the same blindness #5250 records and #5867 declares the population of.SchemaNode | SchemaNode[]where the declaration carries the union) rather than doing a blind string replace;ContextMenuSchema.triggerandDropdownMenuSchema.triggerdisagree with each other on exactly that, which is filed separately.Refs: #7073 · #5250 · #5867 · #6150.
Generated by Claude Code