Skip to content

fix(components,types): eight renderers stop reading undeclared node keys; input-otp and loading read their declared spellings (objectui#11347) - #11360

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-11347-components-uncast-reads
Oct 1, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-11347-components-uncast-reads

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Refs #11347
Clause-②: yes (narrowing)

This PR is the @object-ui/components preparation unit of objectui#8347. objectui#8347 is the parent: it removes BaseSchema's index signature, and it lands last. This PR settles the twelve un-cast reads in eight renderers that objectui#8347's P1 mutation reddens, measuring each key on its own:

  • Seven reads are retired.
  • Two move to the spelling the type already declares.
  • One key, list.title (two reads), is kept and declared.

The Clause-② arm covers both directions:

  • The retirements narrow the registry's inputs and the keys the renderers honour.
  • The ListSchema.title declaration widens the TypeScript face. On the zod mirror it newly refuses a non-string title.

64 of the package's 94 test errors are retyped to their concrete node types. The other 30 stay:

  • One is objectui#8347's own probe flip.
  • The other 29 author nodes with no TypeScript declaration at all. The seat moved them to objectui#11364. That is why this PR says Refs.

Round 2 answers the at-tier record (FAIL, one item) and the seat's ruling on the card. My census missed a producer of list.title: the published skills/objectui expressions guide (guides/schema-expressions.md, under os:check). It authors { "type": "list", "title": "Team", ... }, and it says title is read off the node. Under the card's rule 2 the seat ruled to keep the read and declare the key, by 「未声明键随实现,文档随之」. list has no spec row, the renderer reads title, and the registration publishes it. Nothing under skills/ changes.

This body was refreshed at 2026-10-01T09:41Z. It answers every comment posted on this PR since the first body:

  • the at-tier record 5927953448, in this section;
  • the changeset-claim-re-read comment 5927656616, under Files outside the claimed surface and Gates;
  • three Console Performance Budget comments (5927699774, 5928383897, 5928726380). They report PASS and ask nothing.

Per-key verdicts

Spec row. The installed @objectstack/spec is 17.5.0. Its ComponentPropsMap has 55 entries, and none of them is any of the eight node types. A grep of the whole installed package for shouldScaleBackground, showClose, input-otp and dropdown-menu returns zero hits. The control modalCloseButton hits three files, so the grep was reading.

Producers. The census covered:

  • examples/schema-catalog, every entry of these eight node types, key by key;
  • examples/* and content/docs/**;
  • every package README;
  • packages/types/examples;
  • skills/;
  • objectstack origin/main 2742e5370, its examples and packages.

One producer exists: the skills/objectui expressions guide authors title on a list node. This was missed in round 1 and caught by the at-tier record. None of the producers authors any of the other eight read keys. The objectstack hits for type: 'list' and type: 'drawer' are page types, flow variables and a form-view type, not component nodes. The registrations name these keys in their own inputs / defaultProps. None of the eight types is in PUBLIC_BLOCKS, so those names never reach the published sdui.manifest.json.

Runtime. Each key was rendered through the real SchemaRenderer and registry, before and after, in a scratch probe that is not committed.

node key (reads) rule verdict rendered through SchemaRenderer, before then after
list title (2) 2: a producer authors it kept, declared as ListSchema.title?: string on both faces a heading with the title, both before and after; now pinned
loading text (2) 3, near spelling read moves to the declared LoadingSchema.label; text retired with no alias text: a message, then none. label: none, then a message
input-otp maxLength (TS2551) 3, near spelling read moves to the declared InputOTPSchema.length length: 4: 6 slots, then 4. length: 8: 6, then 8. maxLength: 4: 4, then 6
sidebar-menu-button active (read off BaseSchema itself; no node type exists) 3 retired data-active="true", then "false"
drawer footer 3 retired the footer is drawn, then none
drawer showClose 3 retired 1 Close button, then 0
drawer shouldScaleBackground 3 named read retired the vaul root receives the authored false both before and after, through the prop spread
dropdown-menu, popover, sheet modal (1 each) 3 named read retired the Radix root receives the authored value both before and after, through the prop spread

list.title is declared on both faces at once, so no zod-mirror-parity row opens. A non-string title that .passthrough() used to keep unjudged is now refused at title. That follows the wrapperClass precedent from objectui#7722.

H3: the near spellings. For input-otp, all five catalog entries and the docs page spell the key length. The type declares length on both faces with @default 6, so the read moved and the declaration stayed. Before this change, the published 4-digit and 8-digit examples drew six slots. For loading, LoadingSchema.label was declared but inert while an undeclared text was read. The seat accepted moving the read to label over a plain retirement.

Inputs. Where a registration published a retired key as an input, the input goes too:

  • active on sidebar-menu-button;
  • the three drawer keys;
  • modal on popover and on sheet.

dropdown-menu never published modal. sheet's defaultProps also loses its modal seed. list's title input stays.

An independent instrument. pnpm check:component-surface-parity (objectui#4631, report-only) was read at base 770cc5ba4 in a detached control worktree, and again at the head:

  • interface-missing-key falls from 59 to 49. The ten rows that go are exactly these keys; list.title goes because it is declared now.
  • interface-extra-key falls from 121 to 120, because input-otp.length is now read.
  • The total falls from 250 to 239.

P1 measurement (H1)

The un-chained recipe is tsc --noEmit, then tsc -p tsconfig.test.json. It ran with objectui#8347's mutation applied through ablation-replace, and with @object-ui/types rebuilt. The restore was proven after every run:

  • the blob equals HEAD;
  • git diff HEAD on base.ts is empty;
  • the dist index-signature count is back to 2.
tree src program test program
base 770cc5ba4, mutated 12 106 (12 of them the same source sites, so 94 test errors in 20 files)
head 61be40730, mutated 0, so the two list reads compile against ListSchema.title 30
base and head, signature present (control) 0 0

The tests (H4)

64 literals are now typed as the nodes they are, each through a small typed identity per file (actionBar, textNode, selectNode, ...). Excess-property checking therefore runs against the concrete type, not against BaseSchema. The helpers are not generic, so they cannot widen anything. The button variant and size tables and the input inputType table are typed with the declared unions.

list-title-declared-11347.test.tsx pins list.title on three readers:

  • The runtime. The guide's own literal, rendered through the real SchemaRenderer, draws Team as the heading. A list with no title draws none.
  • The zod mirror. A string parses, and a number is refused at title.
  • The compiler. A @ts-expect-error sits on a numeric title, and tsc -p tsconfig.test.json reads it.

The 30 left, by file:

  • objectui#8347's probe flip (1): form-renderers.test.tsx, where label authors its retired content spelling on purpose.
  • No TypeScript node type exists (29); the seat moved these to objectui#11364:
    • The properties bag of element:text, element:text_input and element:record_picker:
      • page-variables.test.tsx (5, one of them dataSource)
      • text-input.test.tsx (5)
      • text-input-description-association.test.tsx (1)
      • required-marker-markup.test.tsx (1)
      • record-picker-label-association.test.tsx (1)
    • items on page:tabs: page-tabs-builtin-label-i18n-4645.test.tsx (2) and chrome-i18n-no-provider-fallback.test.tsx (1).
    • The executor keys of action:button: action-params-templates-7867.test.tsx (5).
    • The page kind home with kind: html-page-lazy-blocks.test.tsx (1) and react-page-scope.test.tsx (1).
    • The legacy props alias: alias-precedence-cross-channel.test.tsx (4).
    • A type that only the test registers, with properties: degenerate-config-bag.test.tsx (2).

Files outside the claimed surface

Each was forced by a verdict, and the at-tier record judged each one.

  • packages/types/src/crud.ts: the CRUDDialogSchema.showClose docblock no longer names the drawer's retired look-alike read as live.
  • packages/types/src/__tests__/layout-default-jsdoc-7361.test.ts: the test now pins that retirement, with a firing control.
  • packages/components/src/renderers/__tests__/node-slot-numeric-falsy.test.tsx: the drawer footer row is removed.
  • .changeset/8318-jsdoc-default-tag-corrections.md: a dated correction is appended, and the frontmatter is byte-identical.
    • changeset-claim-re-read flagged renderers/overlay/drawer.tsx:38 in this changeset. That address sits in the original bullet, inside the append-only prefix.
    • In round 2 the appended correction binds the same address, in its own sentence, to 33f4a1980, the commit that added this changeset. I read that tree through a REST contents read, and line 38 there is the drawer registration's showClose read. The correction also names that read by what it is.
    • The prefix occurrence stays unbound, because editing it would break append-only. The first 2879 bytes are byte-identical to origin/main (cmp -n 2879 exits 0). The gate still reports the prefix occurrence, which is report-only.

The branch merges cleanly with origin/main (git merge-tree exit 0).

Gates

The PR head is 57c757ffa. It differs from 61be40730 by one .changeset/*.md file and touches no TypeScript program.

  • Build:
    • At 61be40730: pnpm --filter '@object-ui/components^...' build exits 0.
    • At 57c757ffa: the scoped turbo run build that check:skill-examples --build-filter names succeeds on all 29 tasks.
  • Type check: at 61be40730, pnpm --filter @object-ui/types type-check and pnpm --filter @object-ui/components type-check both exit 0, with 0 error TS lines. That run also consumes the new pin's @ts-expect-error.
  • Tests:
    • At 61be40730: vitest run packages/types/ + the new pin passed 310 files and 7822 tests.
    • At 57c757ffa: vitest run packages/components/ gave 349 files passed and 1 skipped (350); 3481 tests passed and 24 skipped; the lock reported VERDICT command-exit 0.
    • Round 1, at bba957503: examples/schema-catalog/ + widget-dom-leak-sweep + registry-inputs-spec-parity passed 38 files and 2677 tests.
  • check:skill-examples at 57c757ffa exits 0 after the scoped build: 18 of 18 ts fences are judged with 0 failed, 70 json fences parse with 0 failed, and the gate reports "Every marked skill example holds up against the built types."
  • Other checks:
    • Exit 0: check:new-line-citations, check:control-bytes, check:changeset-claims (report-only; see the note below), check:pending-changeset-literals, check:doc-types, check:doc-fences, check:doc-example-ids, check:component-surface-parity, check:test-path-roots, check:vi-mock-specifiers, check:phantom-deps, check:self-import, check:prompt-keys, check:handler-key-reads, check:skills-paths, changeset presence and no-major.
    • check-governed-queue-guard --test reads NOT GOVERNED.
  • Pending changesets. I re-read every pending changeset the gate lists as naming this round's surface (list.tsx, drawer.tsx, data-display.ts, data-display.zod.ts). There are 13 of them: 5926, 6349 batch 1, 6881, 6940, 6951, 6972, 7352, 7694, 7722, 8331, 8478, 9256-list, and the 5350 table one. 8318 is flagged separately, by its line address. None is made false by this branch except 8318, which carries the correction.
    • 7722 says the list renderer reads wrapperClass and that the key was undeclared; both still hold.
    • 9256-list says no body / children read files under ListSchema; that still holds.
    • 8478's .describe() strings gain no line address.
    • The other ten are about different members.
  • Narrowed lint (round 1): the 28 touched .ts/.tsx files gave 0 errors and 73 warnings, against the same 0 and 73 for those files at base. Type-aware linting is off and no custom rule reads the disk, so the narrowed run speaks for the untouched files too. Round 2 adds one test file, which CI's Lint reads.

Acceptance notes (observed, not filed)

  • The prop spread. SchemaRenderer still spreads unread node keys onto the component. An authored modal or shouldScaleBackground therefore still reaches the Radix or vaul root. An authored title on a list also lands as a DOM title attribute on the ol/ul, and text / label on loading land on its wrapper. These belong to the strict face (objectui#8345, objectui#11070) and to the bare-spread family.
  • Family consistency. DialogSchema and ContextMenuSchema declare modal, and SheetSchema and DialogSchema declare footer. Rule 3 retires the same keys on these four nodes, because no producer authors them there.
  • LoadingSchema.size. The declared union is 'sm' | 'default' | 'lg', and the renderer branches on sm / md / lg / xl. NOT MEASURED, carried for the next touch.
  • input-otp separator draws nothing. It is filed as objectui#11365.

Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT


Generated by Claude Code

claude added 5 commits October 1, 2026 07:19
… keys; loading and input-otp read their declared spellings (objectui#11347)

The display, feedback and form units of objectui#11347, the components
preparation card for objectui#8347's BaseSchema index-signature removal.
Each key was measured on its own: the installed @objectstack/spec (17.5.0)
has no row for `list`, `loading` or `input-otp`, and no catalog entry,
example, docs page, package README or objectstack-shipped document authors
any of the three read keys.

- list: the `title` heading read is retired (rule 3: no spec row, no
  producer). Its registration input goes with it.
- loading: the undeclared `text` read moves to the declared
  `LoadingSchema.label` ("Loading text/message" on both faces), which was
  inert. One spelling, no alias.
- input-otp: the undeclared `maxLength` read moves to the declared
  `InputOTPSchema.length`, the spelling all five catalog entries and the
  docs page author. Measured through the real SchemaRenderer, `length: 4`
  and `length: 8` drew six slots before and draw four and eight now.

The body/children tombstone texts on the zod mirror and the matching
docblocks are brought in line with what the renderers now read.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
…ive` (objectui#11347)

The navigation unit of objectui#11347. `active` was read off a `schema`
typed `BaseSchema` itself: no type declares it for `sidebar-menu-button`,
the installed @objectstack/spec has no row for the node, and no catalog
entry, example, docs page or README authors it (the five catalog sidebars
author none). With no spec row and no producer, the read is retired along
with its registration input; `isActive` is no longer driven by the node.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
…reading undeclared keys (objectui#11347)

The overlay unit of objectui#11347. The installed @objectstack/spec has
no row for any of these four nodes, and no catalog entry, example, docs
page, README or objectstack-shipped document authors any of the keys, so
each named read is retired (rule 3):

- drawer: `shouldScaleBackground`, `footer` and `showClose`. The drawer
  draws no footer and no Close button from the node any more.
- dropdown-menu, popover, sheet: `modal`.

Their registration inputs (and sheet's `modal` seed) go with them.
Measured through the real SchemaRenderer: an authored `modal` or
`shouldScaleBackground` still reaches the Radix / vaul root through the
prop spread, which the strict authoring face owns; the named reads were
redundant on that path.

Collateral, each forced by a verdict here:
- `node-slot-numeric-falsy.test.tsx` loses its `drawer footer` row (the
  slot no longer exists).
- `CRUDDialogSchema.showClose`'s docblock and its pin in
  `layout-default-jsdoc-7361.test.ts` named the drawer's look-alike read
  as live; both now record it retired.
- the pending objectui#8318 changeset gets a dated correction for the same
  sentence; its frontmatter is unchanged.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
…objectui#11347)

64 of the 94 test errors objectui#8347's P1 mutation raises in this
package are literals checked against `BaseSchema` (the `renderComponent`
parameter, `SchemaRenderer`'s `schema`, or a `SchemaNode` child slot) that
author keys their concrete node type declares. Each is now typed as that
node through a small typed identity per file (`actionBar`, `textNode`,
`selectNode`, ...), which keeps excess-property checking against the
concrete type rather than switching it off. The button variant / size and
input type tables are typed with the declared unions, which the concrete
type now demands.

Left as they are, on purpose:
- 29 literals author a node no `@object-ui/types` declaration covers:
  the public blocks' `properties` bag (`element:text`,
  `element:text_input`, `element:record_picker`), `page:tabs`' `items`,
  `action:button`'s executor keys, the page kinds' `kind`, the legacy
  `props` alias bag and a test-registered probe type. Handed back on
  objectui#11347 rather than cast or widened.
- `label`'s retired `content` spelling is a deliberate probe; it is
  objectui#8347's to flip.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
…derers read (objectui#11347)

The input-otp page's schema block shows `length` as the optional slot count
it is (default 6) and says the renderer now reads it; the loading page
gains the declared `label`. Plus the changeset for objectui#11347.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation package: types package: components tests labels Oct 1, 2026
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 2 address(es) in this pull request's own prose name a tree it replaced

Each was read from a tree this change itself moves, so a reader who follows it lands somewhere else. ⛔ Nothing here blocks and nothing here says the sentence is false — the question asked is arithmetic: does this diff move the line that number points at?

  • in .changeset/8318-jsdoc-default-tag-corrections.md, renderers/overlay/drawer.tsx:38 — this change rewrites packages/components/src/renderers/overlay/drawer.tsx:38

    (renderers/overlay/drawer.tsx:38) belongs to DrawerSchema.

  • in this body, renderers/overlay/drawer.tsx:38 — this change rewrites packages/components/src/renderers/overlay/drawer.tsx:38

    • changeset-claim-re-read flagged renderers/overlay/drawer.tsx:38 in this changeset.

⛔ The repair is not to correct the number. Changing :246 to :274 is true today and born false again on the next insertion — objectui#9509 states that before anything else. Bind the number to the tree it was read from (`:246` at `b8a006883d`, `:274` at this head), which cannot re-stale because each number names its own tree; or state a rule instead of a coordinate, the way objectui#9495 replaced a file count with "every file in git diff --name-only against the merge base".

⚠️ 42 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/5632-sidebar-trigger-dom-passthrough.md

  • names renderers/navigation/sidebar.tsx → packages/components/src/renderers/navigation/sidebar.tsx — edited by this change

    The renderer forwarded its whole prop bag to SidebarTrigger, which spreads its own rest onto the ANGLE-BRACKETS(button) it renders — so every authored SDUI key on the node became an attribute. Fourteen of them, one more than the shape this target derives from, because this registration also never destructured schema: every other registration in renderers/navigation/sidebar.tsx names it (they need the node's child list — spelled schema.body when this change landed, schema.children since objectui#6771 retired that spelling), while this one renders no children and named only className, so the node SchemaRenderer injects on every render rode the spread and landed as schema="[object Object]".

.changeset/5632-svg-host-dom-passthrough.md

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

    Both renderers forwarded their whole prop bag to the SVG they render, so every authored SDUI key on the node became an attribute — 14 per target, and icon="check" on all 71 icon nodes in the schema catalog. The two nodes declare different keys, and each renderer consumes its own node's keys by name: IconSchema (packages/types/src/layout.ts) against the pass-through docblock in renderers/basic/icon.tsx, and SpinnerSchema (packages/types/src/feedback.ts) against the one in renderers/feedback/spinner.tsx. icon and color are IconSchema's alone — SpinnerSchema declares neither. Read those two declarations for what they carry; this paragraph deliberately copies no member list. So the SDUI pass-through list withholds nothing they need.

.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/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/6349-types-internal-name-collisions-batch-2.md

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

    MenuItem — renamed to AppMenuItem in app.ts. app.ts declared a flat, all-optional interface (type?: 'item' | 'group' | 'separator', label, icon, path, href, children, badge, hidden) — the @deprecated legacy navigation item that AppComponentSchema.menu, AppAction.items and menuItemToNavigationItem read. overlay.ts declared a discriminated union, MenuCommandItem | MenuDividerItem, whose command arm requires label and whose both arms tombstone type as type?: never (objectui#6523) — precisely the key app.ts declares as a three-value enum. Re-pointing either at the other would have made an authored type: 'separator' legal on one side and a type error on the other, so the two names had to part. @object-ui/types continues to publish overlay's union as MenuItem and app's interface as AppMenuItem, exactly as before.

.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/6541-sonner-button-variant-enum.md

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

    What was wrong. The same key on the same component shipped as two disagreeing published faces: an open string to anyone validating (@object-ui/types/zod), and a closed six-member union to anyone type-checking (@object-ui/types, SonnerSchema.buttonVariant in feedback.ts). The TS face was already correct — only the mirror is changed here, so this is the mirror being made to agree with a declaration that sat beside it all along.

.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/6939-overlay-trigger-mirror.md

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

    patch, not minor: the accept set only widens toward what already renders. Every key involved is optional, and children stays legal — it is BaseSchema's own optional key, merely no longer demanded here. No document that validated before this change stops validating; documents the renderers already draw start validating. The TypeScript twins in packages/types/src/overlay.ts move in the same stroke, so the published declaration and the published validator keep saying the same thing.

.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.

.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/7081-overlay-trigger-union.md

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

    This is a widening, not a replacement: every singular trigger keeps type-checking unchanged. The Zod mirror is untouched — zod/overlay.zod.ts already spelled every one of these keys z.union([SchemaNodeSchema, z.array(SchemaNodeSchema)]) — and so is the runtime: every overlay renderer hands schema.trigger to renderChildren, whose Array.isArray branch has served the array form all along, and every registration's defaultProps.trigger ships as an array. What changes is that the TypeScript face stops under-reporting an accept set that already ships: copying a renderer's own default into a typed document is no longer a type error against the type that shipped it. The seven docs pages' trigger rows follow the declaration.

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

  • 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/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).

.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.

.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 renderers/data-display/list.tsx → packages/components/src/renderers/data-display/list.tsx — 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 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 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/7918-zod-lazy-getter-identity.md

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

    ⚠️ Also settled while locating the ten: AppMenuItemSchema has no declaration of its own — it is the barrel alias of app.zod.ts's MenuItemSchema, while the barrel's own MenuItemSchema is overlay.zod.ts's. Two different schemas, so the list really is ten entries and not nine.

.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/8338-retire-toast-action.md

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

    What was wrong. The two faces shared nothing, and one of them had no JSON inhabitant at all. packages/types/src/feedback.ts declared action?: { label: string; onClick: () => void } — both members REQUIRED and onClick a function, so a JSON document could omit the key but never author it — while packages/types/src/zod/feedback.zod.ts declared z.union([SchemaNodeSchema, z.array(SchemaNodeSchema)]), a node or a list of nodes. Disjoint accept sets, one of them empty: the same document got a green safeParse and a tsc refusal, and no spelling satisfied both. renderers/feedback/toast.tsx read NEITHER — it reads variant, title, description, duration, buttonVariant, className and buttonLabel, and the file has exactly one ComponentRegistry.register call, so the zero is a reading and not a failed scan.

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

    What was wrong. The two faces shared nothing, and one of them had no JSON inhabitant at all. packages/types/src/feedback.ts declared action?: { label: string; onClick: () => void } — both members REQUIRED and onClick a function, so a JSON document could omit the key but never author it — while packages/types/src/zod/feedback.zod.ts declared z.union([SchemaNodeSchema, z.array(SchemaNodeSchema)]), a node or a list of nodes. Disjoint accept sets, one of them empty: the same document got a green safeParse and a tsc refusal, and no spelling satisfied both. renderers/feedback/toast.tsx read NEITHER — it reads variant, title, description, duration, buttonVariant, className and buttonLabel, and the file has exactly one ComponentRegistry.register call, so the zero is a reading and not a failed scan.

.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/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/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 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.

.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/9710-overlay-trigger-bare-string.md

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

    ⛔ No published FACE moves — and one published FILE does. The accept set is the one both faces already shipped, and this is the implementation catching up to it — the direction objectui#7105 ruled for node slots, which relax the renderer rather than narrow the declaration. ⛔ No type, no accept set, no export and no runtime behaviour moves in @object-ui/types: every changed line in packages/types/src/overlay.ts is a docblock line. What moves there is documentation that SHIPS. The eight trigger docblocks named renderChildren(schema.trigger) inside each Radix trigger, and the renderers now spell that read renderTriggerSlot(XTrigger, schema.trigger) — so the JSDoc an author's editor shows described a call that no longer exists. Those eight now name the current spelling, which the emitted dist/overlay.d.ts carries and the old spelling no longer appears in; and the line addresses they carried are gone, because packages/components moves lines, nothing re-derived those numbers, and shipped documentation should not rot with them. That correction is why @object-ui/types takes a patch here.

.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.

.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.

.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.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with d0fba91aa (merge-base with origin/main): 32 file(s) changed outside .changeset/, read against 1915 pending declaration(s) that publish a body (2531 pending in total). · run

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3552.6 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-DoP9Wh0Q.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.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
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.54KB 3.46KB
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) 570.46KB 136.72KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 229.96KB 63.80KB
fields (index.js) 261.05KB 66.23KB
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.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.55KB 11.41KB
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.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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) 53.15KB 15.45KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.34KB 37.30KB
plugin-designer (index.js) 216.54KB 44.64KB
plugin-detail (index.js) 245.45KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.25KB 44.58KB
plugin-gantt (index.js) 173.11KB 43.10KB
plugin-grid (index.js) 231.53KB 63.58KB
plugin-kanban (index.js) 49.49KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 23.54KB 7.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.91KB 10.00KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
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.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
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) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
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: bba957503a98d1725e038a83ae6772a37125e4f6
Local-runs: none

Rendered 2026-10-01T08:46Z from card #11347 (body and all three comments), PR #11360 (body, the 32-file list, the diff against main at merge-base 770cc5ba4), the eight renderers and every touched types / docs / changeset file read at the head and at origin/main (5638529e6) with git show and git grep only, the installed spec's source at the 17.5.0 tag commit 0f6dcac5e9, and the 43 check-runs on the head, read last at 2026-10-01T08:41Z. The dev report 5927683269, the seat ACCEPT 5927753260 and the PR body were read as claims and re-derived; nothing was built, run or re-run.

① Derived judgments

Spec row, all eight node types — RIGHT. At 0f6dcac5e9 (packages/spec/package.json reads 17.5.0) ComponentPropsMap has 55 keys and none of list, loading, input-otp, sidebar-menu-button, drawer, dropdown-menu, popover, sheet. A grep of the whole packages/spec tree for showClose|shouldScaleBackground|input-otp|dropdown-menu returns 0 hits while the control modalCloseButton hits 5 files. Rule 1 is closed for every key: no declaration against the spec was made, and none is owed.

Producer census, re-grepped at origin/main — HOLDS for eleven of the twelve reads, DOES NOT HOLD for list.title.

  • Catalog: the eight components-* directories author none of the nine keys on these nodes. verification-form.json's "text" is on a label node; the maxLength hits (auth/two-factor.json, components-form-form/registration-form.json) are on input nodes and form fields; all five input-otp entries author length (4, 6, 8, 6, 6). HOLDS.
  • content/docs: the eight component pages carry none of the keys. sidebar.mdx's active?: boolean is on a SidebarItem of a different items / groups shape, not the sidebar-menu-button node; guide/expressions.md:225's title sits on the nested card template, not on the list. HOLDS.
  • Package READMEs, root README, packages/types/examples: the list nodes there carry no title. HOLDS.
  • objectstack: the type: 'drawer' hits (examples/app-showcase/src/ui/views/task.view.ts, packages/lint/src/showcase-shape.fixtures.ts) are form-view kinds with sections, not component nodes. HOLDS.
  • skills/ — DOES NOT HOLD. skills/objectui/guides/schema-expressions.md, lines 447 to 455 at origin/main, a guide linked from skills/objectui/SKILL.md and carried under the os:check marker that check:skill-examples reads, authors { "type": "list", "title": "Team", "ordered": true, "items": [...] } under the comment "title and ordered are read off the node". The PR body ("I searched ... skills/ ... None of them authors any of the nine read keys") and the changeset's census sentence are false for this one key. After this head a published authoring guide asserts a read the renderer no longer performs, so list.title is not a rule-3 key as filed: a real producer authors it, which is rule 2's frame, and the card's acceptance line "the docs and doc snippets for these node types agree with each verdict (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2)" is unmet for list. The PR touches nothing under skills/. The retirement direction is not disputed here: the producer is a doc snippet, not a shipped document, and the startup-focus axis points the same way. What is wrong is the census claim as shipped in the changeset, and the producer left asserting the read. This is the FAIL item; the remedy is at the end.

The two read moves — RIGHT. Each honours a declared key, and no fallback reads the old spelling (AGENTS.md §5 #0.1).

  • input-otp maxLength to length: InputOTPSchema.length?: number with @default 6 is declared on both faces, and every catalog entry and the docs page author length. The head reads only schema.length || 6, the pre-existing default shape honouring the declared default; the maxLength={length} on line 35 is the OTP primitive's prop, not a schema read. Registration inputs and defaultProps follow. Not an alias.
  • loading text to label: LoadingSchema.label ("Loading text/message") is declared on both faces; the head reads only schema.label; no text read or fallback remains; no producer authors either spelling (the catalog's with-text.json draws its caption with a sibling text node). The seat ACCEPTed the move over a plain retirement (声明而未兑现是实现缺口); concur. Honouring an existing declaration widens nothing.

The retirements — what the renderer now draws for an authored value.

  • list.title (two reads): no h3 heading; registration input title removed. Census: see above, the FAIL item.
  • sidebar-menu-button.active: isActive is no longer set from the node, so data-active="false"; input removed. RIGHT.
  • drawer.footer: no DrawerFooter; the slot input removed; the node-slot-numeric-falsy row removed with a docblock note. RIGHT.
  • drawer.showClose: no Close button. It was opt-in (schema.showClose && inside the footer), so no default drawer loses one; input removed. RIGHT.
  • drawer.shouldScaleBackground: the named prop is gone and the Drawer wrapper's own default applies; an authored value still reaches vaul through the {...props} spread, before and after (the strict face's, objectui#8345 / objectui#11070); input removed. RIGHT.
  • modal on dropdown-menu, popover, sheet: the named prop is gone and the Radix default applies when unauthored; an authored value still reaches the root through the spread; inputs removed from popover and sheet, and sheet's defaultProps.modal seed removed. dropdown-menu never carried a modal input at origin/main, so the changeset's "each retired key also leaves its registration's inputs" is over-inclusive there, a prose nit. RIGHT.

Published-surface narrowing — judged on all of it, not on two rows. Seven ComponentMeta.inputs rows leave five registrations (list.title, sidebar-menu-button.active, drawer.shouldScaleBackground, drawer.showClose, drawer.footer, popover.modal, sheet.modal), plus sheet's defaultProps.modal seed; two rows are respelled to the declared member (loading text to label, input-otp maxLength to length, defaultProps likewise). None of the eight types is in PUBLIC_BLOCKS (59 entries), so sdui.manifest.json does not move; the narrowing is on the registry's inputs publication face. The changeset states the removals in one sentence and the two respellings as "write length" / "write label"; it does not say in so many words that label and length enter inputs, and it need not: those rows mirror members the TypeScript types already declare, so nothing widens. Family consistency holds: DialogSchema declares footer and modal, SheetSchema declares footer (its footer read stays), ContextMenuSchema declares modal; DrawerSchema, PopoverSchema and DropdownMenuSchema declare none of the retired keys.

@object-ui/types — no accept-set change, RIGHT. data-display.ts, feedback.ts, form.ts, overlay.ts and crud.ts change docblocks only; the zod files change .describe() text and the body / children tombstone messages (the "What it renders instead" lists) only. No member is added or removed on either face.

Pins — RIGHT, not vacuous. layout-default-jsdoc-7361 row 24: the control expect(drawer).toContain('DrawerSchema') proves the read returned the drawer renderer (the head file carries the token in its type annotation and in the retirement comment), then not.toMatch(/schema\.showClose/). The origin/main file carries schema.showClose &&, so the inverted assertion fires on the pre-change tree and passes on the head, whose only showClose tokens are in the retirement comment. The expectAbsentTagWithEvidence tokens drawer.tsx, DrawerSchema and objectui#11347 are all present in the head crud.ts docblock. node-slot-numeric-falsy: the drawer footer row is gone; the dialog, sheet, page:card and table footer rows remain.

.changeset/8318-jsdoc-default-tag-corrections.md — RIGHT. The first 2,879 bytes are byte-identical to origin/main, frontmatter '@object-ui/types': patch included; 585 bytes are appended. The dated note quotes the earlier bullet accurately ("showClose's one other occurrence ... belongs to DrawerSchema") and leaves that change's verdict, no @default, unchanged.

Docs — RIGHT for the three named faces. input-otp.mdx: length?: number // (default 6) matches the type; the callout's "4- and 8-digit examples above drew six slots" is true of 4-digit.json (length: 4) and 8-digit.json (length: 8). loading.mdx: label?: string is added and the callout names label; the page's size union ('sm' | 'md' | 'lg' against the type's 'sm' | 'default' | 'lg') pre-exists and is the carried NOT MEASURED item. crud.ts cites the drawer renderer by path and says DrawerSchema never declared the key.

Tests — no widening. The 23 typed-identity helpers are monomorphic, each annotated with one concrete node type and returning its argument; the diff adds no as any, no as unknown and no @ts-expect-error. The P1 figures (src 12 to 0, test 106 to 30) are the dev's local measurement and are read as a claim; the diff is consistent with it: grepped at the head, no read of an undeclared key remains in the eight renderers.

② Semver level

  • @object-ui/components: minor — RIGHT. The change narrows the registry's inputs face and the set of keys the renderers honour. objectui AGENTS.md §9 版本号策略 marks objectui's own breaking changes minor with the breaking semantics stated in the body and forbids major (check-changeset-no-major; the fixed group sits at 17.6.0). The body states the breaking semantics per key.
  • @object-ui/types: patch — RIGHT. Published JSDoc text in dist/*.d.ts and tombstone message strings; no member added or removed. The level objectui#8318 used for the same class.
  • Coverage: both released packages the diff changes carry a changeset. Check-runs Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Claim Re-read and Changeset Overwrite Report: success.
  • Clause-②: yes (narrowing) — the arm holds. What moves out: seven inputs rows, one defaultProps seed, two respelled rows, and the honoured-key set of eight renderers. Nothing widens: label and length entering inputs mirror already-declared members, and loading honouring label fulfils a declaration that already existed.
  • One changeset sentence moves with the FAIL item: "No catalog entry, example, docs page, package README or objectstack-shipped document authors any of them" is false for list.title (the skills/ guide).

③ Boundary flags

  • Dev deviation 1, four files outside the claimed surface (crud.ts, layout-default-jsdoc-7361.test.ts, node-slot-numeric-falsy.test.tsx, the 8318 changeset): each is forced by a verdict and is judged above. Answered: in scope by consequence.
  • Dev deviation 2, loading moved to label instead of a plain retirement: judged in ①; concur with the seat's ACCEPT.
  • Dev deviation 3, the acceptance line "0 errors except the probe keys" is not met (29 literals with no TypeScript face): settled by the seat in ACCEPT 5927753260, objectui#11364 (direction A). NOT a FAIL on this PR per the dispatching seat; Refs #11347 is right.
  • Dev deviation 4, the run resumed at bba957503 after an API-limit stop: no bearing on the diff; every gate family is re-answered by the head's check-runs.
  • open_questions[0] (who gives the public blocks, page:tabs items, action:button executor keys, page kind home and the props alias a TypeScript face): answered by the seat, objectui#11364. Escalation closed.
  • Out-of-scope findings: input-otp separator draws nothing, objectui#11365 (settled, not this PR's); an authored modal / shouldScaleBackground still reaching the Radix / vaul root through the prop spread, the strict face's (objectui#8345 / objectui#11070), carried in the Acceptance notes; LoadingSchema.size union against the renderer's branches, NOT MEASURED, carried for the next touch. Each answered.
  • Gates the dev declared to CI (check:doc-snippets, check:doc-examples, check:sdui-registration-pins): answered by the head's check-runs. Doc Snippet Type Check, Doc Component Type Check, Doc Example Id Check, Skill Example Check, Type Check, Lint, Test and all eight test shards, Test (dist pins), Build & E2E, Build Docs: success.
  • New flag, raised here and escalated to the seat: the skills/objectui/guides/schema-expressions.md producer for list.title (①). Skill Example Check is green on the head, so no gate sees it: the snippet is well-formed, it is only no longer true.
  • CI on bba957503: 43 check-runs, 40 success, 3 skipped (dependabot and the two coverage matrix placeholders), none in progress.

Remedy for the one FAIL item (small; nothing else need move). On the same branch: (a) correct the producer under AGENTS.md #0.1 — drop "title": "Team" and the "title and ordered are read off the node" comment from the schema-expressions.md snippet, or re-word it to ordered alone, then run pnpm check:skill-examples; (b) correct the census sentence in .changeset/11347-components-uncast-reads.md and in the PR body to name that producer and its correction; or, if the seat prefers, (c) hand list.title back under rule 2 with the four-axis frame instead of retiring it here. A new head then takes a new record.

Implemented-by: claude/issue-11347-components-uncast-reads
Reviewed-by: session_01VhxTqosz7wn54ahqyxgERT

VERDICT: FAIL

claude added 3 commits October 1, 2026 08:51
…a.title (objectui#11347, round 2)

The at-tier record on PR #11360 found a producer the census missed: the
published `skills/objectui` expressions guide authors
`{ "type": "list", "title": "Team", ... }` and says `title` is read off
the node. The seat ruled under the card's rule 2, by 未声明键随实现,
文档随之: `list` has no row in the installed @objectstack/spec, the
renderer reads `title` and the registration publishes it, so the key is
declared rather than retired.

- `list` draws `schema.title` as its heading again, and the registration's
  `title` input returns.
- `ListSchema.title?: string` is declared on the TypeScript face and on
  the zod mirror. A non-string `title` is now refused by name where
  `.passthrough()` used to keep it unjudged. Both faces gain the key
  together, so no zod-mirror-parity row opens.
- The list docs page documents `title`. The refusal messages and
  docblocks no longer call it retired.
- `list-title-declared-11347.test.tsx` pins it on three readers: the
  guide's literal drawn through the real SchemaRenderer (with a no-title
  control), the zod mirror, and the compiler (`@ts-expect-error` on a
  numeric title).
- The changeset names the guide as `list.title`'s producer. It also
  stops claiming that `dropdown-menu` lost a `modal` input it never
  published.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
… a fresh literal (objectui#11347)

`satisfies` keeps a literal fresh, so under objectui#8347's P1 mutation the
control's literal was still checked against `SchemaRenderer`'s `BaseSchema`
and `title` read as an excess key. A typed const carries the declaration.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
…rrection to its tree (objectui#11347)

The `changeset-claim-re-read` comment flagged `renderers/overlay/drawer.tsx:38`
in `.changeset/8318-jsdoc-default-tag-corrections.md`, because this branch
rewrites that line. The flagged address is in the original bullet, inside
the append-only prefix, so it stays byte-identical. The appended correction
now binds the same address, in its own sentence, to `33f4a1980` (the commit
that added this changeset), where line 38 is the `drawer` registration's
`showClose` read. It also names that read by what it is, so the published
CHANGELOG line is anchored. The first 2879 bytes still `cmp` equal to
origin/main.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3552.5 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-CsN8j3XM.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.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
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.54KB 3.46KB
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) 570.62KB 136.73KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 229.96KB 63.80KB
fields (index.js) 261.05KB 66.23KB
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.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.93KB 11.29KB
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.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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) 53.15KB 15.45KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.34KB 37.30KB
plugin-designer (index.js) 216.54KB 44.64KB
plugin-detail (index.js) 245.45KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.25KB 44.58KB
plugin-gantt (index.js) 173.11KB 43.10KB
plugin-grid (index.js) 231.53KB 63.59KB
plugin-kanban (index.js) 49.49KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 23.54KB 7.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.91KB 10.00KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
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.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
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) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
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

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3552.5 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-BWP6-KqZ.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.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
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.54KB 3.46KB
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) 570.62KB 136.73KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 229.96KB 63.80KB
fields (index.js) 261.05KB 66.23KB
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.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.93KB 11.29KB
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.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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) 53.15KB 15.45KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.34KB 37.30KB
plugin-designer (index.js) 216.54KB 44.64KB
plugin-detail (index.js) 245.45KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.25KB 44.58KB
plugin-gantt (index.js) 173.11KB 43.10KB
plugin-grid (index.js) 231.53KB 63.59KB
plugin-kanban (index.js) 49.49KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 23.54KB 7.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.91KB 10.00KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
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.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
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) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
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: 57c757ffaf03258cfa980d55ea58690c911dbacc
Local-runs: none

Delta record, round 2, rendered 2026-10-01T09:49Z. It supersedes record 5927953448 (FAIL, one item, on bba957503) for this head. Inputs: the card's two new comments (seat ruling 5927981915, dev round-2 report 5928858594, both read as claims), the PR's edited body, its 34-file list, the diff against main, and the round-2 delta git diff bba957503 57c757ffa (7 files, +120 / −19, three commits: 5cd2c5884, 61be40730, 57c757ffa), every line read; the touched files read whole at the head with git show; the 43 check-runs on the head, read last at 2026-10-01T09:48Z. Everything not re-judged below carries forward from 5927953448 unchanged: the spec row (no 17.5.0 row for any of the eight types), the census for the other eleven reads, the two read moves, the seven retirements, the pins, the tests, the three boundary dispositions. Nothing was built, run or re-run.

① Derived judgments

1. The round-1 FAIL item is closed; docs and snippets agree with list.title's verdict. list.tsx reads schema.title again and draws it as an h3 above the list; the list registration publishes { name: 'title', type: 'string' } again; list.mdx documents title?: string // heading drawn above the list; the skills/objectui/guides/schema-expressions.md snippet is untouched (nothing under skills/ changes, confirmed by the delta stat) and its sentence "title and ordered are read off the node" is true again. The TypeScript docblocks and the zod .describe() text return to "around the title and the list", and both body / children tombstones list title among what the renderer reads. RIGHT.

2. The declaration is right on both faces, matches the registration's published type, and is not a declaration against the spec. packages/types/src/data-display.ts line 300: title?: string on ListSchema, with a READ SITE docblock naming the renderer, the registration and the producer. packages/types/src/zod/data-display.zod.ts lines 188–189: title: z.string().optional(). Registration input type string. The three agree. Declared together on both faces, so no zod-mirror-parity UnmirroredDeclared row opens (CI Test and the eight shards are green on the head). The installed 17.5.0 ComponentPropsMap has no list row (55 keys, verified in round 1), so no spec declaration is contradicted; this is the objectui#7927 ruling's "declare on its schema" arm under the card's rule 2, ruled by the seat in 5927981915 with the four-axis frame (未声明键随实现,文档随之). The new refusal is a consequence, not a widening: a non-string title that .passthrough() kept unjudged is now refused at title, the same shape objectui#7722 recorded for wrapperClass on this very schema. RIGHT.

3. Every round-2 changed line, by commit.

  • 5cd2c5884 (6 files): the renderer read and input restored (above); data-display.ts gains the title member and docblock and drops the two "has since been retired" sentences; data-display.zod.ts gains title and restores the two "What it renders instead" lists; list.mdx gains one interface line; the new pin list-title-declared-11347.test.tsx; the changeset reworded (below). All consistent with each other and with the ruling.
  • 61be40730 (1 file): the untitled control becomes { ...GUIDE_LIST, title: undefined } typed ListSchema rather than a fresh literal. Right: the control now exercises the declared type.
  • 57c757ffa (1 file): the appended 8318 note gains one sentence binding renderers/overlay/drawer.tsx:38 to the tree at 33f4a1980. Verified locally with git show 33f4a1980:packages/components/src/renderers/overlay/drawer.tsx: line 38 is {schema.showClose && ...}, the drawer's showClose read; 33f4a1980 is the objectui#8318 PR commit (docs(types): point nine @default tags at a measured read site (objectui#8318) (#8756)). The binding is true. The clone is shallow, so I make no claim about which main commit first carried the file; the PR body's "the commit that added this changeset" is a claim about the docs(types): point nine @default tags at a measured read site (objectui#8318) #8756 branch commit and is fair on its subject line.
  • The new pin is not vacuous. Runtime: the guide's own literal, typed ListSchema, drawn through the real SchemaRenderer, yields an h3 reading "Team" with two ol items; the LIVE CONTROL without a title yields no h3 and still two items. Zod: the literal parses; title: 42 is refused with title on the issue path. Compiler: the @ts-expect-error line on a numeric title is consumed by tsc -p tsconfig.test.json (CI Type Check green, so the directive is live). Three readers, each with a firing control.
  • The changeset 11347-components-uncast-reads.md: the census sentence now names the producer ("the published skills/objectui expressions guide authors title on a list node") and claims zero producers only for the others; "Seven reads are retired"; the inputs sentence lists the five registrations that lose rows and says "dropdown-menu never published modal" (the round-1 nit, closed); the Types section says ListSchema gains title?: string on both faces and "Apart from ListSchema.title, no member is added or removed and no accept set changes". Every sentence checked against the diff holds. Its frontmatter level is judged in ②.
  • skills/, the governed surface, is untouched (Governed Surface Queue Guard green).

4. The Clause-② sentence — RIGHT as a line; its consequence is the ② finding. The line stays Clause-②: yes (narrowing), one arm from the closed pair, and the body's sentence names both directions: the retirements narrow the registry's inputs and the honoured-key set; the ListSchema.title declaration widens the TypeScript face and the mirror newly refuses a non-string title. With both directions present, (narrowing) is the breaking one and the right single arm; the sentence is accurate. What the sentence admits, a widening of a published face, is what ② measures the levels against.

5. The append-only prefix still holds. cmp -n 2879 of the head's .changeset/8318-jsdoc-default-tag-corrections.md against origin/main exits 0; the file is 2,879 identical bytes plus 719 appended. The original bullet's renderers/overlay/drawer.tsx:38 sits inside that prefix, unchanged, and is now bound in the note's own sentence. The dev's deviation note is right: the addendum's premise pointed at the prefix, and the prefix was correctly left alone.

6. Pending changesets naming list.tsx / drawer.tsx / data-display.ts / data-display.zod.ts. Ten name a full path at the head (10074, 6940, 7352, 7694, 7722, 8318, 8331, 8478, 9256-list, 5350 table); twenty name a basename; the dev's thirteen is the bot's list, between the two. Spot-checked in full: 7722 declares wrapperClass on ListSchema on both faces and records that the renderer reads it onto the wrapper; round 2 restores the "around the title and the list" wording, so it holds. 9256-list says list reads neither content channel and that the item channel is a different key; round 2 changes neither, and the tombstones it describes still carry title in their "renders instead" list. Across every pending changeset, the only sentences about list/title/ListSchema or the drawer showClose read are in 7722, 9256-list and 8318, and none is made false. Changeset Claim Re-read: success on the head.

② Semver level

  • @object-ui/components: minor — RIGHT, carried from round 1 (narrowing of the registry's inputs face; the repo spells breaking changes minor).
  • @object-ui/types: patch — WRONG at this head; it was right at bba957503 and round 2 moved the ground under it. Round 1's types diff was docblocks and tombstone strings. Round 2 adds title?: string to ListSchema on the shipped .d.ts and to the mirror's .shape, and the mirror newly refuses a non-string title. That is the exact class objectui#7722 graded on this same schema, and its changeset says why in so many words: "minor, not patch — the published face gains … members … it is dispatched under the contract-review tier precisely because it widens the PUBLISHED surface", with the by-name refusal recorded as "a behaviour change". The PR body cites 7722 as the precedent it follows, and the changeset's own Types section says a member is added; the frontmatter says patch. The fleet's rule for the line points the same way: a Clause-②: yes takes at least minor on the package whose published surface moves, and here that package is @object-ui/types. Changeset Bump Policy cannot see this: it runs check-changeset-no-major.mjs only, so its green on the head is not a verdict on the level. In the fixed group the released version moves the same either way; the declared level is what the changelog and the release notes read, and it is a stated face of this review.
  • Coverage: both released packages the diff changes carry the changeset; Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report: success.
  • Clause-②: yes (narrowing) — the arm holds (①.4).

③ Boundary flags

  • Round-1 FAIL item (list.title census): closed by the seat's ruling 5927981915 and the round-2 diff (①.1–①.2).
  • Round-1 nit (dropdown-menu never had a modal input): closed in the changeset and the PR body.
  • Dev round-2 deviation (the addendum's premise pointed at the prefix): answered in ①.5; the prefix was rightly left alone and the address is bound in the appended sentence.
  • open_questions: none. out_of_scope_findings: none. The round-1 dispositions carry: objectui#11364 (29 literals, direction A), objectui#11365 (input-otp separator), the strict-face spread note (objectui#8345 / spec(types): 32 keys the renderers read are refused by the strict authoring face — declare each or rule it runtime-only, the ruled precondition before objectui validate goes strict (objectui#5250) #11070), LoadingSchema.size NOT MEASURED.
  • Gates the dev ran locally at 61be40730 / 57c757ffa (P1 0 / 30, type-check, tests, check:skill-examples 18/18 and 70/70): read as claims; every derived family is answered by the head's check-runs.
  • New flag, raised here: the @object-ui/types level (②). It is the only item.
  • CI on 57c757ffa: 43 check-runs, 40 success, 3 skipped (dependabot and the two coverage matrix placeholders), none in progress. Skill Example Check, Doc Snippet Type Check, Type Check, Lint, Test and all eight shards, Test (dist pins), Build & E2E, Build Docs, Spec Main Shape Gate: success.

Remedy for the one FAIL item (one word and one sentence; nothing else on this head need move): in .changeset/11347-components-uncast-reads.md, set '@object-ui/types': minor and add the 7722 spelling in the Types section — the published face gains a member and the mirror refuses a non-string title by name, hence minor. A new head then takes a new record; everything judged RIGHT here carries to it.

Implemented-by: claude/issue-11347-components-uncast-reads
Reviewed-by: session_01VhxTqosz7wn54ahqyxgERT

VERDICT: FAIL

…a member (objectui#11347, round 3)

Round 2 declared `ListSchema.title` on the shipped `.d.ts` and on the
mirror's `.shape`, and the mirror now refuses a non-string `title` by
name. objectui#7722 graded that class on this same schema `minor` ("the
published face gains ... members"), so `patch` was wrong. The Types
section now says so, in the same words 7722 uses.

Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3552.5 KB 3574.6 KB
Main entry chunk (gzip) 150.4 KB 350 KB
Entry file index-BWP6-KqZ.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.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
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.54KB 3.46KB
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) 570.62KB 136.73KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 229.96KB 63.80KB
fields (index.js) 261.05KB 66.23KB
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.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.93KB 11.29KB
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.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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) 53.15KB 15.45KB
plugin-charts (index.js) 84.07KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.34KB 37.30KB
plugin-designer (index.js) 216.54KB 44.64KB
plugin-detail (index.js) 245.45KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.25KB 44.58KB
plugin-gantt (index.js) 173.11KB 43.10KB
plugin-grid (index.js) 231.53KB 63.59KB
plugin-kanban (index.js) 49.49KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 23.54KB 7.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.91KB 10.00KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
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.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
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) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 21.59KB 7.71KB
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: 172751bab4931d6b501af30ed074fe0d7526da7d
Local-runs: none

Delta record, round 3, rendered 2026-10-01T10:06Z. It supersedes record 5928971172 (FAIL, one item, on 57c757ffa) for this head. Inputs: the dev round-3 report 5928999501 (read as a claim), the PR's current body, the round-3 delta git diff 57c757ffa 172751bab (one commit, 172751bab), the changeset file read whole at the head, and the check-runs on the head, read last; first read at 2026-10-01T09:53Z with 14 still in progress, then polled every two minutes within the brief's 25-minute bound. Everything not re-judged below carries forward from 5928971172 and 5927953448 unchanged. Nothing was built, run or re-run.

① Derived judgments

1. The delta is exactly one file. git diff --stat 57c757ffa 172751bab lists .changeset/11347-components-uncast-reads.md alone: 3 insertions, 1 deletion, one commit (docs(changeset): @object-ui/types is minor, because ListSchema gains a member). No source, test, docs or skills/ line moves, so every ① judgment from rounds 1 and 2 stands as read: the spec row, the census with the skills/ producer named, the two read moves, the seven retirements, the ListSchema.title declaration on both faces, the pins, the 8318 append-only prefix (cmp -n 2879 against origin/main still exits 0, the file being untouched since 57c757ffa), and the pending changesets. RIGHT.

2. The level and the new sentence are right, and every other sentence in the file still holds. Line 3 now reads '@object-ui/types': minor. Line 31 adds, in objectui#7722's wording: "minor, not patch — the published face gains a member. ListSchema.title is a new member of the shipped .d.ts and of the mirror's .shape, and the mirror refuses a non-string title by name, the class objectui#7722 graded minor on this same schema." Each clause is true of the diff: data-display.ts line 300 declares title?: string, data-display.zod.ts lines 188–189 declare z.string().optional(), and 7722's changeset graded the same move on ListSchema minor for the same two reasons. Lines 6 to 29 are byte-for-byte the round-2 text judged in 5928971172: the census sentence naming the skills/objectui expressions guide as list.title's one producer, the kept-and-declared paragraph, the two read moves, the seven retirements, the inputs sentence with "dropdown-menu never published modal", and the Types section ending "Apart from ListSchema.title, no member is added or removed and no accept set changes". Re-read against the head, none is made false by the new frontmatter or the new sentence. RIGHT.

3. The PR body is unchanged and states no types level. Its Clause-②: yes (narrowing) line and both-directions sentence stand as judged in round 2; a regex over the current body for a @object-ui/types level finds none, so nothing there contradicts the changeset.

② Semver level

  • @object-ui/components: minor — RIGHT, carried.
  • @object-ui/types: minor — RIGHT at this head. The round-2 item is closed: the published face gains a member (ListSchema.title on the shipped .d.ts and the mirror's .shape) and the mirror newly refuses a non-string title, which is objectui#7722's minor class on this same schema, and the changeset now says so in its own text. The fixed group's minor and the fleet's "a Clause-②: yes takes at least minor" rule are both satisfied on the package whose published surface moves.
  • Coverage: both released packages the diff changes carry the one changeset. Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report: success on the head.
  • Clause-②: yes (narrowing) — the arm holds (round 2, ①.4).

③ Boundary flags

  • Round-2 FAIL item (@object-ui/types: patch): closed by 172751bab (②).
  • Round-1 FAIL item (list.title census) and its nit: closed at 57c757ffa, unchanged here.
  • Dev round-3 report: open_questions none, out_of_scope_findings none; its four local gate readings (changeset presence, fixed / no-major, changeset-claims, pending-changeset-literals) are read as claims and are each answered by the head's check-runs.
  • Carried dispositions: objectui#11364 (29 literals, direction A), objectui#11365 (input-otp separator), the strict-face spread note (objectui#8345 / spec(types): 32 keys the renderers read are refused by the strict authoring face — declare each or rule it runtime-only, the ruled precondition before objectui validate goes strict (objectui#5250) #11070), LoadingSchema.size NOT MEASURED.
  • CI on 172751bab: 43 check-runs. At the first read 25 were complete and 14 in progress; six polls at two-minute intervals brought the pending count 13, 10, 8, 7, 5, 0, and at the final read, 2026-10-01T10:06Z, all 43 were complete: 40 success, 3 skipped (dependabot and the two coverage matrix placeholders), none failed, none in progress. Type Check, Lint, Test and all eight shards, Test (dist pins), Doc Snippet Type Check, Skill Example Check, README Export Check, Spec Main Shape Gate, Build & E2E, Build Docs: success.

Implemented-by: claude/issue-11347-components-uncast-reads
Reviewed-by: session_01VhxTqosz7wn54ahqyxgERT

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 1, 2026 10:07
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 1, 2026 10:07
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: components package: types tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants