Skip to content

feat(types): declare the read keys the strict authoring face refused (objectui#11070) - #11115

Merged
objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/issue-11070-strict-face-read-keys
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/issue-11070-strict-face-read-keys

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Refs #11070
Clause-②: yes — declaring a read key widens the strict accept set of the published StrictAnyComponentSchema (@object-ui/types/zod); a runtime-only ruling instead corrects corpus documents. The PR waits for the director seat's contract review.

Refs, not a closing keyword, on purpose. Of the card's 32 pairs, 20 leave class (ii) here: 14 are declared, and 6 leave because their documents are corrected. The other 12 stay on objectui#11070 (see "Remaining on objectui#11070"), so the card stays open after this lands. Two rounds are in this PR; round 2 carries the seat's answers to round 1's questions. Draft, for the director seat's contract review; the dev does not mark it ready.

What changed

  • Declared on the TypeScript face and the zod mirror.
    • form.showSubmit on FormSchema: a boolean, default true.
    • form.fields[] on FormField / FormFieldSchema: multiple, rows, accept, dimensions, reference, min, max, minLength, maxLength and pattern. A hand-authored form has no object schema behind it, so the renderer hands each field widget the field ENTRY ITSELF as its metadata carrier (field: field.field || field at the one renderFieldComponent call in renderers/form/form.tsx). The built-in input / textarea branches spread the entry onto the native control. All but pattern are the spec's FieldSchema members by reference, on both faces: SpecField['KEY'] on the TypeScript face, and stripImportedDefaults(SpecFieldSchema).shape.KEY on the zod face. pattern is a string: the spec does not declare it, and JSON has no RegExp. It is also the field-level spelling that the validation.pattern refusal already directs JSON authors to. multiple is read by the file, image, lookup and user widgets; the built-in select branch still ignores it (objectui#11116). reference is round 2: it is the spec spelling of a lookup's target, which the lookup and user widgets read beside the legacy reference_to, and reference_to stays refused by the strict face.
    • dataSource on object-grid, object-form, object-kanban and list-view, and (round 2, the seat folding in the same family under objectui#6678) on object-gantt, object-map and object-calendar. Each is the spec's ElementDataSourceSchema, by reference, as element:number already declares it in public-blocks.zod.ts. Every one of these registrations is gate-wrapped (elementDataSourceBlock), so ElementDataSourceGate reads the binding off the node and lands its object on objectName. The tolerant face still refuses the documented bindings on the nodes that require their own objectName / mode / record source, and nothing here changes that (objectui#11117).
  • object-chart's dataSource is withdrawn, and pinned as still refused (round 2). buildComponentScope in renderers/layout/react-page.tsx builds every public data block's node as { dataSource, ...props, type: tag }, with the host's ADAPTER (or null) under dataSource. object-chart-react-tier-node-10770.test.ts pins that node, with dataSource: null, as valid on the mirror and through safeValidateSchema. Declaring the binding refused it: 7 red. See "Remaining on objectui#11070".
  • list-view's dataSource in app-shell's relay census (round 2; the claim widened to this one line). ObjectView.relayRungCensus-7559.test.ts gains one ABSENCES entry, dataSource, of kind unread. The reason is measured: ListView has no read of schema.dataSource. The binding is resolved one layer up, by the registered list-view renderer ListViewBlock through ElementDataSourceGate, and renderListView bypasses that layer: it renders ListView directly with schema={fullSchema} and takes the adapter as its separate dataSource argument (ds). The census's own unread check re-derives the first half on every run.
  • object-view slots. ObjectViewSchema.table withholds dataSource on both faces, as a record source the view owns. It joins data / staticData / bind under the objectui#10976 rule, and the zod twin refuses it by name. ObjectViewSchema.form carries it, because that slot withholds nothing but the identity keys.
  • Documents corrected (round 2; the claim widened to exactly these).
    • fields-lookup/basic-lookup.json and multi-select-lookup.json: reference_to becomes reference.
    • fields-password/with-minimum-length.json: min_length becomes minLength.
    • fields-auto-number/date-based-ticket-id.json and invoice-number-format.json: format is DROPPED, not renamed. FormField declares no autonumberFormat, and nothing on the form path reads an auto-number format: AutoNumberField renders the value only.
    • guide/schema-playground.md: the flat validation: { pattern, message }, which objectui#5186 removed, now reads as the field-level pattern string. The dialect FormFieldSchema.validation 的 zod 镜像(FieldConstraintsSchema)与 FieldValidationRules 形状完全不符:拒绝 TS 契约合法的对象形、放行渲染器从不读的扁平形 #5186 kept cannot carry this rule in JSON, because its pattern.value must be a compiled RegExp. The message has no field-level spelling, so it is gone.
    • api/schema-reference.md: the page region's children becomes components, which is what the page renderer reads.
    • plugins/plugin-detail.mdx: the page:tabs items move under properties, the spelling the platform's producers write. ⛔ This is no ruling on whether the flat spelling is an authoring channel for page: / record: blocks; that stays objectui#10872's open question.
    • Round 1 also corrected guide/objectos-integration.mdx, whose snippet put the adapter into ObjectGridSchema.dataSource (TS2741 under check:doc-snippets once the binding was typed).
  • Ledger rows the declarations move, and only those.
    • form-field-zod-coverage gained 10 keys.
    • zod-mirror-parity: SPEC_DERIVED_PAIRS gained FormFieldSchema and ObjectKanbanSchema. FormFieldSchema's one-key UnmirroredDeclared entry (field) is now SPEC-DERIVED by membership, so the header's split figures and history moved with it. No ledger KEY set changed.
    • imported-defaults-8317: IMPORTED gained FieldSchema, whose walk reaches a fifth z.lazy.
    • object-view-slot-key-lists: the source member counts moved, and dataSource is classified in both slots.
    • list-view-spec-parity: dataSource goes in a new PAGE_COMPONENT_ENVELOPE category, checked to behave as the spec binding.
  • Changeset: .changeset/11070-strict-face-read-keys.md, @object-ui/types minor. It names every declared key and what now refuses. Among those refusals: a node whose dataSource holds an adapter or null (the react-page wrapper's in-memory nodes, which are rendered, not validated) is refused by safeValidateSchema on the declared blocks.
  • ⛔ Not touched: strict-authoring-face.ts, the .passthrough() of the rendering face, the class (iii) pairs (objectui#6152), PR feat(cli): objectui validate and objectui check judge through the strict authoring face (objectui#5250, slice A) #11069, and the widgets' dual reads.
  • Merged origin/main once (6fe4b631e, no rebase), because main had moved api/schema-reference.md. At d1e683fa1 main has no further change on this PR's paths.

M3, before and after

My port of PR #11069's M3 classifier (a scratch script, never committed) is scripts/measure-strict-authoring-face.mjs's corpus loaders plus #11069's findUndeclaredKeys (at a11f73347). It runs over the SHIPPED StrictAnyComponentSchema from a freshly built packages/types/dist. At base it read exactly the card's figures.

reading base 88fbd793d head 42feeeb25
node documents 588 588
refused by the strict face 158 96
of them strict-only 120 58
refused by the tolerant face 38 38 (the same documents)
class (ii) pairs / occurrences / strict-only 32 / 149 / 141 12 / 38 / 38
class (iii) 10 / 15 / 13 10 / 15 / 13
class (i), M1 corpora 47 / 69 / 49 47 / 69 / 49

The 12 left are exactly the seat's expectation: the 9 dashboard pairs, return_type, summary_type and columns. No pair entered any class. The tolerant face refused the same 38 documents both times. The corrected documents that it refused before are still refused for OTHER reasons: schema-reference's page for pageType: "detail", and schema-playground's form for its string options.

Per pair

Read sites are cited by symbol and quoted expression, not by line (AGENTS.md #11). "Probe" means a scratch test, never committed. It rendered each corpus document through the real SchemaRenderer and registry, with @object-ui/fields registered, once with the key and once without it, and compared the settled markup.

# pair read site docs route ruling / evidence
1 form · showSubmit form renderer: showSubmit = true in the schema destructure; submit button under {showSubmit && ( 76 (a) declared probe: the submit button appears only when the key is removed
2 form · fields[].multiple FileField / ImageField (?.multiple), LookupField (fieldMeta?.multiple), UserField (delegates) 6 (a) declared probe: input multiple on file and image
3 form · fields[].rows built-in textarea branch (spread); RichTextField (richField?.rows || 8, markdown) 5 (a) declared probe: rows="6" against rows="8" or none
4 form · fields[].accept FileField (fileField.accept.join(',')) 1 (a) declared probe: accept="application/pdf"
5 form · fields[].dimensions VectorField (vectorField?.dimensions || value.length) 2 (a) declared probe: (768D) against (5D)
6 form · fields[].min NumberField (numberField?.min); built-in input spread 2 (a) declared probe: native min. The form sets no noValidate
7 form · fields[].max as min 2 (a) declared probe: native max
8 form · fields[].minLength built-in input / textarea spread 1 (a) declared probe: native minlength
9 form · fields[].maxLength built-in input branch (maxLength ?? max_length), textarea branch and counter 1 (a) declared probe: native maxlength
10 form · fields[].pattern built-in input spread 1 (a) declared probe: native pattern. A string
11 form · fields[].return_type FormulaField (formulaField?.return_type || 'text'), snake only 3 remaining on objectui#11070 spec returnType, which no widget reads
12 form · fields[].summary_type SummaryField (summaryField?.summary_type || 'count'), snake only 3 remaining on objectui#11070 spec summaryOperations (an object)
13 form · fields[].reference_to LookupField (reference_to || reference), UserField (reference || reference_to) 2 declared the spec's reference; fixtures corrected seat's answer A. reference_to stays refused by the strict face
14 form · fields[].min_length buildValidationRules (minLength ?? min_length), object-bound paths only 1 fixture corrected to minLength seat's answer A. min_length stays refused
15 form · fields[].columns (grid field) GridField (cfg.columns) 3 remaining on objectui#11070 GridColumnDefinition is not the shape GridField reads
16 form · fields[].format (auto-number) none on this path 2 documents corrected (dropped) probe: identical markup. No autonumberFormat is declared or read
17 form · fields[].validation.message the form renderer only REPORTS it as a rule that validates nothing 1 document corrected the regex is now the field-level pattern
18–23 dashboard · widgets[].options. data / xField / yField / value / description / trend DashboardGridLayout / DashboardRenderer (options.data, options.xField || 'name', options.yField || 'value', options.value ?? …; { ...widget, ...options }) 7 / 6 / 6 / 5 / 1 / 1 remaining on objectui#11070 (to a decision) the spec's widget options is an OPEN object the strict face closes; TS types options as unknown
24–26 dashboard · widgets[].component. chartType / xAxisKey / series DashboardRenderer renders widget.component as a node 1 / 1 / 1 remaining on objectui#11070 the slot is BaseSchema by the objectui#8344 / objectstack#8593 routing
27 object-grid · dataSource ElementDataSourceGate (binding read off the node; object lands on objectName) 2 (a) declared objectui#6678
28 object-form · dataSource same gate (ObjectFormRenderer) 1 (a) declared same
29 object-kanban · dataSource same gate (ObjectKanbanRenderer) 1 (a) declared same
30 list-view · dataSource same gate (ListViewBlock) 2 (a) declared (round 2) census entry unread, reason measured above
31 page · regions[].children none: the page renderer reads region.components 1 document corrected now components
32 page:tabs · items (flat) PageTabsRenderer (schema?.items, the hoisted key) 1 document corrected now properties.items. No ruling on the flat position (objectui#10872)

Outside the 32-pair population, the same declaration (round 2, same family) also lands on object-gantt, object-map and object-calendar · dataSource. The strict face refused it by name there, measured, while the tolerant face accepted the same documents.

Remaining on objectui#11070

  • fields[].return_type and fields[].summary_type: snake_case spellings with no read of the spec's spelling to declare instead.
  • The grid field's columns: the element shape is undecided.
  • The 9 dashboard pairs: to a decision.
  • object-chart · dataSource: withdrawn in round 2 (see "What changed"). The react-page wrapper writes the adapter on the node; SchemaRenderer strips it, and the gate ignores a non-binding value.

Tests and gates

Round 2 figures unless marked. Commits: 863d71e87 (declarations), 184d3c165 (documents), e7afb7d96 (changeset), 42feeeb25 (the exact-type pin; head). Exit codes were captured before any pipe.

gate commit exit verdict
pnpm --filter @object-ui/types type-check (including tsc -p tsconfig.test.json, which judges the parity ledgers) 42feeeb25 0 clean
pnpm exec vitest run packages/types/ 42feeeb25 0 Test Files 282 passed (282) · Tests 6506 passed (6506)
pnpm --filter @object-ui/types build 863d71e87 source 0 dist completeness: 1 package(s) complete
downstream consumers type-check, against the rebuilt dist: core, components, fields, react, plugin-form, plugin-grid, plugin-kanban, plugin-list, plugin-view, app-shell, plugin-designer, plugin-detail, plugin-calendar, plugin-gantt, plugin-map, plugin-timeline, plugin-tree, plugin-dashboard, sdui-parser, plugin-charts 184d3c165 0 20 of 20 type-check: Done
app-shell's census plus every elementDataSource reader test, ListViewBlock, ObjectView.tableSlotRelay-10976, gridNonAuthorKeys, and every test outside packages/types that imports @object-ui/types/zod (81 files) 184d3c165 0 Test Files 81 passed (81) · Tests 1032 passed (1032)
examples/schema-catalog/, packages/cli/, packages/core/ 184d3c165 0 Test Files 242 passed (242) · Tests 6184 passed / 27 skipped
packages/components/src/renderers/form/ 184d3c165 0 Test Files 67 passed (67) · Tests 459 passed / 17 skipped
packages/fields/ 184d3c165 0 Test Files 219 passed / 1 skipped (220) · Tests 3497 passed / 7 skipped
pnpm check:doc-snippets (Doc Snippet Type Check), after building its closure 42feeeb25 0 681 of 681 block(s) judged, 0 failed
pnpm --filter @object-ui/types lint, and eslint on the census file 42feeeb25 0 0 errors; no finding on an added line (eslint JSON over the 11 touched types files and the census file)
node scripts/check-changeset-presence.mjs · pnpm changeset:check 42feeeb25 0 · 0 declares .changeset/11070-strict-face-read-keys.md · No changeset declares a major bump
pnpm check:changeset-claims · check:pending-changeset-literals 42feeeb25 0 · 0 report-only
pnpm check:control-bytes · check:new-line-citations 42feeeb25 0 · 0 OK (scanned 9443 tracked text file(s)) · 0 new citation(s)
pnpm check:spec-symbols · check:element-data-source-declaration · check:handler-key-reads · check:test-path-roots · check:doc-types · check:doc-fences · docs:check-links · check:doc-examples · check:doc-example-ids 42feeeb25 all 0 OK
node scripts/check-governed-queue-guard.mjs --test over the 22 changed paths 42feeeb25 0 NOT GOVERNED

NOT MEASURED locally, left to CI: the Spec Main Shape Gate (it builds @objectstack/spec main) and the repository-wide lint.

Reverse verification

  • Ablations. Each was predicted before the run and applied through objectstack's scripts/ablation-replace.mjs, which checks that the anchor hit, that the blob moved, and that the restore left the blob equal to HEAD with git diff HEAD empty.

    ablation predicted measured
    A1 zod FormFieldSchema.multiple deleted (round 1) 2 red + parity tsc red 2 red / 34 green; tsc -p tsconfig.test.json exit 2
    A2 zod FormSchema.showSubmit deleted (round 1) 2 red + tsc red 2 red / 34 green; tsc exit 2
    A3 zod ObjectKanbanSchema.dataSource renamed away (round 1) 1 red + tsc red 1 red / 35 green; tsc exit 2
    A4 zod FormFieldSchema.reference deleted 2 red + tsc red 2 red / 60 green; tsc exit 2
    A5 zod ObjectGanttSchema.dataSource renamed away 1 red + tsc red 1 red / 61 green; tsc exit 2
    A6 zod ListViewSchema.dataSource renamed away 3 red (the pin, sanctioned-local, envelope) + tsc red 3 red / 59 green, but tsc exit 0
    A6b the same, after the fix below tsc red tsc exit 2 (TS2344, TS2559 on the binding pin)
    A7 the census dataSource line deleted 1 red 1 red / 24 green (leaves NO member both unrelayed and undeclared)

    A6 showed that the type-level pin was blind for list-view. ListViewSchema is derived from its mirror, so a member that leaves the mirror resolves to the index signature's unknown, and an IsAny check passes unknown. The pin now asserts that each binding member IS the spec's ElementDataSource (42feeeb25).

  • Consumers read the rebuilt declarations (round 1). A temporary plugin-form file assigned rows: 'four' and an adapter-shaped dataSource; tsc --noEmit exited 2 (TS2322, TS2353). The file was removed.

Acceptance notes

  • object-chart and the react-page wrapper. buildComponentScope in renderers/layout/react-page.tsx still writes the adapter (or null) under dataSource on every public data block's node. It comments that data blocks read it "from props", but SchemaRenderer strips that key from the props it spreads, and ElementDataSourceGate ignores a value that is not a binding. So on the blocks declared here, such a node now fails safeValidateSchema; it is rendered, never validated. Only object-chart has a pin that validates one.
  • Docs pages still teach the legacy spellings, out of this PR's surface. fields/lookup.mdx still teaches reference_to and fields/password.mdx teaches min_length, in TypeScript fences. The fields/auto-number.mdx headings ("Custom Format", "Date-Based Format") now show only the seeded values.

Queue fix (17.5.0 filter shape)

Round 3, after the merge queue dequeued this PR on CI_FAILURE (merge group head 7c3a0340, CI run 36674156292; the seat's diagnosis is comment 5905013609). Written by the dev dispatched from session https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm, 2026-09-30.

Cause. main resolves @objectstack/spec 17.5.0, whose ElementDataSourceSchema.filter takes the ViewFilterRule array ([{ field, operator, value }], migration element-data-source-and-object-block-filter-rule-array). This PR declares dataSource by reference to that schema, and the previous head's CI ran on 17.4.0. Three literals on this PR's surface still wrote the record form.

Commits.

  • e2c19f95d: merge of origin/main at 0ffc423b1 (a merge commit; no rebase, no force-push). No conflicts; six files auto-merged: imported-defaults-8317.test.ts, zod-mirror-parity.test.ts, objectql.ts, zod/form.zod.ts, zod/imported-defaults.ts, zod/objectql.zod.ts.
  • bdd950ec6: the fix, and the head. Three paths:
    • packages/types/src/__tests__/strict-face-read-keys-11070.test.ts: BINDING, which the seven BOUND_NODES pins use, moves to filter: [{ field: 'project', operator: 'equals', value: 'acme' }]. The pins still measure only that the key is declared.
    • packages/types/src/__tests__/object-kanban-record-source-7780.test.ts ("PR feat(types): declare ObjectKanbanSchema.groupBy and .limit, retire groupField on both faces (objectui#7322 item 1) #7774's two EXCLUDED readings"): the fragment moves to the same rule array, so the refusal it asserts is again the record-source rule's RECORD_SOURCE_REQUIRED, not the filter shape.
    • content/docs/utilities/data-objectstack.mdx: the fence under "Kanban", which that pin mirrors, moves to the same form. No other fence on the page changed.

Reproduced first, on the merged tree (e2c19f95d, spec 17.5.0, before the fix): the two files gave Tests 8 failed | 39 passed (47). The seven BOUND_NODES pins got invalid_type at dataSource.filter ("filter on this element data source takes the ViewFilterRule ARRAY form"), and the 7780 pin got expected [ undefined ] to include 'RECORD_SOURCE_REQUIRED'. These are the queue's two failures.

Census of filter under a dataSource

The instrument is a scratch script, not committed; its method is stated here so the reading can be re-taken. Population: every tracked file of the ref, enumerated with git ls-tree and read with git cat-file from that same ref. It parsed 637 .json files, 349 json fences and 1128 ts/tsx/js fences in .md / .mdx, and walked 5992 ts/tsx/js sources with the TypeScript compiler. A hit is a filter member of a dataSource object literal, or of a const that a dataSource names. Each hit's value is judged by the installed 17.5.0 ElementDataSourceSchema.shape.filter, not by its spelling. Control: a text scan for a dataSource object whose filter comes before its first closing brace matched 34 files. Every one of them without a structural hit is CHANGELOG prose naming the binding's key list, or a code comment (RelatedList.listFilter.test.tsx).

On the merged tree e2c19f95d it read 37 filter literals under a dataSource. 12 of them sit on one of the seven declared blocks by literal type, and BINDING reaches all seven through it.each. The record form on the seven blocks: 7 literals, counting BINDING once. Fixed here: the 3 that went red or that a pin mirrors. Left as they are, not edited:

where block literal why it is left
data-objectstack.mdx, the fence under "Narrowing a saved view" object-grid { "total": { "$gt": 100 } } No pin mirrors it and nothing goes red. The tolerant face already refuses that fence on main, for objectName (objectui#11117); on this head it reports dataSource.filter as well. The page still teaches a filter spelling the 17.5.0 spec refuses, and so does its TypeScript excerpt of the binding (filter?: FilterCondition).
ListView.elementDataSource.test.tsx, "AND-combines the binding filter with the view's, never replacing it" list-view { owner: 'me' } A render test through the gate, never validated. Green.
ListView.sharedGate.test.tsx, "AND-combines the component's own filter with the view's and the binding's" list-view { owner: 'me' } The same.
strict-face-read-keys-11070.test.ts, the refusal case "a binding that names no object" object-kanban { a: 1 } Still refused, so green. On 17.5.0 it is refused at dataSource.object AND at dataSource.filter, so the case no longer isolates the reason it is named for. Measured: with a rule-array filter it is refused at dataSource.object alone.

Also refused by the 17.5.0 filter, though not the record form: 6 legacy tuple arrays (such as [['owner', '=', 'me']]) on the seven blocks, in the render tests ObjectGrid.elementDataSource.test.tsx (2), ObjectKanban.elementDataSource.test.tsx (2), ObjectGantt.elementDataSource.test.tsx (1) and ObjectMap.elementDataSource.test.tsx (1). All green: none of them validates the node. On bdd950ec6 the same census reads 4 record-form literals on the seven blocks, the four in the table.

Changeset

.changeset/11070-strict-face-read-keys.md is unchanged, because no sentence in it is false on 17.5.0. The one sentence a 17.5.0 move could falsify, "the tolerant face refused the same documents both times", was measured again. 613 node documents were judged by the tolerant face of main 0ffc423b1 and of this head, both on 17.5.0: 179 docs json fences, 432 schema-catalog documents, and the two pre-fix data-objectstack.mdx fences. No verdict differs; each tree refuses 58. The apps' authored documents were not measured again; the census found no dataSource filter among them.

Gates, at bdd950ec6

Exit codes were captured before any pipe.

gate exit verdict
pnpm exec vitest run packages/types/ 0 Test Files 284 passed (284) · Tests 6532 passed (6532)
pnpm --filter @object-ui/types type-check (tsc, tsconfig.examples.json, tsconfig.test.json) 0 clean
166 test files outside packages/types: each one that imports @object-ui/types/zod, names ElementDataSourceSchema, ElementDataSourceGate, elementDataSource or a dataSource: { object literal, or holds a census hit, plus all of examples/schema-catalog 0 · 0 · 0 three batches: 59, 51 and 56 files passed; 2975, 748 and 896 tests passed
closure build of the packages the doc gates compile against (turbo, --concurrency=2) 0 35 successful, 35 total
pnpm check:doc-snippets 0 679 of 679 block(s) judged, 0 failed
pnpm check:doc-examples 0 every covered example compiles, or fails exactly as its ledger row declares
pnpm check:doc-fences · check:doc-types 0 · 0 OK · every documented component type is registered
pnpm check:control-bytes · check:new-line-citations 0 · 0 OK (scanned 9536 tracked text file(s); skipped 85 binary) · 0 new citation(s)
node scripts/check-changeset-presence.mjs · pnpm changeset:check 0 · 0 declares .changeset/11070-strict-face-read-keys.md · No changeset declares a major bump
pnpm check:changeset-claims · check:pending-changeset-literals 0 · 0 report-only · No test source names a pending changeset
eslint on the two edited test files 0 0 errors, 0 warnings

NOT MEASURED locally, left to CI: the repository-wide lint, the Spec Main Shape Gate, and the test shards outside the files named above.

Ablation

BINDING was put back to the record form through objectstack's scripts/ablation-replace.mjs. The anchor hit once and the blob moved from 11d08d26d to c8a32682b. Predicted: the 7 BOUND_NODES pins go red. Measured: Tests 7 failed | 23 passed (30), and the 7 failures are those pins. Restored: the blob equals HEAD's (11d08d26d) and git diff HEAD is empty.

State

The PR stays a draft. needs:contract-review is back on it for the director's review of the new head; the seat re-enqueues only after that record.


Generated by Claude Code

…(objectui#11070)

`StrictAnyComponentSchema` refused keys a registered renderer reads, so the
strict `objectui validate` would tell an author to delete a key that works.
Declare, on the TypeScript face and the zod mirror, the ones whose read,
spelling and value shape are settled:

- `form.showSubmit` (the form renderer's submit-button switch, default true);
- `form.fields[]`: `multiple`, `rows`, `accept`, `dimensions`, `min`, `max`,
  `minLength`, `maxLength` (the spec's `FieldSchema` members, by reference)
  and `pattern` (a string), the field metadata a hand-authored form writes on
  the entry the renderer hands each field widget as its metadata carrier;
- `dataSource` on `object-grid`, `list-view`, `object-form` and
  `object-kanban`: the spec's `ElementDataSourceSchema`, by reference, read
  off the node through `ElementDataSourceGate`.

The object-view `table` slot withholds `dataSource` as a record source the
view owns (the objectui#10976 rule); the `form` slot carries it, as it
carries `bind` and `data`. Ledger rows the declarations move are updated.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
…-census entry (objectui#11070)

Declaring `dataSource` on the `list-view` mirror turns
`@object-ui/app-shell`'s ListViewSchema relay census (objectui#7559) red: a
new member owes a rung or a declared absence there, and that file is outside
this card's claimed surface. Withdraw the list-view declaration and pin the
key as still refused; the entry the census needs is reported to the seat.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
…eys (objectui#11070)

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
… not as a schema key (objectui#11070)

The "Using ObjectQL for Queries" snippet put the adapter into
`ObjectGridSchema.dataSource`. That key is the per-element BINDING, and
`SchemaRenderer` strips it from the props it spreads (objectstack#5576), so
an adapter written there never reached the grid. Now that objectui#11070
declares the binding's type, `check:doc-snippets` refused the snippet
(TS2741: property `object` is missing). The snippet now leaves the key out
and says where the adapter goes.

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

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 73 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/10976-table-slot-relay.md

  • names packages/types/src/__tests__/object-view-slot-key-lists.test.ts → packages/types/src/__tests__/object-view-slot-key-lists.test.ts — edited by this change

    The slot's key list and the withheld set are pinned against drift by packages/types/src/__tests__/object-view-slot-key-lists.test.ts, which also requires the validator to refuse every withheld key by name, so the two faces refuse the same keys.

.changeset/11068-grid-declared-keys.md

  • names schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was wrong. ObjectGridSchema declared eight keys the grid never read. An author who wrote description, emptyState, name, placeholder, rowSpecActions or bulkSpecActions on an object-grid got no type error, no validator refusal and no effect. The reference example in schema-reference.md taught description and showFilters as if they worked. It now authors only keys the grid reads.

.changeset/3917-retire-action-condition-branch.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • ActionCondition is removed from @object-ui/types (and from the barrel export). - ActionSchema.condition is retyped to the predicate the runtime actually honours: boolean | string | { dialect?: string; source: string } — the same three arms ActionRunner's own ActionDef.condition carries, and the same vocabulary visible and disabled use. - ActionConditionSchema is removed from @object-ui/types/zod (and from the zod barrel); the condition key now validates against that predicate union. - The two teaching sites (content/docs/core/enhanced-actions.mdx Conditional Execution, content/docs/api/schema-reference.md ActionSchema table) are rewritten to the live vocabulary: condition is a gate; a branch is expressed as separate actions with mutually exclusive conditions.

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

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

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

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

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

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743); the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair — but at that time the ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction, not that nothing was there. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger requires every registered pair's mirrored-but-undeclared key set to equal that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.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/5928-classname-style-props-rename.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Where the non-pair is recorded now. zod-mirror-parity.test.ts keys its existing EXCLUSIONS entry — the mechanism that accounts for every exported const with no TypeScript declaration to mirror, each with its stated reason — to ClassNameStylePropsSchema. Named for its own two keys, the const leaves no like-named declaration for a name-derived pairing to reach for.

.changeset/6051-gantt-flat-config-declared-keys.md

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743) — the same retirement objectui#5903's entry carries, for the same clause and the same reason; the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair, at a time when that ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger reconciles every registered pair's mirrored-but-undeclared key set against that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/6150-undeclared-but-consumed-keys.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ AMENDED, and the amendment ships in this same release. The TreeViewSchema slice (604476d97) gave the key a zod arm after all — a NAMED REFUSAL (handlerKeyRefusal(key, 'runtime-slot', label)), never a shape — because "no mirror entry" is not neutral under BaseSchema.passthrough(): it meant an authored { "type": "tree-view", "onNodeClick": { "action": "toast" } } parsed GREEN, survived the parse, and reached a call site that expects a function. ⇒ the three clauses this bullet used to carry are no longer true of the code shipping beside it. The key is now a MEMBER of TreeViewSchema.shape and an authored value is refused BY NAME at path onNodeClick; it has LEFT zod-mirror-parity.test.ts's RuntimeOnlyDeclared for that file's KnownDrift; and it is no longer "the first pair to sit there without also sitting in UnmirroredDeclared" — draining it emptied that difference, so RuntimeOnlyDeclared is now a SUBSET of UnmirroredDeclared and the union of the two equals UnmirroredDeclared itself. ⛔ objectui#6152's ruling is untouched by any of this: what the key still does not have, and never will, is a z.function() shape — no serialized document could satisfy one.

.changeset/6170-retire-timeline-dead-keys.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Also in this change: the in-repo example packages/types/examples/data-display-examples.json (its timeline node authored all three) is migrated to items / variant; the two content/docs/api/schema-reference.md snippets that authored events: [] now author items: []; and the plugin-timeline docs callout says retired rather than deprecated.

.changeset/6175-column-state-persistence.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Nothing is retired. Both spellings remain declared on DataTableSchema; onColumnReorder stays declared and stays unwired, exactly as the RuntimeOnlyDeclared ledger in zod-mirror-parity.test.ts records it. Which of the two survives is a declared-surface ruling that stays open and is deliberately not settled here.

.changeset/6269-objectview-slot-key-lists.md

  • names packages/types/src/__tests__/object-view-slot-key-lists.test.ts → packages/types/src/__tests__/object-view-slot-key-lists.test.ts — edited by this change

    Each Omit is now a Partial<PickANGLE-BRACKETS(…)> over an explicit key list — at this change 59 keys for table, 64 for form, i.e. every declared member minus the identity keys the view itself fixes. Pick with literal keys never computes keyof T, so it cannot collapse the same way. The key lists are pinned against silent drift by packages/types/src/__tests__/object-view-slot-key-lists.test.ts, which recomputes each source schema's declared members through the TypeScript checker and, at this change, requires set equality; a member added to ObjectGridSchema and not to the list turns it red.

.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/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/6639-objectgrid-title-mirrored.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The gain is the typed refusal: the mirror's .passthrough() base was already admitting any title unexamined, and it now enforces the declared string. zod-mirror-parity.test.ts's UnmirroredDeclared ledger records the key as worked off — the ledger's first shrink by repair (97 + 1 mirrored + 23 reclassified is what the seeded "121" now means).

.changeset/6896-retire-chart-inline-data.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ One correction to the record the ruling rests on. The ruling states zero authorship of a populated series[].data outside tests across packages/ / apps/ / examples/. The re-measurement finds one such site inside those roots — packages/types/examples/data-display-examples.json (2 series) — plus four outside them, in documentation: content/docs/api/schema-reference.md (3) and content/docs/core/report-schema.mdx (1).

.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-kanban-column-cards.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Breaking, deliberately. KanbanColumn declared its card list as items in complex.ts and in the zod mirror complex.zod.ts. Every board reads cards. Measured on origin/main 78a3cc238: KanbanImpl.tsx reads .cards on 12 lines, KanbanEnhanced.tsx on 8, and bucketCardsIntoColumns twice more as col.cards || []; .items had zero read sites in either board (a same-shaped .title control on the same two files returns 8 and 3, so those zeros are readings and not a mis-shaped probe). Both catalog entries, the plugin docs and content/docs/api/schema-reference.md all author cards.

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

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

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

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

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was measured, on this branch's base. TreeViewSchema declared two spellings for its one inline-nodes slot — nodes (read second) and data (read third: boundData || schema.nodes || schema.data || [] at renderers/data-display/tree-view.tsx:105), both declared by objectui#6150. data had been REQUIRED until 777e5c6f4 (PR fix(types): tree-view mirror stops requiring the limb it reads third (group 2 of objectui#6939) #7533) made it optional, so this retirement starts from a declared-and-optional member on both faces. The in-repo corpus at the retirement: seven tree-view nodes under examples/schema-catalog and packages/types/examples plus one content/docs fence — six on nodes, two on data (packages/types/examples/data-display-examples.json and content/docs/api/schema-reference.md), both rewritten; no package source authored either spelling.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.changeset/7323-adapter-factory-return.md

  • names content/docs/utilities/data-objectstack.mdx → content/docs/utilities/data-objectstack.mdx — edited by this change

    The README's note saying the page could not yet teach the factory's shape is removed, and the four sections built on the adapter-only members (Metadata Caching, Connection State Monitoring, Batch Operation Progress, Troubleshooting → Cache Issues) now continue from Basic Setup's createObjectStackAdapter(…) call instead of declaring the class by hand. The docs-site page content/docs/utilities/data-objectstack.mdx is corrected the same way: its prose, its factory signature fragment and its "hold the class type to reach these" section described the old narrow return, and its Mutations and Troubleshooting examples told the reader to construct the class by hand to reach members the factory now declares. src/adapterFactoryReturn.types.test.ts pins the card's TS2339 reproduction inverted, with two controls: the adapter-only members stay absent from DataSource (fires on option B), and the widened return stays assignable to DataSource (swappability kept).

.changeset/7344-handler-string-any-mirrors.md

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

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

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

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

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

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

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

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

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

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

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

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

.changeset/7632-shared-record-source-config.md

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

    That ladder is published contract on both faces — packages/types/src/objectql.ts and its zod mirror both ship .describe() strings naming getDataConfig's order (77cb489b4, maintainer ruling 2026-09-02), pinned by objectql-record-source-refinement-6939.test.ts — and it was hand-copied into five plugin components with no gate holding them together. A change to the ruled order had five edit sites and nothing that noticed a missed one; that is the AGENTS.md #0.1 drift class.

.changeset/7654-floating-chatbot-trigger-icon-tombstone.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Every other tombstone in this package pairs ?: never with a retirementTombstone() refusal on the Zod twin. There is no twin here to carry one: FloatingChatbotConfig has no Zod mirror at all, and floatingConfig sits in the UnmirroredDeclared ledger (zod-mirror-parity.test.ts, complex.zod.ts#ChatbotSchema). BaseSchema is .passthrough(), so the whole floatingConfig object rides through unvalidated — before this change and after it. Minting a mirror to host a refusal would be the declared-but-UNMIRRORED axis (objectui#6152), a different defect: a key can be mirrored and inert, or unmirrored and live, and fixing one says nothing about the other. This change does not widen into it.

.changeset/7664-kanban-arm-plugin-dialect.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Migration. Author boards in the plugin dialect — objectName + groupBy for an object-bound board, or columns[].cards[] with badges for a static one. Replace DeclarativeKanbanSchema imports with KanbanSchema (from @object-ui/types, or the Zod KanbanSchema from @object-ui/types/zod; @object-ui/plugin-kanban re-exports the same KanbanSchema type). Delete draggable (drag-and-drop is always on) and column color (style a lane through className). content/docs/api/schema-reference.md's kanban section now documents this dialect.

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

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

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

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

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

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

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

.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/7780-object-kanban-record-source.md

.changeset/7804-objectql-handler-key-arms.md

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

    The four plain objectql.ts node faces declare the nine handler keys their registered renderers read (the objectql.ts slice): ObjectFormSchema.onCancel / .onError / .onOpenChange / .onStepChange / .onSuccess, ObjectGallerySchema.onCardClick / .onRowClick, ObjectGridSchema.onNavigate and ObjectViewSchema.onNavigate.

.changeset/7804-tree-view-handler-slot.md

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

    'runtime-slot' and not 'retired', measured at this key's own channel. 'retired' publishes "no renderer reads this key, so nothing could ever run it" — true of the two siblings already tombstoned on this arm (onSelectChange, onExpandChange) and flatly false here, since the read is live and INVOKED. ⚠️ No in-repo host builds a tree-view node carrying the key: the channel is wired end to end and only the supplier is absent, which is the same shape as ObjectFormSchema.onStepChange in this card's objectql.ts slice and is not evidence of a dead read. The TypeScript declaration is unchanged and still callable, so a programmatic host supplies it exactly as before.

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The pair moves from zod-mirror-parity.test.ts's RuntimeOnlyDeclared to its KnownDrift, which empties the former of the one entry the latter did not also hold — so the two unmirrored ledgers are now in a containment relation, and the cross-ledger figure that recorded their difference states the containment instead.

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

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

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

.changeset/7963-alert-dialog-footer-keys-retired.md

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

    Nothing else moves. These spellings are overloaded across the tree and every other owner is a live key on a different declaration — FormSchema.cancelLabel, objectql.ts's confirmLabel, plugin-designer's ConfirmDialog React props, plugin-grid's def.confirmLabel, and plugin-form's ModalForm / DrawerForm, which build a local cancelLabel from schema.cancelText. None is an AlertDialogSchema; none is touched, and a pin asserts it. No fixture, catalog schema, example app or doc fence authored any of the three on an alert-dialog node, so no shipped document is stranded.

.changeset/7997-detail-view-related-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Documentation. packages/plugin-detail/README.md and content/docs/api/schema-reference.md stop teaching the retired array and gain a migration block each.

.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/8268-testid-emitted-as-data-testid.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    The other direction — retiring the promise — was considered and declined. It is what c1fe272ad did for BaseSchema.hidden, but that key had a working behaviour to describe and zero named consumers, and the ruling's decline turned on exactly that. This promise already has carriers outside the type declaration: content/docs/api/schema-reference.md states it as a table row and authors testId in that page's own base-schema example, @object-ui/cli's OBJECTUI_STRUCTURAL_KEYS identifies a file as an ObjectUI schema node by this key, at this change ObjectGridSlotKey / ObjectFormSlotKey pin it, SchemaBuilder.testId() writes it, and ADR-0054 C4 — shipped — reads "the renderer emits data-testid … derived from metadata".

.changeset/8317-strip-imported-defaults.md

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

    Decision batch Redesign examples based on new JSON project specification #69 (objectui#7735) ruled a principle: a validator validates; it does not write values into an author's document. PR fix(types,components): the zod mirrors stop authoring defaults #8299 delivered it for the 41 .default() call sites written in this package's own mirrors. Measured afterwards, 57 ZodDefault nodes were still reachable from the published @object-ui/types/zod barrel, every one inside a subschema imported by reference from @objectstack/spec — so safeValidateSchema went on substituting on those keys, with 41 stripped and 57 not and no way to tell which was which from the document. Batch [WIP] Fix action run issue in CI/CD pipeline #90 ruled that the principle holds for every key the validator answers, and those 57 are now stripped where the spec enters this package (.removeDefault(), the established local pattern, applied through zod/imported-defaults.ts).

.changeset/8338-retire-toast-action.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The parity ledgers drain with it, every figure re-derived by zod-mirror-parity.test.ts's own AST and mirror instruments rather than stepped by hand: KnownDrift 42 entries / 64 keys → 41 / 63 (the entry's whole content, so the entry went too — the ledger's first loss by RETIRING a key rather than by moving either face toward the other), and WiderThanDeclared 23 / 36 / 47 arms, split 6 / 30 / 0 / 11 → 22 / 35 / 45, split 6 / 29 / 0 / 10. The pair itself stays registered, so EXPECTED_MIRROR_PAIRS does not move.

.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/8572-chatbot-body-retired.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Why this key and not another. It was the ONE place in this vocabulary where body did not mean "what goes inside this component": zod-mirror-parity.test.ts carried the pair under KnownDrift as "two different meanings of one key", and the same collision was the whole reason chatbot was the single arm of the component union whose output was not assignable to SchemaNode. Both ledger rows move with this change, and the two pins that recorded the old state are INVERTED rather than deleted (see below).

.changeset/8653-listview-title-retired-rowactiondefs-pinned.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    title — retired. ListView resolved its export filename through schema.label || (schema as any).title. @objectstack/spec/ui's ListViewSchema refuses title by name (unrecognized_keys: ['title']) while ObjectGridPropsSchema accepts it; packages/types mirrors the platform contract rather than ruling over it, so declaring title on ListViewSchema would have made this repo accept what the platform save gate rejects. That asymmetry is also why objectui#6639 could take the declare branch for ObjectGridSchema.title one package over and this site could not. A parse-based census of apps/ examples/ content/ and packages/ found zero list-view nodes authoring title, so the retirement costs no author a filename. Over that same corpus the instrument reports three object-grid nodes carrying the key: two authored ones, both in content/docs/api/schema-reference.md, plus one that is not authored at all — packages/plugin-view/src/ObjectView.tsx composes title: schema.table?.title onto a grid node it builds, so it is a producer writing the key rather than an author declaring it. ObjectGrid's own title reads are untouched — they remain declared, ruled and read.

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

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

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

.changeset/8767-object-grid-refuses-string-sort.md

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

    Migration. Write the array: sort: [{ field: 'name', order: 'desc' }]. Both keys are required. SortConfig.order carries no ? in @object-ui/types (packages/types/src/objectql.ts) and no .optional() in its zod mirror, and the protocol's own reusable SortItemSchema requires order as well — measured: that schema refuses [{ field: 'name' }] with invalid_value at 0.order. Do not omit it: this block's array arm interpolates whatever is present, so an omitted order lowers to $orderby: 'name undefined' today. That is pre-existing behaviour on the arm this change does not touch, and it is filed as a successor card rather than widened into here.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • names content/docs/utilities/data-objectstack.mdx → content/docs/utilities/data-objectstack.mdx — edited by this change

    • packages/plugin-list/src/ListView.tsx generates the node as groupBy: laneField. objectDef loads asynchronously, so laneField is undefined on every load until it lands, and stays undefined whenever the object offers no stageField hint and none of status / stage / state / phase. The renderer serves that node; both published faces refused it. - content/docs/utilities/data-objectstack.mdx documents an object-kanban node that is exactly { type, dataSource }, with no groupBy. ⚠️ This one is weaker and is cited for what it is: that fragment is still refused after this change, at RECORD_SOURCE_REQUIRED, because dataSource is not a rung of the record-source ladder. It shows a lane-less board is a documented authoring; it is not a document this change admits.

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

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

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

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

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

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

.changeset/9092-inline-locale-declared-face.md

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

    • AppComponentSchema.label (app.ts) - ObjectGridSchema.label and .description (objectql.ts) - PageNodeSchema.aria.ariaLabel (layout.ts)

.changeset/9187-record-highlights-layout-two-values.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ The census behind this narrowing covers this repository only, and it found no in-repo authoring to migrate: every in-tree layout: 'grid' belongs to a different component (detail-view in content/docs/api/schema-reference.md and phase2-schemas.test.ts, ai-recommendations in packages/plugin-ai/README.md), and the one in-repo consumer of this interface that writes a layout (p1-spec-alignment.test.ts) writes 'horizontal'. So no document in this repository stops type-checking. A TypeScript consumer outside this repo that wrote grid is not observable from here and gets a compile error (TS2322) naming the key — which is why the FROM/TO is spelled out above.

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

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

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

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

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

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

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

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

.changeset/9491-walkabledef-rest-null.md

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

    This is the declaration, not a behaviour change. Nothing here changes what either walker does with the value; the accept set of every exported schema is untouched. objectui#9088 already repaired the one arm the inaccurate type misled — the tuple arm in zod/imported-defaults.ts, which normalised the absent case to undefined because the declared type said that was the absent case, and so rebuilt every rest-less tuple through a === comparison that could never match. This change corrects the type that licensed it, so the next arm written against it is told the truth and tsc agrees with the truth instead of with the mistake.

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

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

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

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

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

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ The declaration alone would not have been enough, and this is the reusable part. A TypeScript declaration does not run at parse time. The hand-written zod mirror is the only face in this repository that can refuse an authored number, so narrowing the declaration without the mirror would have shipped declared !== enforced on a published surface — and zod-mirror-parity.test.ts would have stayed GREEN through it, because that instrument asserts a mirror accepts everything its declaration declares and a mirror left WIDER passes. Both faces moved together for that reason.

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

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

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

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

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

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

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

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

.changeset/9550-object-tree-root-barrel.md

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

    ObjectQLComponentSchema declares the node types an ObjectQL block may be. Every one of its arms was a named export of this package's root barrel except ObjectTreeSchema, which was declared in objectql.ts, applied by the union, and re-exported by the ./zod barrel (objectui#7917) — while no TypeScript consumer could name it. There is no ./objectql subpath to reach around the barrel: the package's exports map is pinned by packages/types/src/__tests__/package-exports-manifest.test.ts, and the root barrel was the only route to this type.

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

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

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

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

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

.changeset/9628-kanban-column-collapsed-honoured.md

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

    The key was declared on both published faces of the object-kanban arm — the lane element of ObjectKanbanSchema (objectql.ts and its Zod mirror) and the runtime lane KanbanColumn (complex.ts and its mirror) — and read by KanbanEnhanced alone, a module no production source imports. An authored { "id": "todo", "title": "To Do", "collapsed": true } therefore parsed green on both faces and reached a board that did nothing with it: KanbanImpl's only collapse is the SWIMLANE row's, held in viewer state under objectui:kanban-collapsed:ANGLE-BRACKETS(swimlaneField) and never keyed to a lane's declared value. That is the ADR-0049 declared-but-unhonoured shape.

.changeset/calendar-view-schema-converge.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Runtime renderer behaviour is unchanged. @object-ui/plugin-calendar's README and content/docs/api/schema-reference.md are repaired to the converged surface in the same change, so no copy of the old contradiction survives.

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

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

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

  • names api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Authoring crud is now REFUSED BY NAME rather than passed or silently ignored. validateSchema returns an error with code: 'RETIRED_TYPE' on schema.type — at any depth, since it is what validateChildren recurses with — so assertValidSchema throws and isValidSchema answers false. The message names the migration: object-grid for the record table with its toolbar, filters, pagination and row/batch actions, object-form for the create/edit form, and detail for the record view. api/schema-reference.md is rewritten around those shapes.

.changeset/object-view-unmirrored-keys-7779.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    listViews stays unmirrored, on the ruling's own fallback clause. The declaration's value is the local NamedListView — 64 declared top-level members (⚠️ re-taken at objectui#8980, which added the seventeen the protocol declares on this surface to the 47 this entry first measured), of which the renderer reads 21 off a named view. data is one of the 21 now: it used to reach the renderer through an as any cast on the named-view config in packages/plugin-view/src/ObjectView.tsx and be declared nowhere, and the objectui#8980 ruling declared it by name — objectui#7928's open half, answered. The spec's ViewSchema.listViews is a record of the STRICT ObjectListViewSchema, which requires columns and refuses options, ObjectQL tuple filters and default — that is, it refused the named views this package's own README and content/docs/api/schema-reference.md taught when this entry was written ({ label: 'All Users' } fails at columns; filter: [["owner", "=", "..."]] fails at filter.0), and objectui#8255 has since rewritten them in the spec shape. Mirroring the spec value would have lost documented behaviour; mirroring the local value would enforce 43 unread members (64 declared, minus the 21 that are both declared and read) into the contract — the very thing ruling B refused for the six local keys. The key therefore stays in the parity ledger with that measurement, pinned, until the maintainer decides its value type. It is not papered over with z.any().

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Who is NOT affected: every correctly typed document, and every document that never wrote these keys — absent stays valid on all nine. No renderer changed. The parity ledger (zod-mirror-parity.test.ts) records the move: UnmirroredDeclared 14 entries / 96 keys to 14 / 87, the ObjectViewSchema entry re-derived into the SPEC-DERIVED half because the mirror now references the spec in code.

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

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What makes this site different from its three siblings is that the alias was not merely tolerated, it was published. content/docs/api/schema-reference.md §TableSchema shipped a copyable { "name": "id", "label": "#" } example and a property row reading "Column definitions with name, label, …", while packages/types declared the opposite pair. Docs and type disagreed about one type they both call TableColumn, each internally consistent. Retiring the alias without correcting the page would have turned a documented, working example into a silently broken one, so both halves land together: the page now authors accessorKey/header. The same row also advertised a render property that TableColumn has never declared — the renderer's hook is cell — and that claim is dropped rather than re-spelled.

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 0ffc423b1 (merge-base with origin/main): 23 file(s) changed outside .changeset/, read against 1788 pending declaration(s) that publish a body (2395 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3110.0 KB 3149.4 KB
Main entry chunk (gzip) 149.3 KB 350 KB
Entry file index-oah03TyU.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) 558.81KB 133.93KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.11KB 66.33KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.54KB 37.02KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 234.44KB 62.20KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 169.69KB 43.37KB
plugin-gantt (index.js) 171.88KB 42.61KB
plugin-grid (index.js) 228.99KB 62.89KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.92KB 28.65KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 31.93KB 9.33KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 90.43KB 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.78KB 2.09KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.17KB 2.73KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 22.61KB 7.40KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
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

… gantt, map and calendar (objectui#11070)

Round 2, on the seat's answers:

- `FormField.reference` — the spec's `FieldSchema` member by reference, the
  spelling the `lookup` and `user` widgets read beside the legacy
  `reference_to`, which stays refused by the strict face.
- `dataSource` on `list-view` (re-added from the first round), and on
  `object-gantt`, `object-map` and `object-calendar`: the spec's
  `ElementDataSourceSchema` by reference; each registration is gate-wrapped.
  The list-view member's absence from app-shell's relay census is declared
  there (`unread`: ListView has no read of `schema.dataSource`; the binding is
  resolved by `ListViewBlock` through `ElementDataSourceGate`, which
  `renderListView` bypasses).
- `object-chart` is withdrawn and pinned as still refused: the react-page
  wrapper writes the host adapter (or null) under `dataSource`, and
  objectui#10770 pins that node as valid on the tolerant face.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
…11070)

- fields-lookup: `reference_to` -> `reference` (both widgets read it).
- fields-password: `min_length` -> `minLength`.
- fields-auto-number: drop `format` — `FormField` declares no auto-number
  format key and nothing on the form path reads one (`AutoNumberField`
  renders the value only).
- guide/schema-playground: the flat `validation: { pattern, message }` is the
  dialect objectui#5186 removed; the object dialect's `pattern.value` must be
  a compiled RegExp, which JSON cannot carry, so the regex moves to the
  field-level `pattern` string.
- api/schema-reference: a page region's children are `components`.
- plugins/plugin-detail: `page:tabs` items under `properties`, the spelling
  the platform's producers write (no ruling on the flat position,
  objectui#10872).

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3110.0 KB 3149.4 KB
Main entry chunk (gzip) 149.3 KB 350 KB
Entry file index-BSHnYBAk.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) 558.84KB 133.94KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.11KB 66.33KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.54KB 37.02KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 234.38KB 62.21KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 169.69KB 43.37KB
plugin-gantt (index.js) 171.88KB 42.61KB
plugin-grid (index.js) 228.99KB 62.89KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.82KB 28.67KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 31.93KB 9.33KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 90.43KB 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.78KB 2.09KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.17KB 2.73KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 22.61KB 7.40KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
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

…aSource (objectui#11070)

An ablation showed the `IsAny` check could not see `ListViewSchema` lose its
member: the derived type answers the index signature's `unknown`, not `any`.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3110.0 KB 3149.4 KB
Main entry chunk (gzip) 149.3 KB 350 KB
Entry file index-BSHnYBAk.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) 558.84KB 133.94KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.11KB 66.33KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.54KB 37.02KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 234.38KB 62.21KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 169.69KB 43.37KB
plugin-gantt (index.js) 171.88KB 42.61KB
plugin-grid (index.js) 228.99KB 62.89KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.82KB 28.67KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 31.93KB 9.33KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 90.43KB 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.78KB 2.09KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.17KB 2.73KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 22.61KB 7.40KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
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

Director: contract review deferred — this head does not land · 2026-09-30T03:48Z

Director seat (objectstack#12708, session_01AsCNgFBs8HCjwhyHQsFbx3), on the maintainer's 「项目总监契约复审」. git merge-tree --write-tree of head 42feeeb25e against objectui main c2a8d23c67: CONFLICT in three files — packages/types/src/__tests__/zod-mirror-parity.test.ts, packages/types/src/objectql.ts, packages/types/src/zod/objectql.zod.ts (PR #11130, merged 2026-09-29 18:01Z, edited the same lines). A record names one head, and a record on a head that cannot land is spent the moment the base is merged, so the review runs on the next head. Owner: the dispatch seat merges main into the branch (no rebase on a shared branch), re-runs its gates, re-pushes; needs:contract-review stays on until then, and the director seat picks the PR up at its next check-in or on the seat's pointer.

…keys

Brings in objectui#11068's first key group (#11130): on ObjectGridSchema,
name / placeholder / rowSpecActions / bulkSpecActions are retired as
tombstones, and emptyState / description are honoured.

Conflicts resolved with both sides kept:
- objectql.ts: ObjectGridSchema keeps `dataSource` right after `type`, followed
  by main's `name` / `placeholder` tombstones. The table-slot docblock keeps
  main's unread / not-relayed split, and `dataSource` is added to the record
  sources the view owns.
- objectql.zod.ts: main's four retired-key strings, then the binding
  description string. In the table-slot withheld map, the `dataSource` refusal
  sits beside main's `TABLE_KEY_NOT_RELAYED` description refusal.
- zod-mirror-parity.test.ts: the header figures were recomputed from the merged
  ledger (the objectui#7279 pin derives them). SPEC-DERIVED is 4 / 35 (3 / 34 on
  main, plus FormFieldSchema's one key moved in by membership). LOCAL is 8 / 46.
  The total is 12 entries / 81 keys.

The auto-merged slot pin keeps main's notRelayed group and the 63 / 69 member
counts, which the merged interface still measures.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3114.7 KB 3149.4 KB
Main entry chunk (gzip) 149.5 KB 350 KB
Entry file index-CKJe7r3C.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) 559.68KB 134.21KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.84KB 66.56KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.73KB 37.05KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 234.78KB 62.36KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.30KB 44.19KB
plugin-gantt (index.js) 172.43KB 42.85KB
plugin-grid (index.js) 229.83KB 63.15KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.82KB 28.67KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 32.26KB 9.42KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 90.43KB 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.78KB 2.09KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.17KB 2.73KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 22.61KB 7.40KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
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: 8628df2fd9eee49da35c3771d0f1136586cead8b
Local-runs: none

Director seat's at-tier review (objectstack#12708, on the maintainer's 「项目总监契约复审」, 2026-09-30) — the review this PR was drafted for, after the base merge 8628df2f cleared the three-file conflict the director's deferral 5903670251 named. Inputs: card objectui#11070 (body; the two os-dev-reports 5892537390 / 5893735765 and the seat's ACCEPT 5893791646 with its answers, read as claims to test); PR #11115 (body, 22 files, +623/−40, the net diff against objectui main 957f695208 at merge base c2a8d23c67); objectstack's spec at the @objectstack/spec@17.4.0 and @objectstack/spec@17.5.0 tags (page.zod.ts ElementDataSourceSchema, field.zod.ts FieldSchema, component.zod.ts); the head's check-runs. Nothing built, run or re-run. merge-tree of the head against main: clean.

Check-runs on the head, read 2026-09-30T04:3xZ: 43 runs, 0 failure, 0 in progress. Base condition, stated once: main now carries the 17.5.0 bump (PR #11086, merged 04:00Z) and this head's merge base predates it, so the head's CI ran on 17.4.0. The one referenced shape that moved between the tags is named in ① and ③; the PR's own pins survive it, and the merge queue's run on the merged tree is the proof on 17.5.0.

① Derived judgments

  • form.showSubmit — RIGHT. FormSchema gains showSubmit?: boolean and the mirror z.boolean().optional(); the form renderer destructures showSubmit = true and draws the submit button under it (the dev's probe: the button appears only when the key is removed).
  • Ten form.fields[] members on FormField / FormFieldSchema — RIGHT, by reference where the spec declares them. TypeScript face: SpecField['multiple' | 'rows' | 'accept' | 'dimensions' | 'reference' | 'min' | 'max' | 'minLength' | 'maxLength'] and pattern?: string; zod face: stripImportedDefaults(SpecFieldSchema).shape.<key> for the nine, z.string().optional() for pattern. At the 17.5.0 tag FieldSchema declares all nine (multiple boolean with a default the strip removes; rows, minLength, maxLength, dimensions positive integers; min / max numbers; accept string array; reference string), and their declaration lines are unchanged from 17.4.0 except describe text and a .meta({ title }). pattern is rightly a string: the spec declares none, JSON has no RegExp, and it is the field-level spelling the existing validation.pattern refusal already points authors to. The read path is the one the PR states: a hand-authored form hands each widget the field entry itself (field: field.field || field at renderFieldComponent), and the built-in input / textarea branches spread it onto the native control.
  • dataSource on seven blocks — RIGHT, by reference. TypeScript face ElementDataSource (@objectstack/spec/ui); zod face stripImportedDefaults(SpecElementDataSourceSchema).optional() on object-grid, object-form, object-kanban, list-view, object-gantt, object-map, object-calendar. It is metadata, not the adapter: SchemaRenderer strips the key from the props it spreads, and each block's gate-wrapped registration reads the binding off the node (ElementDataSourceGate), as objectui#6678 already publishes. The one shape that moved with the bump: at 17.5.0 ElementDataSourceSchema.filter is the ViewFilterRule array ([{ field, operator, value }], migration element-data-source-and-object-block-filter-rule-array) where 17.4.0 took a FilterCondition object; object, view, sort, limit are unchanged. Because both faces reference the spec schema, the mirror follows 17.5.0 on main with no edit here; the changeset's { object, view?, filter?, sort?, limit? } stays true; the only filter literal this PR adds is a refusal pin ({ type: 'object-kanban', dataSource: { filter: { a: 1 } } }, "a binding that names no object"), refused on both tags; the value pins use { object, view, limit }.
  • object-view slots — RIGHT. table withholds dataSource by name on both faces (a record source the view owns, beside data / staticData / bind under the objectui#10976 rule); form carries it, as that slot withholds only the identity keys.
  • list-view's relay census gains one ABSENCES entry, dataSource, kind unread, with the measured reason (the binding is resolved by ListViewBlock through the gate; renderListView renders ListView directly with the adapter as its own argument). One line, inside the seat's round-2 widening. RIGHT.
  • object-chart withdrawn — RIGHT. The react-page wrapper writes the host adapter (or null) under the node's dataSource, and object-chart-react-tier-node-10770.test.ts pins that node as valid; declaring the binding there reddened it. Pinned as still refused; the producer is fixed first in the next round (seat's answer A). The same nodes on the seven declared blocks are rendered, never validated, and the gate ignores a non-binding value, so rendering does not change — stated in the changeset as a refusal on safeValidateSchema, which is the honest sentence.
  • Six documents corrected — RIGHT, each to the spec spelling the renderer reads: reference_to → reference (two lookup fixtures), min_length → minLength, format dropped on two auto-number fixtures (nothing on the form path reads an auto-number format), the playground's flat validation: { pattern, message } → the field-level pattern string (the object dialect objectui#5186 kept cannot carry a RegExp in JSON; the message has no field-level spelling), the page region's children → components, page:tabs items under properties (⛔ no ruling on the flat spelling; objectui#10872 stays open), and the guide's adapter moved out of ObjectGridSchema.dataSource (TS2741 under check:doc-snippets). The legacy spellings stay refused on the strict face.
  • Accept-set moves, stated as the changeset states them. Strict face widens for the declared keys; both faces now judge a declared key by its type — on FormFieldSchema (which strips undeclared keys) a wrong-typed value that was dropped silently is refused (accept: "application/pdf", rows: 0); on the passthrough nodes a wrong-typed showSubmit or dataSource that was kept unjudged is refused. M3 class (ii) 32 / 149 / 141 → 12 / 38 / 38 on the dev's port of feat(cli): objectui validate and objectui check judge through the strict authoring face (objectui#5250, slice A) #11069's classifier; the tolerant face refused the same 38 documents before and after. RIGHT.
  • Ledger rows moved, and only those: form-field-zod-coverage +10 keys; zod-mirror-parity SPEC_DERIVED_PAIRS gains FormFieldSchema and ObjectKanbanSchema (no ledger KEY set changed); imported-defaults-8317 IMPORTED gains FieldSchema; object-view-slot-key-lists and list-view-spec-parity classify dataSource. The parity tsc is in Type Check, green.

② Semver level

Clause-②: yes — as declared: declaring a read key widens the strict accept set of the published StrictAnyComponentSchema, and wrong-typed values now refuse on both faces. .changeset/11070-strict-face-read-keys.md: @object-ui/types minor, every declared key named, "what now refuses that did not" spelled out, the deliberately-undeclared spellings listed — this repository's rule (breaking ships as minor in the fixed group). One package named, the one that publishes; the other 21 files are tests, docs, fixtures and the app-shell census. RIGHT.

③ Boundary flags

  • Refs, not Closes — RIGHT. 12 of the card's 32 pairs remain (return_type, summary_type, the grid field's columns, the 9 dashboard pairs); the card stays open. The dashboard pairs are a contract-shape choice the seat carries to a decision on the card after this lands — not this PR's.
  • object-chart · dataSource (the seat's answer A, producer fixed first, next round): answered — RIGHT.
  • Docs pages still teaching reference_to / min_length in TypeScript fences (fields/lookup.mdx, fields/password.mdx): outside this PR's surface; carried on the card, not blocking. Not a review-face defect of this diff: those pages are unchanged by it.
  • The 17.5.0 filter shape: stated in ①. The seat says one sentence on the card that dataSource.filter on the declared blocks is the rule array on main; no head move.
  • Overlap with PR feat(types): the object-form zod mirror declares the members its TypeScript twin declared (objectui#6152, round 1) #11125 (objectql.zod.ts, the zod-mirror-parity.test.ts totals line): the second to land merges main and re-derives the line. Not a single-claim path.
  • Dev-report deviations (read sites cited by symbol rather than file:line, per AGENTS.md [WIP] Update documentation for project #11; the two round-1 claim widenings — the guide fence and the census line): accepted by the seat; answered.

Implemented-by: claude/issue-11070-strict-face-read-keys
Reviewed-by: session_01AsCNgFBs8HCjwhyHQsFbx3

VERDICT: PASS

State: needs:contract-review comes off PR #11115 in the same stroke (this PASS at this head); the PR stays a draft until its seat lands it through the queue; the card stays open for its remainder.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 05:33
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 30, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Dequeued from the merge queue on CI_FAILURE: this PR's own failure, on 17.5.0. From the domain:spec @ objectui seat, session session_012UwY3ahMixEFkfTUxMVkYm, 2026-09-30T05:51Z.

The merge group gh-readonly-queue/main/pr-11115-0ffc423b1… (head 7c3a0340, CI run 36674156292) failed 2 of 8 test shards. Every other check in the group passed. Both failures come from one cause: main resolves @objectstack/spec 17.5.0, whose ElementDataSourceSchema.filter takes the ViewFilterRule array, and this PR declares dataSource by reference to that schema. This head's own CI ran on 17.4.0, so neither failure showed there.

  • Shard 5/8, packages/types/src/__tests__/strict-face-read-keys-11070.test.ts: the BOUND_NODES value pins use const BINDING = { object: 'task', filter: { project: 'acme' } }, the record form. All seven blocks answer invalid_type at dataSource.filter, where the pin expects no issue. The spec's message: 「filter on this element data source takes the ViewFilterRule ARRAY form [{ field, operator, value }, ...]」.
  • Shard 1/8, packages/types/src/__tests__/object-kanban-record-source-7780.test.ts ("PR feat(types): declare ObjectKanbanSchema.groupBy and .limit, retire groupField on both faces (objectui#7322 item 1) #7774's two EXCLUDED readings"): its fragment { type: 'object-kanban', dataSource: { object: 'task', filter: { project: 'acme' } } } is the one taught in content/docs/utilities/data-objectstack.mdx. With dataSource declared, the record-form filter is refused first, and the pin's RECORD_SOURCE_REQUIRED code no longer appears among the issues (expected [ undefined ] to include 'RECORD_SOURCE_REQUIRED').

So the review's reading that "the PR's own pins survive" the 17.5.0 filter move (5904239785) does not hold in the queue. The fix is this PR's: merge main, move both fixtures to the rule-array form (and the docs fragment the second pin mirrors), and re-run the packages/types suites on 17.5.0. That head move owes a new contract-review record before re-enqueue.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as draft September 30, 2026 05:55
…keys

Brings in the @objectstack/spec 17.5.0 resolution (objectui#11073, #11086),
whose ElementDataSourceSchema.filter takes the ViewFilterRule array, so this
branch's pins can be measured on the tree the merge queue builds.
No conflicts; six files auto-merged.

Refs objectui#11070

Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
Co-authored-by: Claude <noreply@anthropic.com>
…array (objectui#11070)

`@objectstack/spec` 17.5.0 types `ElementDataSourceSchema.filter` as the
ViewFilterRule array (`[{ field, operator, value }]`, migration
`element-data-source-and-object-block-filter-rule-array`), and this branch
declares `dataSource` by reference to that schema. Three literals still wrote
the record form, which the merge queue's run on 17.5.0 refused:

- `strict-face-read-keys-11070.test.ts`: `BINDING`, used by the seven
  `BOUND_NODES` pins, moves to the rule array. The pins still measure only
  that the key is declared.
- `object-kanban-record-source-7780.test.ts` ("PR #7774's two EXCLUDED
  readings"): the fragment moves to the rule array, so the refusal it asserts
  is again the record-source rule's `RECORD_SOURCE_REQUIRED`, not the filter
  shape.
- `content/docs/utilities/data-objectstack.mdx`: the Kanban fence that pin
  mirrors moves to the same form, so the two do not diverge.

Refs objectui#11070

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3569.7 KB 3607.4 KB
Main entry chunk (gzip) 149.5 KB 350 KB
Entry file index-BrPvtL0w.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) 559.46KB 134.18KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.08KB 62.96KB
fields (index.js) 261.19KB 66.27KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.73KB 37.05KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 234.78KB 62.36KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.30KB 44.19KB
plugin-gantt (index.js) 172.43KB 42.85KB
plugin-grid (index.js) 229.83KB 63.15KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.82KB 28.67KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 32.26KB 9.42KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 90.43KB 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.78KB 2.09KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.17KB 2.73KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 22.61KB 7.40KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.82KB 7.15KB
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

Correction to the director's record 5904239785 (head 8628df2fd9): its claim that "the PR's own pins survive" the 17.5.0 ElementDataSourceSchema.filter move was wrong · 2026-09-30T06:57Z

Director seat (objectstack#12708, session_01AsCNgFBs8HCjwhyHQsFbx3). The merge queue (5905013609) proved it: strict-face-read-keys-11070.test.ts's BOUND_NODES value pins took their binding from a const BINDING = { object: 'task', filter: { project: 'acme' } } declared apart from the nodes, and object-kanban-record-source-7780.test.ts carried the same record-form fragment. The director's grep looked for filter on a line with dataSource and saw only the refusal pin. Two shards went red on the merged tree. The record's ① and ② stand on every other point; that one sentence is withdrawn, and the PASS it carried is spent with the head. The new head bdd950ec6d is reviewed below.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: bdd950ec6db9e8ad7cb5a46838f8b878b8181bd1
Local-runs: none

Director seat's at-tier review of the new head (objectstack#12708, session_01AsCNgFBs8HCjwhyHQsFbx3), after the merge queue dequeued 8628df2fd9 on this PR's own failure (5905013609) and the seat fixed it. Inputs: the record 5904239785 and its correction above; the two commits since the reviewed head — e2c19f95 (merge of objectui main 0ffc423b1, 17.5.0 installed) and bdd950ec (the fixture fix, 3 files, +9/−3); the head's check-runs; git grep over every file this PR changes at the head. merge-tree against main 0ffc423b13: clean. Check-runs on the head, read 2026-09-30T06:5xZ: 43 runs, 0 failure, 0 in progress — and this head's CI ran on 17.5.0, since the merge base is now the bump.

① Derived judgments

  • Everything in 5904239785's ① stands for the diff against main, which is unchanged in substance by the merge: the eleven declared keys, the seven dataSource bindings by reference, the two object-view slots, the census line, object-chart withdrawn, the six corrected documents, the ledger rows.
  • The delta commit bdd950ec — RIGHT, and complete. Three fixtures moved to the 17.5.0 orthography, the ViewFilterRule array: strict-face-read-keys-11070.test.ts BINDING (filter: [{ field: 'project', operator: 'equals', value: 'acme' }]), object-kanban-record-source-7780.test.ts's fragment, and the docs fragment that pin mirrors (content/docs/utilities/data-objectstack.mdx). Re-grepped at the head across every file the PR changes: the only remaining object-form filter beside a dataSource is the refusal pin { type: 'object-kanban', dataSource: { filter: { a: 1 } } } ("a binding that names no object"), which is refused on 17.5.0 for two reasons and passes as a refusal; the $filter: hits in three docs pages are OData query examples, not bindings. The two shards the queue reddened (5/8, 1/8) are green on this head.
  • The accept-set statement is now exact on main: on the seven declared blocks, a dataSource.filter written as a record is refused with the spec's own message (the ViewFilterRule array form), where the 17.4.0 head's CI could not show it. The changeset's { object, view?, filter?, sort?, limit? } line stays true; no sentence in it names the filter form.

② Semver level

Clause-②: yes — unchanged from 5904239785: @object-ui/types minor, the break spelled in the body; one package publishes.

③ Boundary flags

  • The director's own error, closed: a value pin declared apart from its node was missed by a one-line grep; the merge queue caught it. The lesson is on the seat posts already (a record covers the landing head, and the landing tree is the one to prove it on): here the landing tree is finally the head's own.
  • Everything else in 5904239785's ③ stands (Refs, object-chart next round, the legacy spellings in two docs pages, the overlap with PR feat(types): the object-form zod mirror declares the members its TypeScript twin declared (objectui#6152, round 1) #11125 — that PR now lands second and merges main).

Implemented-by: claude/issue-11070-strict-face-read-keys
Reviewed-by: session_01AsCNgFBs8HCjwhyHQsFbx3

VERDICT: PASS

State: needs:contract-review comes off PR #11115 in the same stroke; the seat re-enqueues on this head.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 06:59
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit b0a05dd Sep 30, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11070-strict-face-read-keys branch September 30, 2026 07:22
huangyiirene pushed a commit that referenced this pull request Sep 30, 2026
objectui#11070 (PR #11115) landed on main and moved the same
UnmirroredDeclared split and totals line this branch moves. Both conflict
hunks sit in packages/types/src/__tests__/zod-mirror-parity.test.ts:

- the SPEC-DERIVED split bullet: both histories kept, in landing order
  (objectui#11068, then objectui#11070, then objectui#6152 round 1);
- the totals line: both sentences kept, figures re-derived from the
  merged ledger and SPEC_DERIVED_PAIRS.

Merged ledger, measured: 12 entries / 62 keys, 4 / 16 spec-derived,
8 / 46 local. The file-header line and both ledger docstrings (62 keys)
and the LOCAL split (8 / 46, from main) merged cleanly and already agree.

The pending .changeset/10993-object-form-i18nlabel.md takes main's bytes
back; its correction becomes an appended, dated note in the next commit.

Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
Co-authored-by: Claude <noreply@anthropic.com>
github-merge-queue Bot pushed a commit that referenced this pull request Sep 30, 2026
…ion-list / repeater) validate by their spec ComponentPropsMap rows (objectui#10872, batch 4) (#11180)

Part of #10872
Clause-②: yes (widening: six namespaced component types move from
refused-at-type to accepted by their spec rows)

Batch 4 of objectui#10872. The six ADR-0080 public blocks held back
until `@objectstack/spec` carried a `ComponentPropsMap` row for each
(`action:button`, `action:icon`, `action:group`, `action:menu`,
`element:definition-list`, `element:repeater`) are armed **by
reference** to their 17.5.0 rows, the batch-1 method. The card stays
open for `record:line_items` (no spec row yet) and the flat-props /
envelope-key batch.

⚠️ **Draft with one known red, deliberately:**
`packages/types/src/__tests__/zod-mirror-parity.test.ts` census (`every
exported const in ../zod/ is either a registered pair or an excluded
one`) names exactly the six new exports. The claim puts that file off
limits (draft PRs objectui#11115 and objectui#11125 hold it) and says to
stop and report the shape, so the six rows are **not** in this diff.
They are in the os-dev report on the card. Measured: with those six rows
added, the census passes (37/37, in a scratch copy of the test), and
`git merge-file` of the rows against the heads of objectui#11115
(`8628df2fd9`) and objectui#11125 (`a5884b4030`) reports 0 conflicts.

## What changed

- `packages/types/src/zod/public-blocks.zod.ts`: six arms, `BaseSchema`
+ the `type` literal + `properties`, which is the block's
`ComponentPropsMap` row passed straight through `stripImportedDefaults`
(no member restated). All six join `PublicBlockComponentSchema`; the
barrel re-exports them.
- `action:button` / `action:icon` also declare the two `on*` keys their
renderers read off the node, because `check:handler-key-reads` requires
every such read to be an arm member:
- `onClick`: `handlerKeyRefusal(..., 'runtime-slot', ...)`. The renderer
calls it only when it is a function (a code-composed schema), and the
row does not declare it. This is the `ButtonSchema.onClick` precedent.
- flat `onSuccess`: `aliasKeyRefusal` naming `properties.onSuccess`,
where the row declares the post-success `{ navigate, openIn }` block.
This is the `record:alert` flat-`body` precedent (batch 3). The spec's
own `PageComponentSchema` refuses the flat key too, as mis-layered.
- Ratchet: `NAMESPACED_REFUSED_AT_TYPE` falls 397 to 391, and
`ARMED_PUBLIC_BLOCKS_10872_BATCH_4` names the six. The ratchet's
validator import and `refusedAtType` (objectui#11069's hunks) are
untouched.
- Page pin: `objectui validate` passes a page whose `action:button` is
the quick-start's "Add Actions" node, read from
`content/docs/guide/quick-start.md` (the node AGENTS.md #4 teaches). It
also passes a page of all six in the spec's `properties` spelling. The
control is an undeclared bag prop, which is refused and named.
- Arm-list consumer sweep, the edits it required:
- `imported-defaults-8317.test.ts` measures the six rows at the import
boundary. They are placed away from objectui#11115's insertion point,
and none carries a default or a `z.lazy`, so the lazy count stays 4.
- `public-block-arms-10872.test.ts` gets `VALID_BAG` rows for the six.
Its identity leg now compares by definition, because 17.5.0 publishes
these rows as lazy proxies whose methods run on the real schema, so
`.optional()` wraps the object behind the proxy.
- The handler-key census: `action:button` and `action:icon` leave the
objectui#9573 alias population, which is now `view:form`, `view:grid`,
`view:list`. Their four reads are judged on their own arms. Both the
gate docblock and the gate test are amended.
- Changeset `10872-held-public-block-arms.md` (`'@object-ui/types':
minor`). A dated note on the pending `10872-public-block-zod-arms.md`,
whose "Not armed in this release" bullet this falsifies. The zod README
lists the six.

## The spec round's registration notes, re-measured at `main`
`0ffc423b1`

The arm follows the row, and the row follows the read points. Items 1–3
and 5 are pinned at the validator in
`held-public-block-arms-10872.test.ts`; item 4 is a renderer reading.

1. `action:group` publishes `name`, which is read nowhere. Its `size`
enum carries `md`, which inline mode hands raw to the primitive. **Still
true.** The arm refuses both, with the row's prescription.
2. `element:definition-list` publishes `columns` as the strings `'1'` /
`'2'`, and the renderer compares the number `2`. **Still true.** The arm
refuses `'2'` and accepts `2`.
3. `element:repeater` advertises `fields[].label` (its TS interface and
its registration description), which is never rendered. **Still true.**
The arm refuses it.
4. `action:menu` spreads `...rest` after `disabled={loading}`.
**Reproduced** with a probe through the real `SchemaRenderer` and
registry: an in-flight action (an `autoTrigger` member whose handler
never settles) shows the spinner on both mount channels, but the trigger
is `disabled: true` only on a direct registry mount and `disabled:
false` through `SchemaRenderer`, whose forwarded `disabled: undefined`
wins. It is reported on the card as a class-(a) finding; it is not fixed
here.
5. `objectName`: the 17.5.0 rows declare it on `action:button` and
`action:icon`. On `action:group` / `action:menu` it rides each member
(`actions[]` members are open records) and is refused at container
level. Pinned.

**The registrations did not move in this PR.** Items 1–3 sit in
`apps/console/src/__tests__/registry-inputs-spec-parity.test.ts`'s
objectui#11111 ledger, which the maintainer's decision 3 = B routes to
objectui#11168 ("nothing else may own an entry"). objectui#11168's slice
1 (the `action:*` family, including `renderers/action/`) was claimed at
2026-09-30T05:39Z, before this card's claim. So the registration moves,
and the item-4 renderer fix, would duplicate in-flight work. They are
reported on the card instead. This PR does not touch
`registry-inputs-spec-parity.test.ts` or any renderer.

## Tests and gates (all after the final commit, `c1ea153ad`)

- `pnpm exec vitest run packages/types/ packages/cli/src/__tests__/
packages/components/src/renderers/action/
packages/components/src/renderers/basic/
apps/console/src/__tests__/registry-inputs-spec-parity.test.ts`: 351
files, **7678 passed, 1 failed**. The failure is the zod-mirror-parity
census above, and nothing else.
- Arm-list consumer sweep: 54 files, 2878 passed, 0 failed. It covered:
- app-shell `block-config-schema-parity-8216`, `block-config`,
`definition-list-item-keys-8279` and
`PageBlockInspector.retiredBlockProps`;
  - `examples/schema-catalog/test/`;
- console `public-contract`, `html-tier-manifest`,
`component-input-union-specimens` and `unfulfilled-chart-stubs-8760`;
- plugin-dashboard `metricCardRegisteredInputsStrictFace-11022` and
plugin-map `bareMapKeyRetired-10393`;
  - the scripts tests that read the zod directory.
- Every test that names `check-handler-key-read-sites`: 5 files, 132
passed.
- `type-check` for `@object-ui/types` (three programs;
`tsconfig.test.json` lists the three changed test files) and
`@object-ui/cli`, after `pnpm --filter '@object-ui/cli^...' build`: exit
0. `@object-ui/components` is not in the diff.
- eslint on the 8 changed code files: 0 errors, 0 warnings, 0 ignored
(`--format json`). `eslint.config.js` configures no type-aware parsing,
so this diff cannot move a verdict on an untouched file.
- These gates exit 0: `check-changeset-presence`, `check:control-bytes`,
`check:new-line-citations` (0 new), `check:spec-symbols`,
`check:handler-key-reads`, `check:changeset-claims` (report-only),
`check:pending-changeset-literals`, `check-changeset-no-major`.
- NOT MEASURED: `check:readme-exports`. Reason: it needs every package's
`dist` and reported "the population COLLAPSED" on this unbuilt tree. CI
runs it.
- Ablation, both legs through `ablation-replace.mjs`: the anchor hit
once, the write was verified on disk, and the restore was proven (blob
equals HEAD, `git diff HEAD` empty).
- Leg A drops the six from the union: 60 of 179 tests go red across the
three pin files.
- Leg B deletes `action:button`'s `onClick` / `onSuccess` members:
`check:handler-key-reads` exits 1 naming both reads, and 2 held-arm
tests go red.

## Overlap

`git merge-tree` of this head with objectui#11069, #11115 and #11125: my
files merge cleanly with all three. objectui#11069 conflicts in
`packages/cli/src/commands/check.ts`, a file this PR does not touch; the
same conflict appears against the base alone.

## Acceptance notes

- **The taught `action:button` node is flat, and the strict face refuses
it.** AGENTS.md #4, the quick-start, the layout guide and the other
guides write `label` / `actionType` / `target` on the node. The tolerant
face `objectui validate` runs today passes that node (which is what the
page pin reads). `StrictAnyComponentSchema` refuses exactly `actionType`
and `target`, as `PageComponentSchema` does, and this is pinned as a
reading. objectui#11069 moves `objectui validate` onto the strict face.
When it next merges `main`, this PR's taught-node page pin turns red
there. That is the flat-props question for `action:*`, which this card
holds, and it is raised on the card.
- **Content channels are not narrowed.** The six arms carry no
objectui#9256 `children` / `body` refusal: that measurement never
covered them. They keep `BaseSchema`'s channels, and the module docblock
and README say so.
- **Inference, not reproduced, not filed:** inline `action:group` also
spreads `...rest` onto its wrapping div. This is the item-4 shape on a
div.

---
_Generated by [Claude
Code](https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants