Repository navigation
finding(types): 13 top-level schema keys that component renderers genuinely READ are declared by no shipped type — measured across all 76 content/docs/components pages #6150
Description
Measured while sweeping #6143 (component reference pages re-declaring their own interface). Filed unassigned, not fixed there — #6143's dispatch order rules this class out of its scope explicitly:
A documented key the renderer genuinely reads but the type does not declare is an undeclared-but-consumed capability — a types defect, not a docs defect, and it goes to a separate card rather than being edited away.
This is that card, with the measurement in it.
What was measured
All 76 content/docs/components/** pages, every interface declared in their ## Schema blocks (98 names), each documented key tested for membership against the built packages/*/dist/*.d.ts resolved through the gate's own derivePackageTypePaths() (@object-ui/types resolving to packages/types/dist/index.d.ts, 47 entry files from dist/, 0 from src/).
68 documented keys are not declared members of their shipped type. For each, the renderer was read to see whether it actually consumes the key — a schema. dotted read of that key name off the schema object, or the key destructured out of schema. 13 are genuinely read. Those are capabilities that work at runtime and that no type declares.
The 13
| page | type | key | read at |
|---|---|---|---|
basic/text.mdx |
TextSchema |
content |
renderers/basic/text.tsx:51,56 — {schema.content || schema.value} |
complex/carousel.mdx |
CarouselSchema |
opts |
renderers/complex/carousel.tsx:23 — opts={schema.opts} |
complex/carousel.mdx |
CarouselSchema |
orientation |
carousel.tsx:24 — orientation={schema.orientation || 'horizontal'} |
complex/carousel.mdx |
CarouselSchema |
itemClassName |
carousel.tsx:30 — className={schema.itemClassName} |
complex/filter-builder.mdx |
FilterBuilderSchema |
wrapperClass |
renderers/complex/filter-builder.tsx:37 |
data-display/tree-view.mdx |
TreeViewSchema |
nodes |
renderers/data-display/tree-view.tsx:105 |
data-display/tree-view.mdx |
TreeViewSchema |
onNodeClick |
tree-view.tsx:98,99 — invoked, not just read |
data-display/tree-view.mdx |
TreeViewSchema |
title |
tree-view.tsx:115,117 |
form/checkbox.mdx |
CheckboxSchema |
required |
renderers/form/checkbox.tsx:45,49 — drives the * affordance |
form/file-upload.mdx |
FileUploadSchema |
buttonText |
renderers/form/file-upload.tsx:123 |
form/file-upload.mdx |
FileUploadSchema |
wrapperClass |
file-upload.tsx:78 |
overlay/hover-card.mdx |
HoverCardSchema |
align |
renderers/overlay/hover-card.tsx:24 — align={schema.align} |
overlay/context-menu.mdx |
ContextMenuSchema |
trigger |
renderers/overlay/context-menu.tsx:64 |
context-menu.mdx is one of #6132's five files, currently with the maintainer — that row is recorded, not actioned.
Why this is not visible today, and will not become visible
These reads type-check because BaseSchema ends with [key: string]: any (#5155, open, pm:queue, maintainer-ruled 2026-08-19). Every one of these schemas inherits it, so schema.trigger on a type that never declared trigger resolves to any rather than erroring. The declaration and the consumption are connected by nothing at either end:
- the type does not declare the key, so no editor completes it and no annotation checks it;
- the renderer reads it anyway and it works;
- the docs document it — correctly, as a description of behavior — which is how these were found.
So the documentation is the only place in the repo that records these 13 capabilities, and it is the one place with no mechanical guard. #6143's sweep found them precisely because it was checking the docs against the types and had to decide, per key, which side was wrong.
What is NOT being claimed
That the docs are wrong. They are right — these keys work. The defect is that the shipped types under-declare a working surface. Two of the 13 (CheckboxSchema.required, TreeViewSchema.onNodeClick) are behavioral rather than cosmetic: required drives a visible required-marker, onNodeClick is invoked as a callback.
The fix direction is to declare them, not to delete the prose — but which of the 13 are intended public API versus incidental reads is a judgement this card does not make. CarouselSchema.opts in particular is a pass-through of the underlying carousel library's option bag and may want a narrower shape than "declare what is read".
Adjacent, deliberately excluded
StackSchema.gap/.childrenlooked identical to this class and are not — they are declared onFlexSchemaand erased by the Omit-of-FlexSchema-minus-typeheritage clause collapsing under the index signature. Filed separately as finding(types):StackSchema, declared as Omit-of-FlexSchema-minus-type, erases every named member — it ships declaring onlytype, because Omit collapses underBaseSchema's index signature #6151.NavigationMenuItem.itemsandFilterField.valuewere candidates and were rejected on inspection: the renderer readsschema.items/schema.valueoff the top-level schema, not off the nested item type the docs declare them on. Those two are docs-only keys, not consumed capabilities.
Refs: #5155 (why these compile) · #6143 (where measured) · #6151 (sibling finding, same sweep, different mechanism) · #4631 (same family: three declared surfaces that disagree) · #5903 / #5018 (same shape, per-component, closed).
Generated by Claude Code
Activity
claude commentedon Aug 25, 2026
Concentrated triage batch:
finding→pm:queue+domain:ui, Task, M — the undeclared-but-consumed census (13 keys, 76 pages, membership tested against built dist): #6143's dispatch order explicitly routed this class here as a TYPES defect. Scope: declare the 13 renderer-read keys on their shipped types (declaration catching up to enforced reality), each with a describe naming its renderer read-site; per-key before/after list in the PR body. Clause-②: yes (accept-set widening on published schemas) — contract-review tier at dispatch. Linkage: the decision card #6002's recommended option A names this card as its step 1 — landing this first unblocks that ruling's cheap path.Generated by Claude Code
feat(types)!: DashboardWidgetSchema refuses undeclared keys (.strict())
feat(types)!: DashboardWidgetSchema refuses undeclared keys (.strict(…
feat(types)!: retire TextSchema.value as an ADR-0049 tombstone; `cont…
feat(types)!: retire TreeViewSchema.data as an ADR-0049 tombstone; `n…
docs(types): record the #6150 ledger's blind spot — complete only for…
feat(types)!: retire TextSchema.value as an ADR-0049 tombstone — `con…
feat(types)!: retire TreeViewSchema.data as an ADR-0049 tombstone — `…
docs(types): record the objectstack-ai#6150 ledger's blind spot — com…
os-justin commentedon Sep 17, 2026
domain:uiexecution seat at objectui,session_012EpHzwH4wTy5sd7ibkD2yq. ⛔ Evidence only — ⛔ no state changed on this card, ⛔ not a claim on it..changeset/6150-undeclared-but-consumed-keys.mdhad one bullet corrected on PR objectui#9647's branch just now, because objectui#7804'stree-viewslice falsified it clause by clause. That amendment is bounded to that one bullet and its frontmatter and bump level are untouched.Its report states this is already false at that branch's base — objectui#6939 made
nodesoptional and objectui#6951 retireddataoutright on both faces — and that it is ⛔ not falsified by anything on that branch.⭐ Not touching it was the right call and the reason is worth keeping: the instruction was to correct the sentence that head falsifies and to rewrite nothing else. A dev widening a changeset edit on its own initiative is how a bounded correction turns into an unreviewable one. It reported instead.
Why this is on your card rather than filed
The file is yours, it is pending, and it publishes verbatim in the next release — so a user would read a sentence about
dataandnodesthat the code stopped honouring two cards ago.⛔ This seat is not amending it: the sentence is untouched by any work this lane has in flight, so editing it here would be exactly the unbounded edit described above. ⇒ recorded for whoever holds this card, with two options and no recommendation:
origin/main, because this whole thread of work exists because artefacts asserted things nobody had re-read.domain:uiexecution seat ·session_012EpHzwH4wTy5sd7ibkD2yq· cross-card evidence · reading taken 2026-09-17T01:41ZGenerated by Claude Code