Skip to content

feat(types)!: refuse both content channels on the family-D re-measure's residual — markdown, chart, bar-chart, code-editor, detail, report, list-view and six designers (objectui#9256) - #11003

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-9256-family-d-remeasure
Sep 28, 2026

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Part of #9256
Clause-②: yes

Clause-② yes, as the claim declared: thirteen published declarations stop accepting an authored children. Each one's renderer reads neither content channel, so the key rendered nothing; it is now refused by name. A published accept set narrows, so a contract review is owed before landing.

This is the re-measure that release 5867503945 on objectui#9256 asked for, plus the slice it found. The card stays open: the re-measure also found twenty neither-channel registrations it does not narrow here (see "Still open" below), so this PR says Part of.

What changed

  • markdown, chart, bar-chart, code-editor, detail, report: body?: never and children?: never on the TypeScript face (MarkdownSchema, ChartSchema, BarChartSchema, CodeEditorSchema, DetailSchema, ReportComponentSchema), and two retirementTombstone members fed one neitherContentChannelGuidance string on the zod mirror. Both stay MEMBERS, so zod-mirror-parity's key sets stay equal.
  • list-view: the two members on the zod mirror only. ListViewSchema's TypeScript face is z.input of that mirror intersected with ListViewRuntimeProps, so the members are what refuse both keys on both faces.
  • The six designers (page-designer, data-model-designer, process-designer, report-designer, object-manager, field-designer): body?: never and children?: never on the TypeScript face only. None of them has a zod mirror, so that face is the only gate, as it was for nl-query.
  • body was already refused on all of these faces, by BaseSchema (objectui#6771). It is restated because that refusal names children as the remedy, and children is dead here too.
  • New pin file packages/types/src/__tests__/content-channel-remeasure-9256.test.ts.
  • One changeset .changeset/9256-remeasure-content-channels.md: @object-ui/types minor with an explicit BREAKING note and a migration line, the spelling the earlier family-D slices used under this repo's no-major rule.

Why these were missed

The first family-D sweep keyed its population on the renderer's DECLARED props type. A registration typed with a published declaration was family D; one typed with an inline or local type was filed as "no published face to narrow". That second bucket was wrong for every registration whose type LITERAL has a published declaration anyway: the declaration an author types against is chosen by the literal, not by the renderer's props type. The re-measure keys on the literal.

The measurement

Taken on origin/main 328abeb55, and re-taken on this PR's merge head 1ac8cb627 (after git merge origin/main); both runs give the same verdicts. The full table is in the os-dev-report comment on objectui#9256.

  • Registration population: check:registry-bare-names --json (the shipped enumerator: literal, loop and indirect claims) joined to a TypeScript compiler-API walk of every ComponentRegistry.register / registerLazy call site in non-test source. Every enumerated claim maps to a call site, and the only call sites without a claim are the data-driven registrars the enumerator reports as unresolved plus two generic forwarders in packages/core (PluginScopeImpl, WidgetRegistry). 23 packages call ComponentRegistry.register; apps/console registers lazily only; packages/core holds the two forwarders. That is the card's 25.
  • Reads: the TypeScript compiler API, ⛔ not grep. One program per tsconfig.json (the workspace packages, apps/console, the examples), on a BUILT tree, 0 unresolved-module diagnostics. Every .body / .children read (property access, string element access, object destructuring) is filed under the declared type of its receiver, with the enclosing function recorded so an any-typed read can be attributed. Lit controls fire in the same run: ButtonSchema, DivSchema, CardSchema and ContainerSchema each file a children read.
  • Published faces: the built packages/types/dist/index.d.ts read with the compiler API (every exported type and every member of every exported union, for type literals and the declared type of body / children), and the built zod mirror read BEHAVIOURALLY: AnyComponentSchema parses { type }, { type, children } and { type, body } for every arm literal, and an issue counts against a channel only if it sits at that channel's path and is absent from the bare document. Controls in the same run: div accepts children, div refuses body, dialog refuses children, an unknown type is refused.
  • Generic traversers: validateChildren in packages/core now reads schema.children only (the card's children || body premise is gone). It, sdui-parser's parse and validateTree, cli validate and page:tabs' related-list / attachment probes walk descendants to validate or count; they render nothing. SchemaRenderer destructures both keys out of the props bag it spreads. The only live children || body fallbacks left are page:card, page:section, page:footer and page:sidebar (family E, out of this card).

Per-key readership for this slice

key governing registration → reader channel reads reaching the node TS face before → after zod mirror before → after
markdown plugin-markdown:markdown, inline props type none: the package's children reads are hast nodes and React props children live → both never children accepted → both refused by name
chart plugin-charts:chart (+ chart:bar alias), ChartRenderer's inline props type none: the package's reads are React children of its own components same same
bar-chart plugin-charts:bar-chart, ChartBarRenderer's inline props type none: it forwards data, dataKey, xAxisKey, height, className, color same same
code-editor plugin-editor:code-editor, CodeEditorRenderer's inline props type none: the package holds no channel read at all same same
detail view:detail (owner of the bare key) → DetailView, typed DetailViewSchema none filed under DetailViewSchema; the package's other reads are FeedItem.body, err.body, a React children and record:alert's text prop same same
report plugin-report:report → ReportRenderer's three paths none: the package's only channel reads are document.body same same
list-view plugin-list:list-view, typed ListViewSchema none filed under it, while the same program sees it as the receiver of objectName, viewType, columns, filter, sort, options and more derived from the mirror same
six designers plugin-designer:*, no schema prop: the node's keys are spread into the component as props none: the package's reads are nav-tree NavigationEntryItem.children and a provider's React children children live → both never no mirror

None of these registrations declares a children slot input (objectui#9910).

Producers. pnpm census:body-dialect --keys over every key in this slice and the twenty still open, with div / card / page / page:card as lit controls in the same pass, at the merge head: the one node that authors children on any of them is this PR's own nested-refusal case in the new pin file. body appears only in tests (record:alert's text prop, and one detail node in the sdui-parser dialect pin). The controls read children on div 177, card 183, page 54. Nothing was migrated.

Red on base, then green

Predictions were written to a file before any mutation. Each leg mutated one committed file through ablation-replace.mjs (anchor count and blob hash proven on disk), measured, and restored under its trap; the restore was proven by the blob hash equal to HEAD and an empty git diff HEAD, and the tree was clean at the end. Run on 7d451884d, then again on the merge head 1ac8cb627 because the merge touched two of the three mutated files; both runs read the same.

leg vitest (new pin) tsc -p packages/types/tsconfig.test.json
A1: delete MarkdownSchema's zod children member RED 6 failed / 91: the five markdown.children refusal rows and the nested control; the member row stays green, as predicted, because BaseSchema already declares the key RED: 2 × TS2322 in zod-mirror-parity (the pair and the key children)
A2: delete FieldDesignerSchema's children?: never (no mirror) GREEN 97 / 97, NOT MEASURED by vitest (types are erased) RED: exactly 1 × TS2578 at the field-designer pin
A3: delete ChartSchema's children?: never GREEN 97 / 97, NOT MEASURED by vitest RED: TS2578 at the chart pin plus 1 × TS2322 in zod-mirror-parity

Consumer-side reverse validation. A probe file inside packages/components, compiled with that package's options, resolves @object-ui/types to packages/types/dist/index.d.ts. Authoring children on eight of the narrowed types gives 8 × TS2322; the div control with children compiles. The probe is deleted in a finally and the tree is clean.

Gates (merge head 1ac8cb627; heavy runs through the shared verify lock; exit codes by redirect-then-capture)

gate result
turbo run build (all but site and console) 42 / 42
@object-ui/types type-check + vitest run packages/types/ exit 0; 272 files / 6081 tests
downstream type-check: every package downstream of @object-ui/types that has the script, except @object-ui/site and the repo root (38 packages, three batches) 38 × type-check: Done, exit 0
vitest run cli, sdui-parser, plugin-markdown, plugin-editor, plugin-report, plugin-designer 94 files / 1004 tests, exit 0
vitest run plugin-list, plugin-charts, plugin-detail 408 files (+1 skipped) / 4323 tests, exit 0
vitest run scripts/ 177 passed + 2 skipped of 179 files / 5335 tests, exit 0
vitest run examples/schema-catalog/ 34 files / 2198 tests, exit 0
console vite build, then check:eager-closure · check:sdui-registration-pins exit 0 each
eslint over the 11 touched TS files 0 errors, 0 findings on an added line
check:control-bytes · check:new-line-citations (0 new) · changeset:check · check-changeset-presence · check:changeset-claims · check:pending-changeset-literals exit 0 each
check:doc-types · check:doc-snippets · check:doc-examples · check:skill-examples · check:doc-fences · check:doc-example-ids exit 0 each
check:handler-key-reads · check:spec-symbols · check:component-surface-parity · check:readme-exports · check:registry-bare-names · check:prompt-keys · check:test-path-roots · pnpm check exit 0 each
governed guard --test over the 12 paths NOT GOVERNED (lit control AGENTS.md: exit 3)

Bundle Analysis: measured, not argued. The TypeScript members emit no JavaScript. The zod members land in the console build's types-zod chunk only (the one chunk carrying the new refusal strings), and that chunk is not in the eager-closure report the build writes: the root @object-ui/types entry imports the zod mirror for types only, and the one runtime importer of @object-ui/types/zod in the console's graph, plugin-map's ObjectMap.tsx, is lazy. check:eager-closure passes at 1ac8cb627.

NOT MEASURED, left to CI: the pnpm test shards beyond the packages above (app-shell, components, core and the rest), @object-ui/site's type-check, test:dist, E2E, and the repo-wide pnpm lint (the local lint read the touched files only; this repo's eslint config enables no type-aware rule, so no untouched file's verdict can move).

Serial constraints

At branch time no open PR touched these files' sites. origin/main then gained 13 commits; git merge origin/main (no rebase, no force-push) conflicted only in zod/objectql.zod.ts, where objectui#10946 added SpecRuleConditionSchema directly above ListViewSchema and this branch added LIST_VIEW_NEITHER_CHANNEL. Both constants are kept, main's first. Open draft PR objectui#10930 edits a zod/complex.zod.ts docblock; this PR does not touch that file. Open PR objectui#10997 edits zod/objectql.zod.ts at ObjectMapConfigSchema, a different site from this PR's ListViewSchema block; git merge-tree of this head against origin/main 665025908 is clean. Whichever of the two lands second re-merges main only if a conflict appears.

Still open — measured, not narrowed here

Twenty registrations read neither channel and have a published face that still accepts children. They are the next slice, and two questions route it:

  • Nineteen public-block arms, armed after this card's family-E re-derivation by objectui#10872 (PRs objectui#10888, fix(types,cli): element:number validates, with the spec's dataSource waiver (objectui#10872, batch 2) #10908) and objectui#10859 (PR objectui#10927): record:activity, record:details, record:discussion, record:highlights, record:history, record:path, record:quick_actions, record:reference_rail, record:related_list, record:alert (its children only), page:header, page:tabs, page:accordion, element:text, element:number, element:button, element:divider, object-metric, object-master-detail-form. Each arm is zod-only and inherits children from BaseSchema. The spec's own PageComponentSchema (installed 17.4.0) refuses a flat children on a page-component node (unrecognized_keys, measured on record:details, page:header, page:tabs, page:card and element:text). Their module belongs to open card objectui#10872, whose next batch edits the same arms, and the element/page/object blocks are any-typed, which this card's brief lists as family E while ruling 5861449497 (Q2 A) treated an any-typed registration with a published arm as family-D-shaped. That conflict is in the report, not decided here.
  • metric-card: its TypeScript face DashboardWidgetSlotComponentSchema accepts children, and its zod twin is a private routing arm inside the dashboard widget slot's union, so a member refusal there needs its own design.

Acceptance notes — out of scope, not fixed here

  • record:alert reads a key named body as its message TEXT (through readProps, which merges the flat node key with properties.body), while its zod arm refuses a flat body with BaseSchema's message, which names children as the remedy. Carrier: objectui#10872's flat-props batch.
  • A comment in content-channel-family-d-9256.test.ts above the chatbot rows still says body is ACCEPTED on chatbot-enhanced and chatbot-floating; the same file's LIVE CONTROL now asserts both refuse it. Carrier: the next family-D slice.

Generated by Claude Code

…al (objectui#9256)

The family-D re-measure keyed the population on each registered key's
type LITERAL rather than on the renderer's declared props type. Thirteen
declarations whose renderer reads neither `body` nor `children` still
accepted `children`:

- markdown, chart, bar-chart, code-editor, detail, report: `?: never`
  pair on the TypeScript face and two `retirementTombstone` members fed
  one `neitherContentChannelGuidance` string on the zod mirror;
- list-view: the zod mirror only, since `ListViewSchema` is `z.input` of
  that mirror intersected with its runtime props;
- the six designer faces (page, data-model, process, report, object
  manager, field): TypeScript only, since none has a zod mirror.

New pin file content-channel-remeasure-9256.test.ts.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
`@object-ui/types` minor with an explicit BREAKING note and a migration
line, the spelling the earlier family-D slices used under this repo's
no-major rule.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
One conflict, in packages/types/src/zod/objectql.zod.ts: main added
`SpecRuleConditionSchema` (objectui#10946) directly above
`ListViewSchema`, where this branch added `LIST_VIEW_NEITHER_CHANNEL`.
Both are module-level constants read by `ListViewSchema`; both are kept,
main's first. No other file conflicted.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
@github-actions

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 51 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/5903-objectgantt-declared-keys.md

  • names src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

.changeset/5905-componentinput-inputtype-tombstone.md

  • names zod/form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    The write was measured as a no-op before it was deleted, and re-measured on this branch's base rather than inherited from the card. A structural census over every inputs: array in the repository (211 regions, all tracked TS/TSX/JS sources) scores inputType at exactly ONE authoring site — the plugin-markdown registration — against name 953, type 969, label 966, description 194, enum 119, required 86 and binding 4 in the same pass over the same regions, so the instrument was not blind. The other 192 in-repo inputType hits are a DIFFERENT face: FormField.inputType (zod/form.zod.ts), the text-input renderer's prop, and SchemaBuilder.inputType, none of which sit on a ComponentInput. The publication path is unchanged and was re-confirmed: packages/sdui-parser/src/index.ts forwards exactly seven keys per input — name, type, of, required, enum, binding, description — so an authored inputType could not reach the published sdui.manifest.json even in principle.

.changeset/5926-empty-action-visible-when.md

  • names data-display.zod.ts → packages/types/src/zod/data-display.zod.ts — edited by this change

    emptyAction was the one authored-node exception in the tree. The empty-state CTA slot resolved the registry directly — ComponentRegistry.get(node.type) — and mounted the result itself, so the node never passed through SchemaRenderer and its visibleWhen was never evaluated. @objectstack/spec accepts the key (SchemaNodeSchema carries visibleWhen, and data-display.zod.ts types emptyAction as a SchemaNode), so an author wrote a gate, the platform took it, and nothing enforced it — declared-not-enforced, the same class c86185eb5 closed for record:alert, one level down.

.changeset/6309-delete-object-fields-bridge.md

  • names types/src/designer.ts → packages/types/src/designer.ts — edited by this change

    Removing it is not the whole change. Three comments — in types/src/designer.ts, types' designer-field-types.test.ts (twice) and fields' richtext-cell-renderer-5452.test.tsx — cited the bridge as a live corroborating source. Left behind, they would have swapped dead code for false documentation: three in-repo pointers telling a future reader that this bridge mediates between the framework field record and FieldDesigner, and nothing telling them it is unreachable. The two that named it as the consumer deriving an editable-subset check from DESIGNER_FIELD_TYPES now name MetadataFieldsPage, which does exactly that with the same idiom and the same objectui#3017 anchor. The third cited the bridge's richtext → html mapping as one of three corroborations that richtext stores HTML; the other two (the showcase seed and the field-type decision tree) are live and carry the point on their own, so that clause is dropped rather than repointed.

.changeset/6349-name-authority-batch-3.md

  • names form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    @object-ui/components — ComboboxOption now IS @object-ui/types' declaration. The component declared its own { value, label }, a strict subset of the ComboboxOption that @object-ui/types declares for ComboboxSchema.options and mirrors in form.zod.ts ({ value, label, disabled? }). The component now re-exports the types declaration (through the @object-ui/types/form subpath — the root barrel does not publish the name), so the name ComboboxOption exported from @object-ui/components gains the optional disabled?: boolean member. Every value that type-checked before still does — nothing narrows and no key changes type; the one thing that moves is keyof ComboboxOption, so a consumer that EXHAUSTS the type (a Record over its keys) will need the new key. Note that the Combobox component itself does not read option.disabled — that member was already declared on the @object-ui/types face and is now visible on this one too; it is recorded as a separate finding, not changed here.

.changeset/6349-types-internal-name-collisions-batch-1.md

  • names crud.ts → packages/types/src/crud.ts — edited by this change

    ActionSchema — renamed, because the two shapes are unrelated. crud.ts and ui-action.ts both declared it. Measured member-by-member they share 9 keys out of 28 each: crud.ts extends BaseSchema and pins type: 'action' (a UI node — a button in a component tree), ui-action.ts extends nothing and types type as ActionType (a spec-v2 action definition, with name, locations, params, target). Re-pointing either at the other would silently hand a consumer a different type, so this took the rename branch (objectui#5044 is the precedent for choosing the surviving name). ui-action.ts's declaration is now spelled UIActionSchema — the name src/index.ts has always PUBLISHED it under, via export type { ActionSchema as UIActionSchema }, which is now a plain re-export. The package's public surface is unchanged: ActionSchema still means crud.ts's legacy shape and UIActionSchema still means ui-action.ts's, exactly as before. Nothing outside ui-action.ts imported the old spelling — there is no ./ui-action subpath in exports, so the old name was never reachable from outside the package.

  • names data-display.ts → packages/types/src/data-display.ts — edited by this change

    BreadcrumbItem / BreadcrumbSchema — re-pointed, because one copy was stale. Both were declared in data-display.ts and in navigation.ts. The data-display pair was not a second dialect but a strict SUBSET: no key declared differently on either side, and missing BreadcrumbItem.icon / onClick / siblings and BreadcrumbSchema.maxItems. Everything that reads a breadcrumb was already on the navigation declaration — registry.ts maps the 'breadcrumb' component type to it, src/index.ts re-exports it under the bare names, zod/navigation.zod.ts mirrors it (icon, onClick, siblings, maxItems included), the ui:breadcrumb renderer consumes it, and the component's own documentation page documents icon and maxItems. data-display.ts now re-exports the one authority.

.changeset/6396-previous-values-dom-leak.md

  • names packages/types/src/form.ts → packages/types/src/form.ts — edited by this change

    Scope is the runtime leak only. The declared key stays exactly as declared (packages/types/src/form.ts, packages/types/src/zod/form.zod.ts are untouched): it has a live consumer, so there is nothing here for the enforce-or-remove channel.

  • names packages/types/src/zod/form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    Scope is the runtime leak only. The declared key stays exactly as declared (packages/types/src/form.ts, packages/types/src/zod/form.zod.ts are untouched): it has a live consumer, so there is nothing here for the enforce-or-remove channel.

.changeset/6397-partial-schema-collapse-pin.md

  • names packages/types/src/form.ts → packages/types/src/form.ts — edited by this change

    ⚠️ Dated note, 2026-09-28 — a generic re-spelling of this Omit does not collapse — objectui#9256. Later in this same release objectui#9256 declared a key-remapping OmitDeclared ({ [P in keyof T as P extends K ? never : P]: T[P] }, in packages/types/src/form.ts) and re-spelled the heritage of InputShorthandSchema and UiCalendarSchema with it. Such a mapped type iterates the named members and the index signature separately, so it drops exactly K, keeps every other named member with its modifiers, and keeps the index signature. The same spelling of this alias declares 28 properties at ButtonSchema and 62 at ObjectGridSchema in this release, where the shipped alias declares 1 at each; at this change's own commit, under the same TypeScript, it declares 27 and 61, the source counts in the table above. So "every generic re-spelling collapses" was not true when it was written. The alias is still left as written: re-spelling it would narrow what every instantiation accepts, a contract change and not a pin's business. The PartialSchema docblock and partial-schema-collapse-pin.test.ts carry the correction. The rest of this entry is kept as the reading of this change.

.changeset/6881-retire-data-table-toolbar.md

  • names data-display.ts → packages/types/src/data-display.ts — edited by this change

    What was measured. The key was declared on both published faces — data-display.ts (toolbar?: SchemaNode[], "Table toolbar actions/content") and the Zod mirror (SchemaNode | SchemaNode[]) — documented, mirrored, and read by NOTHING: data-table.tsx, the registered renderer for type: 'data-table', contains the word only in two prose comments and never reads schema.toolbar. The sibling emptyAction slot on the same interface IS mounted through SchemaRenderer, so the census zero is a reading, not a blind query. An author who wrote a toolbar got a green document and a blank result, with no signal anywhere that said so — the declared-vs-enforced failure mode that is worst for AI-authored metadata, which has nothing but the declaration to go on.

.changeset/6938-checkbox-wrapper-class.md

  • names packages/types/src/form.ts → packages/types/src/form.ts — edited by this change

    packages/components/src/renderers/form/checkbox.tsx:36 reads cn("flex items-center space-x-2", schema.wrapperClass) — classes on the wrapper div around the box and its label — and neither the TypeScript interface in packages/types/src/form.ts nor the zod mirror in zod/form.zod.ts declared the key. It compiled through BaseSchema's index signature and parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on FileUploadSchema and FilterBuilderSchema (objectui#6150); the checkbox was left out only because its doc page's schema block is a six-line summary.

  • names zod/form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    packages/components/src/renderers/form/checkbox.tsx:36 reads cn("flex items-center space-x-2", schema.wrapperClass) — classes on the wrapper div around the box and its label — and neither the TypeScript interface in packages/types/src/form.ts nor the zod mirror in zod/form.zod.ts declared the key. It compiled through BaseSchema's index signature and parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on FileUploadSchema and FilterBuilderSchema (objectui#6150); the checkbox was left out only because its doc page's schema block is a six-line summary.

.changeset/6940-rowactions-boolean-mirror.md

  • names zod/data-display.zod.ts → packages/types/src/zod/data-display.zod.ts — edited by this change

    The hand-written zod mirror in zod/data-display.zod.ts declared rowActions: z.array(z.any()).optional(). Every other face of the same key says boolean: the TS declaration it mirrors (rowActions?: boolean), the renderer's destructuring default (rowActions = false), its two truthiness gates and two colSpan arithmetic sites, the registered authoring input ({ type: 'boolean', label: 'Show Row Actions' }), defaultProps: { rowActions: true }, and the renderer's own docblock example, which authors "rowActions": true. The mirror was the single outlier — and the published one, so safeValidateSchema refused the exact spelling the component's documentation, defaults and authoring UI all teach. Two shipped examples/schema-catalog entries (user-table.json, full-featured-table.json) failed validation for this and no other reason; both now validate unchanged.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The list view's same-named rowActions in zod/objectql.zod.ts — z.array(z.string()), the legacy bare-name action list on ObjectGridSchema — is a different key that is correct as it stands, is in parity with its own TS twin (rowActions?: string[]), and is not touched.

.changeset/6951-tree-view-data-retired.md

  • names data-display.ts → packages/types/src/data-display.ts — edited by this change

    Two published faces, one retirement — and why a tombstone, not a deletion. The TypeScript interface TreeViewSchema (@object-ui/types, data-display.ts) declares data?: never; the Zod mirror TreeViewSchema (@object-ui/types/zod, data-display.zod.ts) declares data as a retirementTombstone(). BaseSchema already declares data?: any (z.any().optional() on the mirror), so DELETING the member would not have refused the key — it would have ADMITTED it, unvalidated, through the base member, and the renderer would have drawn an empty tree. The tombstone on the extended schema shadows the base member on both faces; the pin measures the base accepting the very document the extended schema refuses.

  • names data-display.zod.ts → packages/types/src/zod/data-display.zod.ts — edited by this change

    Two published faces, one retirement — and why a tombstone, not a deletion. The TypeScript interface TreeViewSchema (@object-ui/types, data-display.ts) declares data?: never; the Zod mirror TreeViewSchema (@object-ui/types/zod, data-display.zod.ts) declares data as a retirementTombstone(). BaseSchema already declares data?: any (z.any().optional() on the mirror), so DELETING the member would not have refused the key — it would have ADMITTED it, unvalidated, through the base member, and the renderer would have drawn an empty tree. The tombstone on the extended schema shadows the base member on both faces; the pin measures the base accepting the very document the extended schema refuses.

.changeset/6972-markdown-inert-keys-retired.md

  • names data-display.ts → packages/types/src/data-display.ts — edited by this change

    What was measured, on this branch's base. sanitize was declared ?: boolean with @default true on both published faces — data-display.ts and the Zod mirror — documented, and read by NOTHING. Worse than an ordinary inert key, it implied a switch that does not exist: sanitization is unconditional. rehypePlugins in plugin-markdown/src/MarkdownImpl.tsx is a module-level const array whose last link is [rehypeSanitize, sanitizeSchema], handed to ReactMarkdown as-is — no ternary, no if, no runtime assembly. MarkdownRenderer forwards exactly content and className, and MarkdownImplProps accepts only those two. A repo-wide grep for schema.sanitize over packages/ and apps/ returns nothing, against a control of 20 .tsx files reading schema.content in the same query shape, so the zero is a reading, not a blind query. An author writing sanitize: false believed they turned XSS filtering off; one writing sanitize: true believed they turned it on. Neither was true.

.changeset/7113-chart-data-model.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

  • names form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

.changeset/7200-object-form-section-style-keys-undeclared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The authored-metadata type now agrees with @objectstack/spec, whose FormSectionSchema is a strict object declaring neither key, and with the ruling's rationale (maintainer 2026-09-01, verbatim): "retire the reads … Declaring the keys was weighed and not adopted: it would formally invite free Tailwind strings into authored metadata, the exact class the boundary exists to keep out." A ?: never tombstone was not used: ObjectFormSection has no zod mirror (ObjectFormSchema in zod/objectql.zod.ts does not declare sections), so there is no parse door to refuse at, and a tombstone is still a declaration in completion and in the published .d.ts.

.changeset/7265-types-user-filter-field-derives.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    zod/objectql.zod.ts declared two schemas under names @objectstack/spec/ui already exports. They were triaged separately, by reading their sites, and went different ways.

.changeset/7322-object-kanban-group-by-limit.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

.changeset/7352-drill-down-config-mirror.md

  • names zod/data-display.zod.ts → packages/types/src/zod/data-display.zod.ts — edited by this change

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

.changeset/7363-objectql-union-arms.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.changeset/7530-predicate-envelope-declared.md

  • names zod/form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    • ExpressionWire (type, main entry) — the TypeScript wire union, in packages/types/src/expression.ts. - ExpressionWireSchema (@object-ui/types/zod) — its runtime twin, hoisted out of zod/form.zod.ts (where it was module-private) into zod/expression.zod.ts and imported by both base.zod.ts and form.zod.ts. One envelope type, reused by reference; no second spelling.
  • names form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    • ExpressionWire (type, main entry) — the TypeScript wire union, in packages/types/src/expression.ts. - ExpressionWireSchema (@object-ui/types/zod) — its runtime twin, hoisted out of zod/form.zod.ts (where it was module-private) into zod/expression.zod.ts and imported by both base.zod.ts and form.zod.ts. One envelope type, reused by reference; no second spelling.

.changeset/7694-chart-series-chart-type-alias-refusal.md

  • names zod/data-display.zod.ts → packages/types/src/zod/data-display.zod.ts — edited by this change

    • Before: series: [{ name: 'revenue', chartType: 'line' }] validated green through @object-ui/types/zod (safeValidateSchema, objectui check / objectui validate, any pipeline that keeps parse()'s output) — and the key was gone from the output, so a consumer of the parse result drew that series in the chart's own family, precisely what the author was overriding. On the TypeScript face the key was merely an excess property on a fresh literal; a widened object carrying it assigned structurally. - After: the same document REFUSES at series[i].chartType (issue code invalid_type) with one message on both channels — the parse-time issue and the .describe() metadata: Unrecognized key(s) on this chart series: \chartType`. Did you mean `chartType` → `type`? …followed by the reason and the remedy. Writetype: 'bar' | 'line' | 'area'. On the TypeScript face ChartDataSeries.chartTypeis a?: nevertombstone, so both the fresh literal and the widened assignment aretsc errors. - **Both written** ({ type: 'bar', chartType: 'line' }) is refused at chartTypealone — the key is not folded ontotypeand no precedence is minted between the two spellings. - **Which documents to scan.** The narrowing does not stop atChartDataSeriesSchema; it reaches every document through the parents that embed it — ChartSchema.series (zod/data-display.zod.ts, z.array(ChartDataSeriesSchema)) and, one level further out, ReportSectionSchema.chart (zod/reports.zod.ts, ChartSchema.optional()). Authors meet it through safeValidateSchema() (zod/index.zod.ts, which parses AnyComponentSchema) and through the CLI's objectui validate command (packages/cli/src/cli.ts). In practice: every chartnode'sseries[], and every report section whose chart` carries one.
  • names zod/reports.zod.ts → packages/types/src/zod/reports.zod.ts — edited by this change

    • Before: series: [{ name: 'revenue', chartType: 'line' }] validated green through @object-ui/types/zod (safeValidateSchema, objectui check / objectui validate, any pipeline that keeps parse()'s output) — and the key was gone from the output, so a consumer of the parse result drew that series in the chart's own family, precisely what the author was overriding. On the TypeScript face the key was merely an excess property on a fresh literal; a widened object carrying it assigned structurally. - After: the same document REFUSES at series[i].chartType (issue code invalid_type) with one message on both channels — the parse-time issue and the .describe() metadata: Unrecognized key(s) on this chart series: \chartType`. Did you mean `chartType` → `type`? …followed by the reason and the remedy. Writetype: 'bar' | 'line' | 'area'. On the TypeScript face ChartDataSeries.chartTypeis a?: nevertombstone, so both the fresh literal and the widened assignment aretsc errors. - **Both written** ({ type: 'bar', chartType: 'line' }) is refused at chartTypealone — the key is not folded ontotypeand no precedence is minted between the two spellings. - **Which documents to scan.** The narrowing does not stop atChartDataSeriesSchema; it reaches every document through the parents that embed it — ChartSchema.series (zod/data-display.zod.ts, z.array(ChartDataSeriesSchema)) and, one level further out, ReportSectionSchema.chart (zod/reports.zod.ts, ChartSchema.optional()). Authors meet it through safeValidateSchema() (zod/index.zod.ts, which parses AnyComponentSchema) and through the CLI's objectui validate command (packages/cli/src/cli.ts). In practice: every chartnode'sseries[], and every report section whose chart` carries one.

.changeset/7697-combobox-option-root-barrel.md

  • names src/form.ts → packages/types/src/form.ts — edited by this change

    Additive only. ComboboxOption is added to the root barrel's existing named re-export list from ./form.js, next to the sibling option types that were already there (SelectOption, RadioOption). Nothing is removed, retyped or narrowed: the declaration stays in src/form.ts, its three members (value, label, disabled?) are unchanged, and the @object-ui/types/form subpath spelling keeps working exactly as before. Both spellings now resolve to the same declaration.

.changeset/7722-wrapper-class-five-more.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    Each of renderers/form/switch.tsx, textarea.tsx, date-picker.tsx, select.tsx and renderers/data-display/list.tsx reads schema.wrapperClass onto its wrapper element, and neither the TypeScript interface (form.ts, data-display.ts) nor the zod mirror (zod/form.zod.ts, zod/data-display.zod.ts) declared the key. The reads compiled through BaseSchema's index signature (objectui#5155) and the values parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on CheckboxSchema (b74a8598d), FileUploadSchema and FilterBuilderSchema (objectui#6150); these five were left out only because their doc pages never listed it.

  • names data-display.ts → packages/types/src/data-display.ts — edited by this change

    Each of renderers/form/switch.tsx, textarea.tsx, date-picker.tsx, select.tsx and renderers/data-display/list.tsx reads schema.wrapperClass onto its wrapper element, and neither the TypeScript interface (form.ts, data-display.ts) nor the zod mirror (zod/form.zod.ts, zod/data-display.zod.ts) declared the key. The reads compiled through BaseSchema's index signature (objectui#5155) and the values parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on CheckboxSchema (b74a8598d), FileUploadSchema and FilterBuilderSchema (objectui#6150); these five were left out only because their doc pages never listed it.

  • names zod/form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    Each of renderers/form/switch.tsx, textarea.tsx, date-picker.tsx, select.tsx and renderers/data-display/list.tsx reads schema.wrapperClass onto its wrapper element, and neither the TypeScript interface (form.ts, data-display.ts) nor the zod mirror (zod/form.zod.ts, zod/data-display.zod.ts) declared the key. The reads compiled through BaseSchema's index signature (objectui#5155) and the values parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on CheckboxSchema (b74a8598d), FileUploadSchema and FilterBuilderSchema (objectui#6150); these five were left out only because their doc pages never listed it.

  • names zod/data-display.zod.ts → packages/types/src/zod/data-display.zod.ts — edited by this change

    Each of renderers/form/switch.tsx, textarea.tsx, date-picker.tsx, select.tsx and renderers/data-display/list.tsx reads schema.wrapperClass onto its wrapper element, and neither the TypeScript interface (form.ts, data-display.ts) nor the zod mirror (zod/form.zod.ts, zod/data-display.zod.ts) declared the key. The reads compiled through BaseSchema's index signature (objectui#5155) and the values parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on CheckboxSchema (b74a8598d), FileUploadSchema and FilterBuilderSchema (objectui#6150); these five were left out only because their doc pages never listed it.

.changeset/7735-zod-mirrors-stop-authoring-defaults.md

  • names crud.zod.ts → packages/types/src/zod/crud.zod.ts — edited by this change

    What changed. All 41 .default() call sites under packages/types/src/zod/ are removed — layout.zod.ts 22, crud.zod.ts 11, form.zod.ts 5, views.zod.ts 2, app.zod.ts 1. @object-ui/components reconciles the third face a separate finding found: flex's registration defaultProps.align seeded 'center', the value its own renderer never applies, so a designer-made node laid out differently from a hand-authored one; it now seeds 'start'.

  • names form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    What changed. All 41 .default() call sites under packages/types/src/zod/ are removed — layout.zod.ts 22, crud.zod.ts 11, form.zod.ts 5, views.zod.ts 2, app.zod.ts 1. @object-ui/components reconciles the third face a separate finding found: flex's registration defaultProps.align seeded 'center', the value its own renderer never applies, so a designer-made node laid out differently from a hand-authored one; it now seeds 'start'.

.changeset/7917-export-breadcrumb-object-tree-zod-schemas.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    AnyComponentSchema declares 107 node component types. 105 of them could be named on the ./zod barrel — ButtonSchema.safeParse(node), which is what a designer, a form builder or a targeted test needs. The arms declaring type: 'breadcrumb' (navigation.zod.ts) and type: 'object-tree' (objectql.zod.ts) could not: both were already export const in their own module, but index.zod.ts — the package's only zod entry point — did not re-export them, so the schemas existed, were maintained, and were applied by the union while no consumer could name them.

.changeset/8072-input-wrapper-class-mirrored.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    packages/components/src/renderers/form/input.tsx reads cn("grid w-full items-center gap-1.5", schema.wrapperClass) onto the wrapper div around the input and its label. The TypeScript face has declared the key all along (form.ts, docblock "Input wrapper CSS class"); the zod mirror never did, so the value rode through .passthrough() and { type: 'input', wrapperClass: 42 } validated GREEN — while the identical document on any of the other eight schema.wrapperClass readers (checkbox, file-upload, filter-builder — objectui#6150 / b74a8598d; switch, textarea, date-picker, select, list — objectui#7722) was refused at the key.

.changeset/8331-data-table-empty-action-primitive-node.md

  • names packages/types/src/data-display.ts → packages/types/src/data-display.ts — edited by this change

    Behaviour change on a published surface, deliberately. DataTableSchema.emptyAction is declared SchemaNode on both published faces — packages/types/src/data-display.ts and its Zod twin in packages/types/src/zod/data-display.zod.ts — and SchemaNode is BaseSchema | string | number | boolean | null | undefined. The empty-state render path additionally required typeof … === 'object', so an authored emptyAction: 'Create the first record' rendered nothing and reported nothing: declared wider than enforced, failing in the direction that loses the author's content without a diagnostic. A node that renders nothing today therefore starts rendering.

  • names packages/types/src/zod/data-display.zod.ts → packages/types/src/zod/data-display.zod.ts — edited by this change

    Behaviour change on a published surface, deliberately. DataTableSchema.emptyAction is declared SchemaNode on both published faces — packages/types/src/data-display.ts and its Zod twin in packages/types/src/zod/data-display.zod.ts — and SchemaNode is BaseSchema | string | number | boolean | null | undefined. The empty-state render path additionally required typeof … === 'object', so an authored emptyAction: 'Create the first record' rendered nothing and reported nothing: declared wider than enforced, failing in the direction that loses the author's content without a diagnostic. A node that renders nothing today therefore starts rendering.

.changeset/8478-describe-line-addresses.md

.changeset/8478-zod-pins-form-layout.md

.changeset/8499-node-slot-registered-arms.md

  • names zod/form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    • SemanticElementSchema (zod/layout.zod.ts) — the seven HTML sectioning tags renderers/layout/semantic.tsx registers: aside main header nav footer section article. - HtmlElementSchema (zod/layout.zod.ts) — the 37 safe flow/inline tags renderers/basic/html-elements.tsx registers (h1…h6, p, a, ul, img, …), plus the per-tag keys that module forwards to the DOM (href, target, rel, title, src, alt, width, height, dateTime, cite). ⚠️ Dated note, 2026-09-27 — that set has since gained code — objectui#10756. At this change TAGS and this arm both named 37 tags; both now name 38, and the parity pin counts 38. The rest of this entry is kept as the reading of this change. - InputShorthandSchema (zod/form.zod.ts) — email / password, the two aliases renderers/form/input.tsx registers onto the input renderer with inputType pinned. inputType is deliberately NOT declared on this arm: the wrapper spreads its own value last, so an authored one is overwritten. ⚠️ Dated note, 2026-09-28 — inputType is now declared on this arm, as a refusal — objectui#8762. Later in this same release the arm declares inputType on both faces and refuses it by name (?: never on the TypeScript face, a retirementTombstone on the zod mirror, at path inputType), with guidance pointing at { "type": "input", "inputType": "email" }. So "inputType is deliberately NOT declared on this arm" no longer holds; the reason does, since the wrapper still spreads its own value last. The rest of this entry is kept as the reading of this change. - UiCalendarSchema (zod/form.zod.ts) — ui:calendar, the date-picker primitive renderers/form/calendar.tsx registers under exactly that key (skipFallback, because bare calendar belongs to the plugin-calendar view).

.changeset/8516-8556-mirror-partial-record-narrowing.md

  • names zod/reports.zod.ts → packages/types/src/zod/reports.zod.ts — edited by this change

    | key | mirror was | mirror is | | :-- | :--------- | :-------- | | GridSchema.columns (zod/layout.zod.ts) | z.record(z.string(), z.number()) | a PARTIAL record over the six breakpoints | | ReportComponentSchema.exportConfigs (zod/reports.zod.ts) | z.record(z.string(), ReportExportConfigSchema) | a PARTIAL record over ReportExportFormat |

.changeset/8735-objectql-mirror-docblocks-not-defaulted.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Correct four zod/objectql.zod.ts docblocks that described the behaviour objectui#8317 removed. Since that change the zod mirrors strip imported @objectstack/spec defaults at this package's import boundary, but the docblocks on HttpRequestSchema, ListColumnSchema, SelectionConfigSchema and PaginationConfigSchema still said, in the present tense, that method, prefix.type, type and pageSize are defaulted on parse — the opposite of what each export does. Each now says the key is declared and accepted but NOT defaulted on parse.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8885-object-chart-drilldown-title-compareto.md

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

.changeset/8992-user-actions-collapse-and-docblock.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    objectql.zod.ts's UserActionsSchema read stripImportedDefaults(Spec).extend({ group, hideFields, rowColor }), an extension that existed only because @objectstack/spec did not declare those three keys while normalizeListViewSchema folded objectui's legacy showGroup / showHideFields / showColor onto them. The protocol adopted all three in 17.3.0 (objectui#5435's ruling), so the extension is now a second local copy of a protocol declaration — the shape two faces start drifting from — and it collapses into the plain by-reference re-export its own note always said it would become.

.changeset/9067-zod-barrel-named-arms.md

  • names zod/form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    • InputShorthandSchema (zod/form.zod.ts) — the email / password shorthand arm. - UiCalendarSchema (zod/form.zod.ts) — ui:calendar, the date-picker primitive renderers/form/calendar.tsx registers, a different component from the calendar plugin view that owns the bare literal.

.changeset/9256-list-timeline-content-channels.md

  • names packages/types/src/data-display.ts → packages/types/src/data-display.ts — edited by this change

    These two were held out of the previous family-D slice for a SERIAL constraint on packages/types/src/data-display.ts and never for a verdict. Readership was re-derived for both rather than inherited: a TypeScript compiler-API sweep files every .body / .children read under the declared type of its receiver and answers zero for ListSchema and TimelineSchema while its live controls fire. timeline's bare-key owner is any-typed, so it was attributed directly as well — packages/plugin-timeline contains no channel read of any kind.

.changeset/9309-object-gallery-filter-destination-typed.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

.changeset/9406-types-root-barrel-two-names.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    form-barrel-mirror-9406.test.ts keeps it closed, and it is DERIVED rather than a pair of presence assertions: it reads form.ts's export list and the root barrel's ./form.js re-export list on every run and names whatever is in the first and not the second. A pin asserting "these two names are present" would pass on the day the next declaration lands in form.ts and is forgotten, which is this class reopening yet again. Names deliberately left off the list get a ledger row carrying the reason instead, and a row goes red once its name reaches the barrel or stops being declared.

.changeset/9511-record-id-is-a-string.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • names crud.ts → packages/types/src/crud.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • names zod/crud.zod.ts → packages/types/src/zod/crud.zod.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

.changeset/9526-types-root-barrel-command-element-types.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    The change is purely additive: the two names join the root barrel's existing named re-export list from ./form.js, beside CommandSchema. Nothing is removed, renamed or narrowed, the declarations stay in form.ts, and the /form subpath keeps working. It is the third instance of one class, repaired by the same route each time: objectui#7697 for ComboboxOption, and objectui#9406 (director decision batch 133, item 2, letter (a)) for InputShorthandSchema and UiCalendarSchema.

.changeset/9549-tree-filter-declared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9606-object-kanban-card-title.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

.changeset/action-callback-retired-7068.md

  • names crud.ts → packages/types/src/crud.ts — edited by this change

    What was measured, on this branch's base (900f8d99). ActionCallback ({ type: 'toast' | 'message' | 'redirect' | 'reload' | 'custom' | 'ajax' | 'dialog', message?, url?, api?, method?, dialog?, handler? }) was declared in crud.ts, mirrored in zod/crud.zod.ts, re-exported by both barrels, and carried on the legacy ActionSchema as onSuccess? / onFailure?. Producers: the package's own phase2-schemas.test.ts fixture and three ts fences in content/docs/core/enhanced-actions.mdx — nothing else (git grep -l ActionCallback over packages content skills hit the five packages/types files; positive control SchemaNodeSchema hit 22). Runtime readers: none — ActionRunner imports UIActionSchema, never this interface, and its own ActionDef.onFailure is a different (runner-native) meaning. It was the THIRD meaning of one key: objectui#5934 had already retired the runner's callback meaning of onSuccess and converged it on the spec's block.

  • names zod/crud.zod.ts → packages/types/src/zod/crud.zod.ts — edited by this change

    What was measured, on this branch's base (900f8d99). ActionCallback ({ type: 'toast' | 'message' | 'redirect' | 'reload' | 'custom' | 'ajax' | 'dialog', message?, url?, api?, method?, dialog?, handler? }) was declared in crud.ts, mirrored in zod/crud.zod.ts, re-exported by both barrels, and carried on the legacy ActionSchema as onSuccess? / onFailure?. Producers: the package's own phase2-schemas.test.ts fixture and three ts fences in content/docs/core/enhanced-actions.mdx — nothing else (git grep -l ActionCallback over packages content skills hit the five packages/types files; positive control SchemaNodeSchema hit 22). Runtime readers: none — ActionRunner imports UIActionSchema, never this interface, and its own ActionDef.onFailure is a different (runner-native) meaning. It was the THIRD meaning of one key: objectui#5934 had already retired the runner's callback meaning of onSuccess and converged it on the spec's block.

.changeset/dashboard-config-aria-retired-5852.md

  • names designer.ts → packages/types/src/designer.ts — edited by this change

    Both spellings are named verbatim above so a host can grep its own sources: the retired member is aria, on the TypeScript interface DashboardConfig (@object-ui/types, designer.ts) and on its Zod mirror DashboardConfigSchema (@object-ui/types/zod). It declared { label?: string; description?: string }.

.changeset/issue-5373-retire-crud-schema.md

  • names packages/types/src/crud.ts → packages/types/src/crud.ts — edited by this change

    crud had four declaration faces and no registered renderer, for the whole life of the key: the TS interface (packages/types/src/crud.ts), the zod mirror (packages/types/src/zod/crud.zod.ts), a dedicated branch in validateSchema that affirmatively PASSED it, and CRUDBuilder in @object-ui/core. A node spelling it painted the OBJUI-001 "Unknown component type" panel, and content/docs/api/schema-reference.md published it as reference material — so a reader (or an AI author) who copied the page got a red panel.

  • names packages/types/src/zod/crud.zod.ts → packages/types/src/zod/crud.zod.ts — edited by this change

    crud had four declaration faces and no registered renderer, for the whole life of the key: the TS interface (packages/types/src/crud.ts), the zod mirror (packages/types/src/zod/crud.zod.ts), a dedicated branch in validateSchema that affirmatively PASSED it, and CRUDBuilder in @object-ui/core. A node spelling it painted the OBJUI-001 "Unknown component type" panel, and content/docs/api/schema-reference.md published it as reference material — so a reader (or an AI author) who copied the page got a red panel.

.changeset/param-dialog-title-fallback-4282.md

  • names crud.ts → packages/types/src/crud.ts — edited by this change

    title is declared on no action surface in the ecosystem: it is absent from @objectstack/spec's ActionSchema (44 keys walked at spec 17.0.0), from @object-ui/core's ActionDef and its pinned ACTION_DEF_KEYS / SPEC_ACTION_KEYS inventories, and from @object-ui/types' renderer view (ui-action.ts) and crud.ts ActionSchema / BaseSchema. None of the four action renderers — action:button, action:icon, action:group, action:menu — forwards it either. So the right-hand side of that || could not be reached by authored metadata: a fallback that cannot fire, which is the "declared is not enforced" shape objectstack#4075 exists to reduce. Nothing a user hits changes; the line now reads exactly one key, matching the description line directly below it.

.changeset/record-detail-param-dialog-title-5610.md

  • names crud.ts → packages/types/src/crud.ts — edited by this change

    title is declared on no action surface in the ecosystem: it is absent from @objectstack/spec's ActionSchema (44 keys walked at spec 17.0.0), from @object-ui/core's ActionDef and its pinned ACTION_DEF_KEYS / SPEC_ACTION_KEYS inventories, and from @object-ui/types' renderer view (ui-action.ts) and crud.ts ActionSchema / BaseSchema. None of the four action renderers — action:button, action:icon, action:group, action:menu — forwards it either. So the right-hand side of that || could not be reached by authored metadata: a fallback that cannot fire, which is the "declared is not enforced" shape objectstack#4075 exists to reduce. Nothing a user hits changes; the line now reads exactly one key, matching the description line directly below it.

.changeset/table-renderer-declared-column-contract-5350.md

  • names packages/types/src/data-display.ts → packages/types/src/data-display.ts — edited by this change

    renderers/complex/table.tsx resolved a heading as col.header || col.label and a cell as row[col.accessorKey || col.name]. Neither label nor name is declared on TableColumn, which declares header and accessorKey — both required (packages/types/src/data-display.ts). This was the fourth site of the column-alias family, after data-table, ObjectDataTable and ObjectGrid (objectui#5350).

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with 4b742f41d (merge-base with origin/main): 11 file(s) changed outside .changeset/, read against 1701 pending declaration(s) that publish a body (2303 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3104.0 KB 3104.5 KB
Main entry chunk (gzip) 149.8 KB 350 KB
Entry file index-LmCkDdSa.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.62KB 63.16KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.53KB 4.89KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.96KB 14.83KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.83KB 36.71KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.49KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.44KB 22.41KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 1ac8cb6278ba7d501a9ebe33f69216ea881d748c

Isolated adversarial at-tier review of PR objectui#11003 (card objectui#9256, family D re-measure; Clause-② yes because thirteen published accept sets narrow). Read against GitHub REST, the branch fetched as refs/review/pr-11003 (head 1ac8cb627, three commits over merge parent 42687baf2), and a detached worktree at that head with an offline install, ⛔ not against the dev report 5873403544. Every renderer below was read by me; every probe below was run by me in that worktree and the tree was restored to git status clean afterwards.

① Derived judgments

1. The thirteen narrowed declarations — renderer readership, re-derived. For each row I read the registration that owns the bare key, every alias or namespaced twin of the same literal (the registry snapshot in packages/cli/src/utils/known-schema-types.ts lists them all), the component it names, and SchemaRenderer. SchemaRenderer (packages/react/src/SchemaRenderer.tsx) destructures children and body out of the props bag it spreads, and passes the whole node only as the schema prop, so a channel reaches a component only if the component reads schema.children / schema.body (or spreads the node into something that does). Reads are the component's own property access, destructuring or spread; React children of the component's own JSX and hast/nav-tree children are not the node's channel.

declaration governing registration → reader twins checked reads children / body verdict
markdown plugin-markdown:markdown → MarkdownRenderer reads schema.content, schema.className, hands LazyMarkdown those two console lazy stub, same full type; field:markdown is a field type, not a node no / no (MarkdownImpl's children are hast nodes and React props) narrowing sound
chart bare key owned by plugin-charts:chart → ChartRenderer reads series, xAxisKey, config, colors, chartType, data, className, categoryColors, categoryOrder, isAnimationActive, height chart:bar → same ChartRenderer; view:chart (skipFallback) → ObjectChartBlock, whose only body is a local JSX const; console lazy stub no / no narrowing sound
bar-chart plugin-charts:bar-chart → ChartBarRenderer forwards data, dataKey, xAxisKey, height, className, color console lazy stub no / no narrowing sound
code-editor plugin-editor:code-editor → CodeEditorRenderer forwards value, language, theme, height, readOnly, className, onChange to Monaco none no / no (no channel read in the package) narrowing sound
detail view:detail → DetailView, typed DetailViewSchema; reads resourceId, objectName, fields, sections, tabs, summaryFields, api, data, … detail-view is a different literal (already narrowed); SectionBoundary's children is React no / no narrowing sound
report plugin-report:report → ReportRenderer unwraps spec-report, then DatasetReportRenderer / specReportToPresentation → ReportViewer / LegacyReportRenderer (spreads schema.chart, not the node) spec-report alias → same dispatcher; console lazy stub no / no (the package's only body reads are document.body and CSS text) narrowing sound
list-view plugin-list:list-view → ListViewBlock (elementDataSourceBlock, reads no channel) → ListView; sub-view nodes are built key by key ({ type: 'object-grid', ...baseProps, … }), never ...schema view:list (skipFallback) → same ListViewRenderer no / no (document.body.appendChild only) narrowing sound
page-designer plugin-designer:page-designer → PageDesigner, no schema prop, named props only none no / no narrowing sound
data-model-designer plugin-designer:data-model-designer → DataModelDesigner none no / no narrowing sound
process-designer plugin-designer:process-designer → ProcessDesigner (its local children is a Map over graph edges) none no / no narrowing sound
report-designer plugin-designer:report-designer → ReportDesigner none no / no narrowing sound
object-manager plugin-designer:object-manager → ObjectManager none no / no narrowing sound
field-designer plugin-designer:field-designer → FieldDesigner none no / no narrowing sound

No registration of the thirteen declares a children slot input. The plugins' own exported MarkdownSchema, CodeEditorSchema and BarChartSchema are re-exports of @object-ui/types, so no second published face carries these literals with a live channel. Generic traversers: packages/core validateChildren reads schema.children only (the card's children || body premise for it is gone, as the dev says); sdui-parser validateTree walks to warn. None renders. ⇒ no row is a FAIL.

2. Producers, re-run twice. (a) The repo's own instrument, node scripts/body-dialect-census.mjs --keys over the thirteen plus div, card, page as lit controls, 9118 files at the head: the only children on any of the thirteen is the PR's own nested-refusal case in the new pin; the only body is one detail node in packages/sdui-parser/src/__tests__/body-dialect-6771.test.ts. Controls: div 177 / card 183 / page 54 authored children. (b) An independent string-and-comment-aware object-literal scanner of mine over examples/, apps/ (including apps/site), content/docs/, skills/, packages/**, e2e/, public/, docs/, all of .ts .tsx .js .mjs .cjs .json .md .mdx .yaml .yml (6410 files): the same two hits plus one false positive, the DetailSchema zod arm's own children: member. Controls fire (div 166, card 145, page 34). ⇒ no stored or shipped document starts being refused; nothing needed migrating; the changeset's "no render behaviour changes" is true.

3. Shape. Six declarations carry body?: never / children?: never on the TypeScript face and two retirementTombstone members fed one neitherContentChannelGuidance string on the zod mirror, both MEMBERS (Object.keys(mirror.shape) contains both; parity green in CI). list-view: right to touch the mirror only — ListViewSchema is ListViewAuthored & ListViewRuntimeProps, where ListViewAuthored is a key-remapping mapped type over ListViewInferred = z.input of the mirror (⛔ not Omit, which would erase every declared member through BaseSchema's index signature), so the two members become body?: undefined / children?: undefined on the face; my type-check probe below proves the face refuses both. The six designer faces: correct that they have no mirror — no Designer or ObjectManager name exists under packages/types/src/zod, AnyComponentSchema refuses { type: 'page-designer' } at type today, and the TypeScript-only shape is the nl-query precedent in content-channel-family-d-9256.test.ts.

4. Refusal messages, all read. Every zod string is the corrected objectui#10928 clause (the builder at head says "no render-time error or warning and no element; only the parser tier's not-a-container warning noticed it"; objectui#10956 landed before this branch merged main, and the cross-seat note 5868030743 is satisfied). Each route clause matches the registration I read; each renders clause names keys the renderer reads (markdown content; chart data / chartType / series; bar-chart data / dataKey / xAxisKey; code-editor value / language / theme; detail objectName / resourceId / fields / sections / tabs; report's three paths; list-view objectName / viewType / columns / filter / sort / options; each designer's registered inputs). None says "Did you mean". One text defect, TypeScript docblock only: CodeEditorSchema.children (packages/types/src/form.ts) says the renderer forwards six keys "to Monaco and nothing else", but CodeEditorRenderer also forwards onChange (onChange ?? schema.onChange); the zod string omits "nothing else" and is true. Observation, not a defect of this PR: the detail remedy names sections, which DetailView reads but DetailSchema does not declare (admitted through the index signature / passthrough) — a pre-existing face-versus-renderer gap on view:detail.

5. Pins and ablations. The 97-test pin covers all thirteen: seven zod arms × two channels × five assertions plus controls, and 26 @ts-expect-error lines on the TypeScript face (13 × 2). Run by me: vitest 97 / 97. tsc -p packages/types/tsconfig.test.json on the unmutated head: 0 errors, so all 26 directives fire. My own probe file authoring both channels on all thirteen faces without directives: exactly 26 × TS2322, the div control clean. My A2 (delete FieldDesignerSchema's children?: never): exactly 1 × TS2578 at the field-designer line. My A3 (delete ChartSchema's children?: never): 1 × TS2578 at the chart line plus 1 × TS2322 in zod-mirror-parity. Both match the dev's readings. The tsc-only legs are acceptable: ?: never is erased before vitest runs, the pin says so in its header, the type-check script runs tsc -p tsconfig.test.json, CI's Type Check job runs pnpm type-check (turbo), and PRs objectui#9589 / #10897 / #10907 and the nl-query block use the identical compile-time shape.

6. Downstream. @object-ui/site (apps/site) authors div / card nodes only in app/playground/page.tsx; nothing under apps/site, the repo root (README.md, root configs) or content/docs authors children or body on the thirteen. apps/site has a type-check script and CI's Type Check job runs turbo type-check across the workspace, so the dev's two unrun packages are covered by the green check-run.

7. CI and commits. Head 1ac8cb627: 43 check-runs, 40 success, 3 skipped (Test (coverage), the coverage shard, dependabot), 0 failure; mergeable_state clean. git merge-tree of current origin/main (665025908, nine commits past the merge parent) with this head is conflict-free. The three commits carry author Claude and the model-free Co-Authored-By: Claude trailer only; no model name anywhere (the squash message will be the PR title plus body). The merge commit's resolution of zod/objectql.zod.ts: the three-dot diff against the merge parent is +15 / −0 for that file, SpecRuleConditionSchema (main, objectui#10946) sits directly above LIST_VIEW_NEITHER_CHANNEL (branch), and both are read by ListViewSchema — both sides kept, main's first, as described.

② Semver level

minor for @object-ui/types with an explicit BREAKING note and a migration line, the spelling PRs objectui#9589 / #10897 / #10907 used under the no-major rule; Changeset Bump Policy and Changeset Declaration are green. Every sentence checked: pre-PR each of the seven arms inherited BaseSchema's accepted children member (no override on the merge parent, verified per file) and every TypeScript face inherited children?: SchemaNode | SchemaNode[], so "type-checked, and parsed green where a zod mirror exists" is true; body was already refused on both faces by BaseSchema (base.ts body?: never, base.zod.ts aliasKeyRefusal), so "already refused … now names what the node renders instead" is true; the breaking effect (an authored children on these thirteen is now refused) is declared, and the census shows it reaches no shipped document.

③ Boundary flags

  • Open question 1 (who narrows the 19 public-block arms). Facts verified: the installed spec is @objectstack/spec 17.4.0, whose PageComponentSchema is a strictObject and refuses a flat children with unrecognized_keys on record:details, page:header, page:tabs, element:text and page:card (parsed by me); objectui's AnyComponentSchema accepts children on record:details, page:header, page:tabs, element:text, object-metric and record:alert today (parsed by me), because each arm is BaseSchema.extend(...); objectui#10872's release 5868698636 names its next batch as the flat-props channel and envelope keys over public-blocks.zod.ts and the two objectql.zod.ts arms — the same arms — but "additive, when a producer needs them", so it has no scheduled dispatch. My reading: A, this card, serial after (or folded with, if it dispatches first) objectui#10872's batch on those files. Ruling 5861449497 Q2 A's own criterion — a published arm plus a renderer that reads neither channel is family-D-shaped and moves to objectui#9256 — is what brought the any-typed E3 keys here; the nineteen now have published arms and read neither, so C contradicts that precedent, and B parks a family-D narrowing on a card whose subject is the validator refusing namespaced types and whose carrying batch has no date. Constraint for whoever takes it: record:alert's body is a text prop and must not get the neither-channel tombstone; page:tabs / page:accordion item-level children stay live. Decision is the seat's.
  • Open question 2 (metric-card). Facts true: DashboardWidgetSlotComponentSchema (complex.ts) extends BaseSchema with no children override, so the TypeScript face accepts children; its zod namesake in complex.zod.ts is a non-exported const used only inside DashboardComponentSchema.widgets' union; AnyComponentSchema refuses a bare { type: 'metric-card' } at type (invalid_union); the MetricCard renderer destructures schema away and reads no channel.
  • Out-of-scope findings, both confirmed. record:alert: readProps merges the flat node keys with properties, pickLocalized(props.body) renders it as the message text, and { type: 'record:alert', body: 'msg' } is refused today with "Did you mean body → children? … Every registration that read it now reads children" while { properties: { body } } parses — a wrong remedy at the public door; carrier objectui#10872's flat-props batch. The family-D pin's comment above the chatbot rows ("body is ACCEPTED on chatbot-enhanced and chatbot-floating") is stale: the same file's LIVE CONTROL asserts chatbot-enhanced refuses body with the requestBody message.
  • Serial, one addition to the PR body. Open PR objectui#10997 (not draft) now edits packages/types/src/zod/objectql.zod.ts at ObjectMapConfigSchema, a different site from this PR's ListViewSchema block; whichever lands second re-merges main. objectui#10930, named in the body, is no longer open. No other open PR touches the twelve files.
  • Part of #9256 is correct: OPEN is non-empty (the twenty above). The PR body carries no angle brackets, no line addresses and no model names, and no sentence in it read false against the tree; the registering-package count (23 + core + console) is consistent with my own non-comment call-site count and not load-bearing.

Implemented-by: claude/issue-9256-family-d-remeasure
Reviewed-by: session_01DuWo5bdP9SdVebamn99GGk

VERDICT: PASS


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants