Filed unassigned by the os-dev seat while implementing #6318. Grading and domain:* are the triage seat's.
#6318's bucket A asked for a per-group verdict: is the fixture wrong, or does the schema under-declare something the renderer honours? These eight groups came out on the schema side, so the fixtures are deliberately untouched by #6318's PR and the finding is recorded here instead. The three groups that came out on the fixture side were repaired there.
The class
For each component below, the Zod member in @object-ui/types/zod requires a key the renderer never reads, or omits the key it reads first. safeValidateSchema therefore refuses a document the renderer draws correctly — declared and enforced disagree, and the corpus is the side that is right.
Verified by rendering both spellings through the real SchemaRenderer (the same harness examples/schema-catalog/test/catalog-gallery-render.test.tsx uses). #6318's triage supplies the test: a "correction" that renders identically proves the edit was wrong. Every row below either renders identically after the "correction" or renders strictly worse.
Measured, per group
| component | files | zod demands | renderer reads | render after "correcting" the fixture |
|---|
tooltip | 1 | children (required) | schema.trigger, schema.content or schema.body — overlay/tooltip.tsx:28,31; its own inputs list trigger/content/body and never children | blank tile — 3 elements and text Hover me becomes 2 elements and text "" |
context-menu | 1 | children (required) | schema.trigger, schema.items — overlay/context-menu.tsx:95,99 | authored trigger lost — Right-click here becomes the renderer's hardcoded fallback Right click here |
tree-view | 4 | data (required) | boundData or schema.nodes or schema.data — data-display/tree-view.tsx:105; inputs and defaultProps both spell it nodes, and the fixtures ARE those defaultProps | identical — 14 elements, same text, both spellings |
kanban | 2 | columns[].items | col.cards at 12 read sites in KanbanImpl.tsx / KanbanEnhanced.tsx; items at zero. plugin-kanban/src/types.ts declares KanbanColumn.cards, contradicting types/src/complex.ts's KanbanColumn.items | board empties — To Do 1 + the card title becomes To Do 0 + No cards |
filter-builder | 4 | fields[].name, fields[].type in string or number or date or boolean or select, value.operator | fields.find(f => f.value === …) and fields[0]?.value — custom/filter-builder.tsx:1099,1161,1201,1234,1239; its own FilterBuilderProps.fields is Array of { value, label, type? } (line 66); the type switch cases are text/number/boolean/date/datetime/time; FilterGroup is { id, logic, conditions } (line 60), not { operator, conditions } | condition row loses its field — Where Clear all Category Remove condition becomes Where Clear all Remove condition |
chart | 2 | series[].nameandseries[].data as number[], both required | str(raw.dataKey) ?? str(raw.name) — plugin-charts/src/normalizeChartSchema.ts:239, whose docblock states "Internal (dataKey) wins over spec (name)"; ChartRendererProps.series documents itself as accepting both shapes. xAxisKey and the top-level data table the fixtures use are not declared at all | not discriminating in happy-dom (Recharts needs a sized container); verdict rests on the read sites |
object-map | 3 | objectName (required) | getDataConfig is a three-arm resolver data then staticData then objectName — plugin-map/src/ObjectMap.tsx:122-167, whose comment calls staticData"this schema's declared door for inline rows" | identical — adding objectName changes nothing, staticData still wins |
object-gantt | 3 | objectName (required) | same three-arm resolver — plugin-gantt/src/ObjectGantt.tsx:310-322; plugin-gantt/src/index.tsx:74 says it prefers staticData"over the object name" | identical — same text, same element count |
24 files, and every one of them is real ObjectUI content that renders.
Why this is not one fix
The rows are not interchangeable and should probably not land as one PR:
tooltip / context-menu — the mirror should declare trigger (and body / items / triggerClassName / contentClassName / modal) and stop requiring children. HoverCardSchema two entries above TooltipSchema in the same file already declares trigger, so the shape is settled in-repo. ⚠️tooltip's fixture was ALREADY moved from children to trigger once, on render evidence — see catalog-gallery-render.test.tsx's header on objectui#4626. Reverting it is a known regression.tree-view — declare nodes and title, and stop requiring data. Both are read; title is currently undeclared and survives only on BaseSchema.passthrough().kanban — a genuine fork, and the only row here that needs a ruling rather than a repair: two declarations of the same component disagree (items in @object-ui/types, cards in @object-ui/plugin-kanban), and only cards renders. Renaming the renderer to items is contract-first but breaks every authored board; correcting the declaration to cards blesses what ships.filter-builder — three independent mis-declarations in one member (field key, field-type vocabulary, group shape).chart — the mirror models only the spec dialect of a binding the renderer deliberately accepts in two dialects.object-map / object-gantt — objectName should become optional with a refinement that at least one of data / staticData / objectName is present, rather than required outright.
Reproduce
pnpm exec turbo run build --filter=@object-ui/cli
node packages/cli/dist/cli.js check
Measured on a clean checkout at 40c479af2 with only the CLI closure built.
Related
Filed unassigned by the
os-devseat while implementing #6318. Grading anddomain:*are the triage seat's.#6318's bucket A asked for a per-group verdict: is the fixture wrong, or does the schema under-declare something the renderer honours? These eight groups came out on the schema side, so the fixtures are deliberately untouched by #6318's PR and the finding is recorded here instead. The three groups that came out on the fixture side were repaired there.
The class
For each component below, the Zod member in
@object-ui/types/zodrequires a key the renderer never reads, or omits the key it reads first.safeValidateSchematherefore refuses a document the renderer draws correctly —declaredandenforceddisagree, and the corpus is the side that is right.Verified by rendering both spellings through the real
SchemaRenderer(the same harnessexamples/schema-catalog/test/catalog-gallery-render.test.tsxuses). #6318's triage supplies the test: a "correction" that renders identically proves the edit was wrong. Every row below either renders identically after the "correction" or renders strictly worse.Measured, per group
tooltipchildren(required)schema.trigger,schema.content or schema.body—overlay/tooltip.tsx:28,31; its owninputslisttrigger/content/bodyand neverchildrenHover mebecomes 2 elements and text""context-menuchildren(required)schema.trigger,schema.items—overlay/context-menu.tsx:95,99Right-click herebecomes the renderer's hardcoded fallbackRight click heretree-viewdata(required)boundData or schema.nodes or schema.data—data-display/tree-view.tsx:105;inputsanddefaultPropsboth spell itnodes, and the fixtures ARE thosedefaultPropskanbancolumns[].itemscol.cardsat 12 read sites inKanbanImpl.tsx/KanbanEnhanced.tsx;itemsat zero.plugin-kanban/src/types.tsdeclaresKanbanColumn.cards, contradictingtypes/src/complex.ts'sKanbanColumn.itemsTo Do 1+ the card title becomesTo Do 0+No cardsfilter-builderfields[].name,fields[].typeinstring or number or date or boolean or select,value.operatorfields.find(f => f.value === …)andfields[0]?.value—custom/filter-builder.tsx:1099,1161,1201,1234,1239; its ownFilterBuilderProps.fieldsisArray of { value, label, type? }(line 66); thetypeswitch cases aretext/number/boolean/date/datetime/time;FilterGroupis{ id, logic, conditions }(line 60), not{ operator, conditions }Where Clear all Category Remove conditionbecomesWhere Clear all Remove conditionchartseries[].nameandseries[].dataasnumber[], both requiredstr(raw.dataKey) ?? str(raw.name)—plugin-charts/src/normalizeChartSchema.ts:239, whose docblock states "Internal (dataKey) wins over spec (name)";ChartRendererProps.seriesdocuments itself as accepting both shapes.xAxisKeyand the top-leveldatatable the fixtures use are not declared at allobject-mapobjectName(required)getDataConfigis a three-arm resolverdatathenstaticDatathenobjectName—plugin-map/src/ObjectMap.tsx:122-167, whose comment callsstaticData"this schema's declared door for inline rows"objectNamechanges nothing,staticDatastill winsobject-ganttobjectName(required)plugin-gantt/src/ObjectGantt.tsx:310-322;plugin-gantt/src/index.tsx:74says it prefersstaticData"over the object name"24 files, and every one of them is real ObjectUI content that renders.
Why this is not one fix
The rows are not interchangeable and should probably not land as one PR:
tooltip/context-menu— the mirror should declaretrigger(andbody/items/triggerClassName/contentClassName/modal) and stop requiringchildren.HoverCardSchematwo entries aboveTooltipSchemain the same file already declarestrigger, so the shape is settled in-repo.tooltip's fixture was ALREADY moved fromchildrentotriggeronce, on render evidence — seecatalog-gallery-render.test.tsx's header on objectui#4626. Reverting it is a known regression.tree-view— declarenodesandtitle, and stop requiringdata. Both are read;titleis currently undeclared and survives only onBaseSchema.passthrough().kanban— a genuine fork, and the only row here that needs a ruling rather than a repair: two declarations of the same component disagree (itemsin@object-ui/types,cardsin@object-ui/plugin-kanban), and onlycardsrenders. Renaming the renderer toitemsis contract-first but breaks every authored board; correcting the declaration tocardsblesses what ships.filter-builder— three independent mis-declarations in one member (field key, field-type vocabulary, group shape).chart— the mirror models only the spec dialect of a binding the renderer deliberately accepts in two dialects.object-map/object-gantt—objectNameshould become optional with a refinement that at least one ofdata/staticData/objectNameis present, rather than required outright.Reproduce
Measured on a clean checkout at
40c479af2with only the CLI closure built.Related
safeValidateSchema#6318 — the parent card; its PR repairs the three fixtures that WERE wrong and closes the two missing-schema types, and leaves these eight groups to this issueBaseSchemaonly — the ~17 sibling zod mirrors have nothing equivalent, and the class already has two confirmed instances #5684 / finding: the #5684 zod-mirror-parity guard is BLIND to a key declared on the TS side but absent from the mirror — measured on ObjectGanttSchema, and it is the guard #5927 just used as authoritative #6058 — the mirror-parity ratchet, which catches a mirror narrower than its TS twin but cannot see a mirror that agrees with a TS twin both renderers ignore