Skip to content

chore(deps): resolve @objectstack/* 17.6.0 in pnpm-lock.yaml and follow its mechanical contract moves; five owner-held reds reported by row (objectui#11438) - #11531

Merged
objectstack-fleet[bot] merged 36 commits into
mainfrom
claude/issue-11438-objectstack-17-6-0
Oct 3, 2026
Merged

objectstack-fleet[bot] merged 36 commits into
mainfrom
claude/issue-11438-objectstack-17-6-0

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Fixes #11438
Fixes #11227
Fixes #11094

What this PR is

pnpm-lock.yaml now resolves @objectstack/* 17.6.0, regenerated with pnpm only and never edited by hand. Every gate that the bump turned red is listed below by row. The mechanical ones are done on this branch. The five that were not mechanical are each resolved on this branch under objectui#11438 ruling A″ (record 5968177777, confirmed by the maintainer: 「确认 A″,17.6 先落地」): row 4 is fixed, and rows 1, 2, 3 and 5 are booked to their owner cards with an expiry. See "Not mechanical" below. The branch head 0507d6716 is green.

package before (main lock) after
@objectstack/spec · types · core · client · formula · lint · sdui-parser 17.5.0 17.6.0

Nothing else moved. The resolution census compares package and snapshot keys between origin/main's lock and this branch's lock in both directions: seven keys removed at 17.5.0 and seven added at 17.6.0, with no importer specifier line changed. The 17.6.0 packages ask for zod ^4.6.5, which the lock already resolves.

How the lock was regenerated. I used the 17.5.0 bump's route (objectui#11073). Every @objectstack/* specifier was raised to ^17.6.0 for one pnpm install. Every manifest was then restored byte for byte to HEAD, and a second pnpm install reconciled the importers back to their declared ranges. objectui#11509 (the jsdom 29.1 pin) landed on main while this was in flight. I merged main as a merge commit, not a rebase. git merged the lockfile without a conflict. Then pnpm install --frozen-lockfile exited 0 with engine-strict on, a plain pnpm install left the lockfile byte-identical, and the census against the new main lock shows only the seven @objectstack/* moves.

B3: lockfile-only, or must every floor move?

Lockfile-only, plus the floors the floor gates demand. On the bump alone they demanded none. objectui#11227's slice then made one floor rise: @object-ui/types raises its @objectstack/spec floor from ^17.5.0 to ^17.6.0 (6b8a0ed96, .changeset/11227-types-spec-floor-17-6.md), because its published types and zod mirror now read EmptyState / EmptyStateSchema from @objectstack/spec/ui, which 17.5.0 does not export. No other package.json range moves.

  • check:spec-floors (scripts/check-spec-range-floors.mjs): its header says "A package's declared @objectstack/spec FLOOR must carry every symbol that package's own published artifact references". It judges symbol presence only. Over a full build it printed: "✅ Every consumer-facing @objectstack/spec floor carries the symbols its package's artifact references". With --cross-check it also printed "Dual-package cross-check: 54 entry point(s) — the import and require halves export the same names". Both exited 0.
  • check:installed-pin-claims judges prose about the installed version, never a declared range. Its findings were 38 prose sites, handled below.
  • No other rule here asks for floors to track the newest release. objectui#5793's ruling is "floors track reality", which the floor gate enforces. Every declared range already admits 17.6.0. On the bump alone, no package imported a 17.6.0-only export from published code; the one 17.6.0-only import (@objectstack/spec/migrations) is in a test file. @object-ui/types is now the exception above, and its floor rises with it.

Disposition by row

Done here (mechanical)

gate / test what 17.6.0 moved done here
check:spec-symbols @objectstack/spec/ui now exports EmptyState, the authoring type of a list view's empty-state config ALLOW entry for @object-ui/components:EmptyState, which is a React component alias. That is the same disposition objectui#11073 gave the four Object*Props collisions.
check:installed-pin-claims 38 sites named 17.5.0 Each fact was re-measured on 17.6.0 with a 17.5.0 tarball as the control, then restamped. The retired-key spelling moved (see next row) and was reworded. Seven sites in four files that name a past release were added to the ledger as historical. Gate: OK.
retired-key pins (retired-key-type.ts and five pins) the pinned spec's tombstone type is now the branded [REMOVED] mark, as on main reworded: "the branded mark at the pinned 17.6.0 and on objectstack main, bare undefined through 17.5.0"
writeWarningToast.test.ts tripwire DroppedFieldsEventSchema.reason lists computed Did what the tripwire asked: the | 'computed' widening is gone, the spent tripwire is deleted, and _ReasonIsTheEnum pins the exact four-member union
DatasetWidget.unrenderedMeasures-8894 the root no longer exports MIGRATIONS_BY_MAJOR (migrations-entry-split) static import from @objectstack/spec/migrations, as its docblock asked
registry parity: "page:header declares no top-level input the spec does not accept" PageHeaderProps.breadcrumb is a tombstone (objectstack#20758) The page:header registration drops its breadcrumb input, which the renderer has not read since objectui#11166; the entry's own comment said it would leave with the retirement. The slotted-pages guide example drops breadcrumb: true, and the page-header doc now says the key is refused.
registry parity: dangling exemptions and ledger caps action:button and action:icon no longer declare endpoint (objectstack b3917d90) The two stale objectui#11111 bookings are struck. The cap goes from 3 to 1 and the owner total from 3 to 1; undoable is still owed to objectui#11168.
loadLanguage.test.tsx the served translations gain a picklists group (objectstack addbbf02) @object-ui/i18n recognises the group
MetadataFieldsPage.refusalIssues-11302 the constructor field-name refusal is raised at its key (objectstack#20997) the reading moves to custom @ fields.constructor, which the pin said is the only change needed
MetadataService.retiredObjectEnabled / .specKeyObjectPayload ObjectSchema gains imageField (43 to 44 keys; lost set empty) corpus-guard count re-pointed, the same way the 17.3.0 adoption was
vite-objectstack-spec-dist.test.ts the exports map gains ./migrations (20 to 21; no browser arm; nothing removed) counts and prose re-pinned
check-lockfile-integrity.test.ts its samples were keyed on the 17.5.0 snapshot keys samples rebuilt on the 17.6.0 keys, as its own tripwire asked
ci-cd-pipeline-doc.test.ts the live-e2e backend pin must equal the resolved spec OBJECTSTACK_VERSION=17.6.0 (@objectstack/cli@17.6.0 resolves to the 17.6.0 tag commit)
grouping-field-padded-refused-7347 object-grid.grouping is typed (it was unknown) the bag member now refuses a padded name on every face, so it moves from the uncovered table to the declaring table; the node-level flat refusal stays uncovered
nested-page-children-11223 the spec's walk descends page:card's properties.footer[] The footer becomes a row of (a) and block (e) retires itself as it instructed. The CLI doc no longer names the footer as unjudged. ⚠️ Block (e) also asks that the closure be recorded on objectui#11223. That is a card write outside this dispatch's budget, so it is left to the seat.
check:eager-closure (Bundle Analysis) the spec root sheds its migration chain: −250,096 gzipped eager bytes The ceilings come down by exactly what was recovered (the second payback, objectstack#20646): aggregate 3,660,380 to 3,410,284, and vendor-objectstack 1,689,265 to 1,439,157. The baselines move to 2ba091c. Two console builds were taken in one lock hold, with main 2d576e46 as the control; the table is in the file. Left unchanged, the gauge was blind (exit 2, headroom 3.01x).

Not mechanical: resolved by row under ruling A″

Each of these rows was owned by a card that waited on this bump while the bump could not land green without it. Ruling A′ (record 5965062249) made this branch the trunk: each owner's slice lands here as commits, reviewed at tier by its lane seat, with merge commits only. Ruling A″ (record 5968177777) lands the trunk on 17.6.0 as soon as it is green. A row that would ship a user-visible regression is fixed here. Any other row is booked to its owner card in objectui#11111 decision 3 = B's shape: a bounded ledger with the owner and an expiry, ⛔ never a skip, a deletion or a weakened assertion. Booked owner cards stay open.

  1. object-grid declares description, emptyState, keyboardNavigation (objectstack f5c7b2c7, #20882). Fixed for two keys, booked for one.
    • objectui#11227's slice (6a86dd13a; contract record 5967010652 on objectui#11227): GRID_QUERY_INPUTS publishes description and emptyState, both renderers resolve emptyState's I18nLabel members, and the four object-grid-properties-bag-11276.test.ts rows read 17.6.0. This PR completes objectui#11227.
    • keyboardNavigation is booked to objectui#11068 (6c5011ded, bebd7ecdf) in registry-inputs-spec-parity.test.ts. Its unpublishedKeys cap rises by exactly that entry, and the GA-block split row admits that one id by name. Expires 2026-11-02, or when objectui#11068's build lands.
  2. record:line_items gets its ComponentPropsMap row (objectstack 24c554da, #21142 / #21244). Booked to objectui#11536 (00c13e7, c9121f9): ten unpublished keys and two unpinned members, with the caps moved by exactly those entries. Expires 2026-11-02, or when objectui#11536 lands.
  3. The dimensionless measure-arity check (checkDashboardWidgetDimensionlessMeasureArity; objectstack 11d28c17, #21053; objectui#8894 ruling D). Booked to objectui#11334 (0a518da48, c4775ed3a) on the 7715 census row and as a bounded seven-type ledger in both objectui#8894 measure-door tests, each with a cap row.
    • On 17.6.0 the spec itself refuses a dimensionless multi-measure chart widget at save, so an author gets a loud refusal from the server, not a silent wrong answer.
    • The mirror waits for objectui#11334's own Restart-when: objectstack main renamed the export (32d57690), and the Spec Main Shape Gate refuses a static import of the 17.6.0 name. Expires when objectui resolves an @objectstack/spec that carries 32d57690.
  4. $empty joins FILTER_OPERATORS, and is_empty / is_not_empty lower to it (objectstack f1e921ab, #20446 / #20570). Fixed by objectui#11094's slice (acd62a3a1 to 8a9cf1b5e, merged as 9187c5c40; contract record 5967059614 on objectui#11094). ValueDataSource executes is_empty / is_not_empty and $empty, and convertFiltersToAST lowers $empty. This was the one row that would have shipped a user-visible regression. This PR completes objectui#11094. objectui#10813 (the builders) lands on main afterwards as its own PR.
  5. ActionSchema gains outcomeMessages (objectstack d6d6e872, #21214). Booked to objectui#11344 (13f07dd0f) in actionKeys.pin.test.ts: the spec-inventory row requires missing to equal the one-entry ledger exactly, with stale still empty, and a new row asserts today's difference. Expires 2026-11-02, or when objectui#11344's slice lands.

⛔ None of these assertions was weakened, and no hold was touched.

Tests

CI on the branch head 0507d6716 (CI run 37123597204 on 0507d67167a1eaf29ca0635fdecc6afe708fc209): 45 check runs, 42 success and 3 skipped; Lint, Type Check, all eight Test shards, Test (dist pins), Spec Main Shape Gate, Build & E2E and Bundle Analysis among them. The Vercel status is success. mergeable_state is clean, and the branch is 0 commits behind main.

The readings that led here, all in families under "Not mechanical": 51 failures at da4c629f1, 40 at 9187c5c40 (row 4 fixed), and 1 at bebd7ecdf (row 5, before its booking).

Earlier, on the merged head 40d9b5a, the whole suite ran with the repository-root form pnpm exec vitest run under the verify lock:

Test Files  12 failed | 4318 passed | 7 skipped (4337)
     Tests  60 failed | 58922 passed | 356 skipped (59338)

All 60 failures are the five families under "Still red": 7 + 21 + 14 + 2 rows from families 1 to 3, 6 + 1 + 1 + 1 + 1 + 1 rows from family 4, and 1 row from family 5. No other test failed. turbo run type-check ran 81/81 tasks on the same head. On the lockfile-only commit 3796d59, the bump-caused reds also included every mechanical row in the table above. Each of those rows is green here.

The main that this branch merged had moved by one more commit before this PR opened (6903eaf, objectui#11523, docs only). The merge queue rebuilds on it.

Changeset

Ten changesets, no major:

  • .changeset/11438-objectstack-17-6-bump.md: @object-ui/components, @object-ui/i18n and @object-ui/console, all patch.
  • .changeset/11227-object-grid-17-6-keys.md: @object-ui/plugin-grid minor, @object-ui/types minor, @object-ui/plugin-list patch.
  • .changeset/11227-types-spec-floor-17-6.md: @object-ui/types patch, the @objectstack/spec floor to ^17.6.0. The bump's own changeset names this as the one declared range that moves.
  • .changeset/11094-value-source-empty-operator.md: @object-ui/core minor.
  • .changeset/11068-row1-booking-17-6.md, 11334-row3-booking-17-6.md and 11344-row5-booking-17-6.md: empty frontmatter; test-only bookings.
  • .changeset/11068-grid-declared-keys.md, 11276-object-grid-properties-bag.md and 11276-plugin-grid-properties-bag-docs.md: pending changesets corrected by objectui#11227's slice, which made a sentence in each false.

The readings below were taken on 40d9b5a, before the owner slices.

  • node scripts/check-changeset-presence.mjs: "✅ 33 source file(s) of 14 released package(s) changed, and this change declares 1 changeset(s): .changeset/11438-objectstack-17-6-bump.md." (exit 0)
  • check-changeset-no-major: exit 0.
  • check:changeset-claims exits 0. It is report-only, and it asks for a read of 59 pending changesets that name a file this branch edits. This branch's edits to those files are restamped comments, a test re-pin, or the breadcrumb input. None of them changes a fact those changesets state.

Gates

Every gate below ran locally on the merged head 40d9b5a. The packages and the console were rebuilt there before any gate that reads dist ran. Exit codes were captured before any pipe.

gate exit verdict
pnpm install --frozen-lockfile (engine-strict on, after the merge) 0 lockfile up to date
check:lockfile-integrity 0 VERDICT clean
check:lockfile-dedupe 0 VERDICT deduped
check:spec-floors (+ --cross-check on the pre-merge build) 0 / 0 every floor carries its symbols
check:installed-pin-claims 0 OK
check:spec-symbols 0 green
check:component-surface-parity 0 report-only. 214 disagreements and 9 divergences, identical on a main control build.
check:action-forward-parity · check:designer-field-key-parity 0 · 0 green
check:phantom-deps · check:unused-deps 0 · 0 green
check:doc-snippets · check:doc-examples · check:doc-types · check:prompt-keys · check:skill-examples 0 each green
check:pre-install-import-graph · check:control-bytes · check:new-line-citations 0 each green; 0 new citations
check:eager-closure · check:eager-locale-catalogues 0 · 0 headroom 0.26x and 0.20x
turbo run type-check --concurrency=2 0 81/81 tasks
turbo run build --filter=!@object-ui/site 0 43/43 tasks

Size and route

2,595 changed lines (+2,090 / −505) across 83 files, lockfile included, which is under the 5,000-line human-merge line. node scripts/check-governed-merges.mjs --pr objectstack-ai/objectui#11531 (objectstack) on the final file list: 0 of 83 paths hit the governed register, NOT GOVERNED. Clause ②: yes. objectui#11227's and objectui#11094's slices declare it in their claims, and each carries an at-tier contract record on its own card (5967010652, 5967059614). This PR lands on a contract record at its final head.

(The bump alone, before the owner slices, was 726 changed lines across 46 files against the merge base 8366acc, Clause ②: no.)

Acceptance notes (observations, not filed)

  • packages/types/src/objectql.ts, the ObjectCalendarSchema.data docblock: the sentence "object-map and object-gantt have no ComponentPropsMap row at all" was already false at 17.5.0. Both rows exist at 17.5.0 and at 17.6.0. I restamped only the measured line beside it.
  • retired-key-type.ts: the bare-undefined arm now describes no installed spec, so it can be dropped. That tightens a helper every retirement pin reads, so I kept it here.
  • @object-ui/i18n now namespaces a picklists group under app. Nothing in objectui reads app.picklists yet; that is the picklist feature's work (objectui#10202, held), not this bump's.
  • BASELINE.squashMerge in scripts/check-eager-closure-budget.mjs stays null and is owed a back-fill once this lands, the same as after objectui#11101.

Deviation

The container runs Node 22.22.0. Before objectui#11509 reached this branch, the root jsdom ^30.0.1 required ^22.22.2, and .npmrc's engine-strict=true refused every install. Until the merge, local installs ran with --config.engine-strict=false. That flag turns an engine refusal into a warning and does not change resolution: pnpm passes engineStrict only to the installability check, not to the resolver. After the merge, every install and gate above runs with engine-strict on.

The session that ran this is session_01HRYqpqGcWpJuJkDmbRF75w, dispatched by objectstack's domain:devx seat 2.


Generated by Claude Code

claude added 15 commits October 2, 2026 22:23
…i#11438)

Regenerated with pnpm 10.31.0 only, by the raise-and-restore route the
17.5.0 bump used: every @objectstack/* specifier raised to ^17.6.0 for one
`pnpm install`, every manifest restored byte-for-byte to HEAD, then a second
`pnpm install` reconciles the importers to their declared ranges.

Resolution census against the base lock: the seven @objectstack/* packages
(spec, types, core, client, formula, lint, sdui-parser) move 17.5.0 -> 17.6.0
and nothing else moves. No importer specifier changes. The registry's new
`deprecated` field on twelve @yuku-analyzer/binding-* 0.8.7 entries is
written into the lock by the same tooling.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…, a component under a name @objectstack/spec 17.6.0 now exports (objectui#11438)

@objectstack/spec 17.6.0 exports `EmptyState` from `@objectstack/spec/ui`:
the authoring type of a list view's empty-state config (title, message,
icon). @object-ui/components publishes `EmptyState` as an alias of the
`DataEmptyState` React component. A component is not a config shape, so
neither import nor derivation fits; the alias is a published name, so its
retirement or rename belongs to its own card. Same disposition objectui#11073
gave the four `Object*Props` collisions 17.5.0 surfaced.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…ing now that @objectstack/spec 17.6.0 carries the arm (objectui#11438)

objectui#11206 widened `STRIPPED_LINE`'s key type by `| 'computed'` so it
compiled against both a three-arm pin and objectstack `main`, and left a
tripwire in `writeWarningToast.test.ts` for the bump that carries the arm.
17.6.0's `DroppedFieldsEventSchema.reason` lists `computed`, so this does what
the tripwire says: the key type is the spec union again, the `computed` case
is spelled as the literal, the spent tripwire is deleted, and
spec-symbol-batch6's `_ReasonIsTheEnum` pins the exact four-member union.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…spec/migrations, where 17.6.0 moved it (objectui#11438)

17.6.0 carries the spec's migrations-entry-split: `MIGRATIONS_BY_MAJOR` is
exported from `@objectstack/spec/migrations` and no longer from the root. The
test read the root dynamically so it compiled against both the old pin and
objectstack `main`, with no fallback, and its docblock asked the bump that
moves the pin past the split to replace that with a static import from the
subpath. This does that.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…jectstack/spec 17.6.0 refuses by name (objectui#11438)

17.6.0 carries objectstack#20758: `PageHeaderProps.breadcrumb` is a tombstone
refused by name. objectui's renderer has not read it since objectui#11166,
and its `inputs` entry said it stayed only while the spec accepted the key and
would leave with the retirement. It leaves now, so the registry no longer
publishes an input the contract refuses
(`registry-inputs-spec-parity.test.ts`, "page:header declares no top-level
input the spec does not accept").

The slotted-pages guide example drops `breadcrumb: true`, which the contract
now refuses (its pin parses the example against the spec row), and the
page-header doc and the renderer comment say the key is refused rather than
"accepted until retired".

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…7.6.0 made stale (objectui#11438)

objectui#11111 decision 3 = B booked `action:button.endpoint` and
`action:icon.endpoint` as spec keys held unpublished, owed to objectui#11168.
17.6.0 refuses `endpoint` on both blocks (objectstack b3917d90, the rename to
`target`), so neither entry names a key the spec declares, and the
dangling-exemption check reds on them. Both are struck and the ledger cap
falls from 3 to 1 (`undoable` stays, still owed to objectui#11168).

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
… group, which @objectstack/spec 17.6.0 adds (objectui#11438)

17.6.0's `GetTranslationsResponseSchema.translations` carries a `picklists`
group (objectstack addbbf02, the `picklist` metadata kind). The recogniser's
group list is written out, and the console's `loadLanguage.test.tsx` walks the
spec's list so a group the spec adds turns it red instead of a bundle carrying
only that group being returned untransformed and read by nothing. Added; the
transform already copies an unlisted group through onto `app`.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…t its key, as @objectstack/spec 17.6.0 raises it (objectui#11438)

Through 17.5.0 the spec raised the reserved-name refusal on the `fields` map
(`custom @ fields`). objectstack#20997 names the key, and 17.6.0 carries it
(`custom @ fields.constructor`). The pin said only this reading moves when
that lands; it moves, in the instrument row and in the banner row, which now
names `fields.constructor`.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…@objectstack/spec 17.6.0 leaves true, and ledger the four that name a past release (objectui#11438)

`check:installed-pin-claims` reads every present-tense claim about the
installed `@objectstack/*` version against the resolved artifact. 38 sites
named 17.5.0. Each was decided, never find-and-replaced:

- RESTAMPED after re-measuring the fact the sentence states against the
  installed 17.6.0 (each probe was also run against a 17.5.0 tarball as the
  control, and answered the same on both): `FieldSchema`'s `dependsOn`, `rows`
  and option `description` readings; `object-calendar.data` and `.calendar`;
  `record:details.columns`; `record:highlights` `fields[]` and `layout`;
  `SelectOptionSchema` labels; the `@objectstack/lint` field-rule verdict text;
  `referenceTo` and its four alias spellings; `CalendarConfigSchema`'s required
  key, options and refusal hints; `record:alert.visible`; `object-kanban`'s
  fifteen keys; the screen node's `waitForInput`; `object-calendar`'s ten flat
  members; `ObjectListViewSchema`'s members; the `view.list.navigation.view`
  tombstone in the gantt README pin; and the sites whose own tests measure the
  fact and pass on 17.6.0.
- REWORDED where the fact moved: the retired-key type is the branded
  `[REMOVED]` mark at the pinned 17.6.0 (bare `undefined` through 17.5.0), on
  `retired-key-type.ts` and the five pins that cite its spellings.
- LEDGERED as `historical` (four files, seven sites): lines whose version says
  WHEN something changed or names a release's record set, where `pinned` is an
  unrelated verb or the sentence sits under a dated update heading.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…ack/spec 17.6.0 moves, and pair the live-e2e backend with it (objectui#11438)

Each pin names what moved, measured against a 17.5.0 control:

- `ObjectSchema`'s accepted keys are 44, not 43: 17.6.0 adopts `imageField`
  (gained set exactly that one, lost set empty). Both corpus-guard counts are
  re-pointed as the 17.3.0 adoption was.
- The spec's exports map has 21 entries, not 20: `./migrations` is added (no
  `browser` arm), nothing removed. Every count and its prose follow.
- `check-lockfile-integrity`'s two lockfile samples are rebuilt on the 17.6.0
  snapshot keys their own tripwire named.
- The objectui#11111 owner total for objectui#11168 follows the cap to 1 (the
  two `endpoint` entries struck earlier on this branch).
- `e2e/live/ci/backend.env` pins `OBJECTSTACK_VERSION=17.6.0`, the version the
  lockfile resolves, as the pin requires (`@objectstack/cli@17.6.0` resolves
  to the 17.6.0 tag commit).
- The page-header doc drops the version literal it gained on this branch;
  `doc-version-claims` holds docs to pointers, not version numbers.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…k/spec 17.6.0, so it joins the covered arms (objectui#11438)

17.6.0 types `ComponentPropsMap['object-grid'].grouping` as the grouping
config instead of `z.unknown()`. The authored arm's `properties` is that row
by reference, so a padded grouping field name is now refused at its entry on
all four faces. The census's recorded reason for leaving the bag member
uncovered stopped holding; it moves to the declaring table and is pinned like
every other arm. The node-level `grouping` stays uncovered: it is the flat
spelling's by-name refusal.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…stack/spec 17.6.0's walk descends it (objectui#11438)

objectui#11223's block (e) held `page:card`'s `properties.footer` as the one
slot the spec's exported walk did not descend, and said to retire itself when
that changed. 17.6.0's walk descends `properties.footer[]`, objectui's faces
now judge a footer child, and block (d) asked for the position to be added to
(a). It is: the footer is a row of (a) on both faces, (e) is deleted, and the
CLI doc no longer names the footer as an unjudged slot.

Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
… @objectstack/spec 17.6.0's root entry shed (objectui#11438)

The second payback of objectui#11073's ruled raise, objectstack#20646, reaches
objectui with the 17.6.0 bump: the spec root no longer exports its migration
chain. Measured with two console builds in one lock hold (`CI=true pnpm exec
vite build` after the packages build): `main` at `2d576e46` (17.5.0) weighs
3,636,289 gzipped eager bytes, this branch at `2ba091c` weighs 3,386,193;
`vendor-objectstack` alone is -250,108, the other 329 chunks +12.

Left alone, the ceiling would sit 3.01x the regression above the payload and
the gate's own sensitivity check exits 2 (a blind gauge). So, as objectui#11101
did for the first payback: `MAX_EAGER_CLOSURE_GZIP_BYTES` 3,660,380 ->
3,410,284 and `vendor-objectstack` 1,689,265 -> 1,439,157, each lowered by
exactly what it recovered; BASELINE and PER_CHUNK_BASELINE move to the
`2ba091c` reading; headroom 0.26x and 0.20x, the bands `main` already had.
The test's rendered literal is re-taken (3306.8). The changeset says what the
console gains.

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

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 92 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/10872-container-children-channel.md

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

    Also in this change, with no behaviour change: objectql.zod.ts's two public-block arms (object-metric, object-master-detail-form) build their properties member with the same propsBag helper as the other public-block arms, instead of a byte copy of it. The member's description text is unchanged.

.changeset/11522-kanban-rule-dialect-retired.md

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

    • KanbanConditionalFormattingRule is now an interface that extends SpecConditionalFormattingRule, with field, operator, value, backgroundColor, borderColor and textColor declared ?: never. It used to be the union of SpecConditionalFormattingRule and KanbanNativeConditionalFormattingRule. - KanbanNativeConditionalFormattingRule is removed. Importing it is a compile error (TS2305). - KanbanConditionalFormattingRuleSchema, the rule schema ObjectKanbanSchema applies, is a module export of this package's src/zod/objectql.zod.ts. It is not on the @object-ui/types/zod barrel or on any other entry of the package's exports map, so it is not an import a consumer can name. It is the spec ListViewSchema.conditionalFormatting rule taken by reference and extended, not a union. It keeps the spec rule's strictness and its style map. Its condition is the same schema the list view's and the grid's { condition, style } arm reads, so a string condition is still not canonicalized into an envelope and '' is still accepted. The six retired keys are retirement tombstones.

.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/4730-retire-dead-locale-key-batch.md

  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    • Superseded twin vocabularies. cellRender.* and rowAction.* duplicated a grid.* vocabulary that won. RowActionMenu.tsx is fully i18n-wired and reads grid.openMenu / grid.edit / grid.delete; ObjectGrid.tsx reads grid.empty / grid.yes / grid.no / grid.systemFields. The twins had no reader on either side. - Labels that outlived their control. calendar.agenda labelled a view mode b55a34647 retired from CalendarViewMode (now 'month' | 'week' | 'day'). home.quickActions.createApp*, layout.systemNav.createApp, actionDialog.defaultActionTitle / .ok and grid.bulk.selectPlaceholder sit in namespaces whose consumers are live and wired but demonstrably read other siblings. - Surfaces that left the product. map.* is the strongest form: @object-ui/plugin-map declares no @object-ui/i18n dependency and contains no t() call at all, so it cannot consume a locale string. home.stats.* and recordDetail.viewersTooltip name surfaces nothing renders.

.changeset/5793-spec-range-floors.md

  • names pnpm-lock.yaml → pnpm-lock.yaml — edited by this change

    Nothing a consumer installs today changes: normal resolution already picks the newest 17.x, and pnpm-lock.yaml still resolves 17.2.0 on this edge after the bump. The change is to the declared floor only, which is why it is scored patch rather than minor — the same reasoning objectui#5753 used for the other direction on this dependency.

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

.changeset/6050-gantt-navigation-basepath.md

  • names src/readme-navigation-example.test.ts → packages/plugin-gantt/src/readme-navigation-example.test.ts — edited by this change

    No gate in this repo could have caught the original defect, and that is why the fix ships with a measurement rather than a re-reading: check-doc-snippet-types compiles ts/tsx fences and check-doc-component-types reads type literals, and both are structurally blind to a metadata key in a README — the former's own header records schema-key validity as "a different question … left unruled on purpose". src/readme-navigation-example.test.ts closes that hole for this example by EXTRACTING the fence from the README on every run and parsing it against NavigationConfigSchema, with a control asserting the same parse still rejects an undeclared key by name, so the green cannot come from a schema that accepts everything.

.changeset/6152-object-form-unmirrored-members.md

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

    ObjectFormSchema in @object-ui/types (objectql.ts) declared a set of members that its zod mirror in @object-ui/types/zod had never heard of. Every one of them is read by the object-form renderer (ObjectForm in @object-ui/plugin-form). The two published faces answered differently:

.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/6213-core-adapters-readme-owns-its-directory.md

  • names packages/core/src/adapters/README.md → packages/core/src/adapters/README.md — edited by this change

    packages/core/src/adapters/README.md now documents the adapters that are actually in that directory, and the ObjectStack material it carried moved to the package that owns the behaviour (objectui#6213). Both files ship to consumers — @object-ui/core publishes its src/, and a README rides every tarball — so this was published documentation describing the wrong package.

.changeset/6286-explain-batch-cap-from-spec.md

  • names scripts/check-spec-symbol-derivation.mjs → scripts/check-spec-symbol-derivation.mjs — edited by this change

    No value changes and no behaviour changes. The spec exports 200, which is what the local copy said, verified by resolving the installed package and reading the export — both statically (dist/security/index.d.mts) and at runtime through the same specifier the source now uses. What changes is reference identity: if the server relaxes or tightens the cap and the spec follows, the client follows too, instead of paginating at the old boundary with no signal anywhere. The cap's whole point is that an over-cap request is refused with 400 VALIDATION_FAILED rather than truncated, so a client that silently disagrees with it is exactly the drift scripts/check-spec-symbol-derivation.mjs argues about — and could not catch here: when this change landed, both of its scanners skipped non-exported declarations, and this const was module-local (objectui#5899). objectui#6291 has since removed that filter from both scanners.

.changeset/6361-spec-floor-17-2-0.md

  • names pnpm-lock.yaml → pnpm-lock.yaml — edited by this change

    Nothing a consumer installs today changes: normal resolution already picks the newest 17.x, and pnpm-lock.yaml still resolves 17.2.0 on both edges after the bump — only the recorded specifier: moves. No source and no behaviour changes, which is why this is scored patch, on the reasoning 111741454 used for the same remediation on @object-ui/plugin-detail.

.changeset/6519-retired-field-key-strip.md

  • names plugin-designer/src/MetadataFieldsPage.tsx → packages/plugin-designer/src/MetadataFieldsPage.tsx — edited by this change

    Unifying the three retired-key lists on this seam is deliberately not part of this change: it spans plugin-designer/src/MetadataFieldsPage.tsx, which objectui#6489 owns in flight.

.changeset/6597-retire-fieldmeta-referenceto.md

  • names plugin-grid/src/ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    No authoring story survived the search either. ObjectGrid's own relational-meta pass-through (applyRelationalMeta, plugin-grid/src/ObjectGrid.tsx) copies reference_to / reference / display_field / etc. from the SCHEMA field def only, at all three of its call sites — never from an authored column override. No doc, example, or fixture in this repo shows a table column pinning a lookup's target away from what its schema field already says. Under the maintainer's standing startup-stage rule (2026-08-27: deprecated/alias spellings retire immediately, no transition windows), no measured demand selects withdraw.

.changeset/6650-listcolumn-wrap-implemented.md

  • names packages/plugin-grid/README.md → packages/plugin-grid/README.md — edited by this change

    @objectstack/spec declares ListColumn.wrap and describes it to authors as "Allow text wrapping", and packages/plugin-grid/README.md shows it in its authored-column example. No renderer anywhere implemented it. Long cell text stayed clipped to one line, with no error, no warning and no feedback of any kind — a promise made at authoring time and silently broken at render time.

.changeset/6771-retire-body-child-list-dialect.md

  • names renderers/layout/containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    Non-rendering readers keep their arm on the same rule, and none of them renders anything: while a renderer still reaches stored body content, a reader that must see the SAME content keeps its arm, or the renderer draws what the reader cannot find. Those are the two tab-subtree walkers in renderers/layout/containers.tsx, app-shell's pageSchemaIntrospect (CONTAINER_KEYS) and PageBlockInspector (STRUCTURAL_PROP_KEYS, the inspector half of a stored properties.body), and the CLI's OBJECTUI_STRUCTURAL_KEYS — a file-IDENTIFICATION marker, where keeping body is what lets an old file still be recognised as an ObjectUI node and therefore refused, instead of silently not judged.

.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/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/7070-no-invented-gantt-date-fields.md

  • names plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

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

.changeset/7122-objectstack-family-17-3-0.md

  • names pnpm-lock.yaml → pnpm-lock.yaml — edited by this change

    @objectstack/client, core, formula and lint each pin @objectstack/spec EXACTLY, so resolving the spec alone to 17.3.0 left the console bundling TWO copies of it. Moving the family with it in pnpm-lock.yaml collapses the duplicate; every declared range already admitted 17.3.0, so no manifest moved.

.changeset/7173-ai-pending-actions-inbox-i18n.md

  • names scripts/check-eager-closure-budget.mjs → scripts/check-eager-closure-budget.mjs — edited by this change

    The ten pack blocks are locale DATA, and locale data lands in the console's eager framework chunk, so scripts/check-eager-closure-budget.mjs raises that chunk's ceiling from 512,000 to 524,000 gzipped bytes and re-pins its baseline onto a fresh measurement (502,405 to 514,863). Attributed by three console builds: the merge parent reads 510,192, this branch with the ten aiApprovals blocks cut reads 510,192 again, and this branch reads 514,863 — so the whole 4,671-byte delta is the pack data and nothing else. Headroom is kept at the line's own convention (9,137 bytes, 0.10x the regression the gate must catch) rather than widened; most of the overage was pre-existing drift, with the merge parent already at 510,192 of the 512,000 allowed.

.changeset/7182-declared-action-ids-one-rule.md

  • names containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    New on @object-ui/types, beside actionRendersAt: the pure resolveDeclaredActionIds(elements, registeredActions), with the DeclaredActionsResolution / DeclaredActionsRefusal result types (the shape classifier stays module-internal: called with no registry, the function already returns the registry-independent verdict a renderer needs before its lookup). Both renderers call it; the whole-array switch in record-quick-actions.tsx and the per-element normalisation in containers.tsx are gone. The rule is closed: a string is an id, a non-null non-array object is an inline definition, and any other element (null, a number, a nested array) is refused at its index too. An all-id array resolves by name in authored order, first registration winning on a duplicate name; ids that name nothing are reported back with their index for the caller to warn about once its lookup has settled.

.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/7298-discussion-explicit-composition.md

  • names content/docs/guide/slotted-pages.md → content/docs/guide/slotted-pages.md — edited by this change

    Docs: content/docs/guide/slotted-pages.md.

.changeset/7313-object-calendar-record-source.md

  • names plugin-calendar/src/ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    ObjectCalendar resolves its records through the shared ladder (resolveRecordSourceConfig in @object-ui/core, called from plugin-calendar/src/ObjectCalendar.tsx): data first, then staticData, then objectName. The published TypeScript interface REQUIRED objectName and declared neither data nor staticData; the published Zod mirror did the same. So an object-calendar node authored on staticData — the route the plugin page documents twice — rendered correctly and was refused by safeValidateSchema, and could not be annotated with its own type (TS2741: Property 'objectName' is missing).

.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/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/7499-gantt-non-axis-floors-omitted.md

  • names plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • plugin-list/src/ListView.tsx — the object-gantt render branch. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.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/7635-spec-173-comment-repairs.md

  • names scripts/check-installed-spec-pin-claims.mjs → scripts/check-installed-spec-pin-claims.mjs — edited by this change

    Two of the five sites are now watched. They are written as single-line claims about the installed pin, which moves them out of scripts/check-installed-spec-pin-claims.mjs's ledger of known-stale debt and into the population that gate re-derives at every bump; their ledger entries are deleted in the same change, as that gate's both-direction ratchet requires. The remaining three sit on facts no instrument reads, and say so rather than reading as live.

.changeset/7658-toc-code-span-anchor-parity.md

  • names content/docs/utilities/cli.mdx → content/docs/utilities/cli.mdx — edited by this change

    Seven live headings in this repo's own docs were affected (content/docs/utilities/cli.mdx, content/docs/utilities/runner.mdx, packages/cli/README.md). Pinned against the real render pipeline rather than a second derivation of the slug rules: the new test renders each heading through MarkdownImpl and compares extractToc's id to the id attribute rehype-slug actually emitted.

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

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

    ⚠️ Dated note, 2026-10-03 — KanbanConditionalFormattingRuleSchema is no longer a union — objectui#11522. At this change KanbanConditionalFormattingRuleSchema was "the rule union the 'object-kanban' arm already applied": the native { field, operator, value } comparison or { condition, style }. Now it is one object, the spec list view's { condition, style } rule by reference, and the native rule and a top-level colour key (backgroundColor, borderColor, textColor) are refused by name; the 'kanban' arm it was shared with has itself retired in this release (objectui#8802). It keeps its name, and it is a module export of src/zod/objectql.zod.ts inside @object-ui/types, NOT an export of the @object-ui/types/zod barrel. Measured at objectui#11522's change: that barrel re-exports KanbanCardSchema, KanbanColumnSchema and ObjectKanbanSchema from the kanban family and not this schema, and no entry of the package's exports map carries it. So the bullet above that calls it "newly exported from @object-ui/types/zod" does not hold in this release either; whether it held at objectui#7664's own commit was not measured. The rest of this entry is kept as the reading of this change.

.changeset/7712-kanban-calendar-filter-input.md

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    ObjectKanban.tsx sends the authored key to the query as $filter: schema.filter and ObjectCalendar.tsx does the same, and @objectstack/spec's ComponentPropsMap declares filter on both blocks (measured: safeParse accepts it, and refuses an undeclared key by name on the same call). But none of the four registrations that publish those two renderers listed filter in inputs, and sdui-parser's validateTree reports unknown-prop for every key no inputs entry claims. So an author writing the one spelling that WORKS was told it was unknown — objectui#6678's shape, where a correct write draws the same diagnostic as a write that does nothing. That is worse than an inert key: it actively punishes the correct behaviour, and the honest response to it is to delete working metadata.

.changeset/7715-mirrors-carry-spec-object-checks.md

  • names packages/types/src/__tests__/spec-object-refinements-7715.test.ts → packages/types/src/__tests__/spec-object-refinements-7715.test.ts — edited by this change

    packages/types/src/__tests__/spec-object-refinements-7715.test.ts accounts for every object-level check each of the six spec objects carries, so a check the spec adds in a later release fails there by site name instead of being dropped.

.changeset/7762-object-grid-export-options-bare-array-refusal.md

  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    What was measured, on this branch's base. The mirror declared NO exportOptions member at all, and BaseSchema is .passthrough(), so ObjectGridSchema.safeParse({ type: 'object-grid', objectName: 'accounts', exportOptions: ['csv', 'xlsx'] }) returned success: true with the array back VERBATIM — as did { formats: ['csv', 'pdf'], compression: 'gzip' }. Nothing on the render path parses, and ObjectGrid.tsx reads schema.exportOptions?.formats and only that, so the authored array then lost SILENTLY to the ['csv', 'json'] default: the useEffect that warns about dropped formats reads .formats too and returns early when it is absent, while !!schema.exportOptions kept the export button on screen. An author declared ['csv', 'xlsx'] and got csv/json with no error, no warning and no console line. The two authoring faces disagreed in the direction opposite to objectui#6956's: the TypeScript interface already declared the object form only, so TS refused what zod admitted.

.changeset/7773-kanban-adapter-groupfield-write.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    Who is NOT affected — the boundary is node-local. Every VIEW-LEVEL groupField read is untouched and still live: it is a legacy alias of the spec's groupByField on the kanban view config, mapped by normalize-list-view.ts, and both adapters still resolve lanes through it (ObjectView.tsx's kanbanCfg.groupField ||, ListView.tsx's groupByField || groupField). Authoring options.kanban.groupField on a list-view or object-view keeps working exactly as documented in packages/plugin-list/README.md. groupField is dead only on the generated object-kanban NODE.

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

.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/8067-component-input-member-kind.md

  • names apps/console/src/__tests__/registry-inputs-spec-parity.test.ts → apps/console/src/__tests__/registry-inputs-spec-parity.test.ts — edited by this change

    A registration's type: 'array' said a value was a list and stopped there, so a member that drifted from @objectstack/spec was invisible to every layer that reads a declaration. page:header.actions is the measured cost: the contract declares z.array(z.string()) ("Action IDs"), the renderer read the members as ActionDef objects, and the repo-wide parity gate in apps/console/src/__tests__/registry-inputs-spec-parity.test.ts stayed green for the whole life of the drift because both sides carried the key and neither could say what was inside it. What settled it was a maintainer ruling, not a test — and even after the fix, "these are ids" survived only as English in the registration's description.

.changeset/8155-app-root-residue-swept.md

  • names containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    Swept as a class, not as two coordinates. Every other place in this tree that stated app was a bound expression-scope root is corrected in the same change — the diagnostic copy and its byte-pin, the ambient-scope docblocks in @object-ui/react (SchemaRenderer, useExpression), @object-ui/core (ActionRunner.ParamDef.visible, RowPredicateOptions.scope), @object-ui/components (form.tsx, containers.tsx), @object-ui/plugin-detail, @object-ui/plugin-form (docblock and README), @object-ui/app-shell and the console app, plus fourteen test fixtures that transcribed the old bag with an app key. The fixtures in @object-ui/app-shell now call buildExpressionScope instead of transcribing it, so that pair cannot drift again.

.changeset/8171-calendar-sort-input.md

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    objectui#7712's defect, one key over. ObjectCalendar.tsx lowers the authored key onto its own query as $orderby: convertSortToQueryParams(schema.sort), and @objectstack/spec's ComponentPropsMap['object-calendar'] declares sort (measured on 17.2.0: safeParse({ objectName, sort }) returns success: true, while the same strict schema on the same call refuses bogusProp by name — that control is what makes the acceptance a verdict). But neither of the two registrations that publish this renderer — plugin-calendar:object-calendar and view:calendar — listed sort in inputs, and sdui-parser's validateTree reports unknown-prop for every key no inputs entry claims. So an author writing the one spelling that WORKS was told it was unknown — objectui#6678's shape, where a correct write draws the same diagnostic as a write that does nothing.

.changeset/8174-kanban-calendar-filter-sort.md

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    filter had four declaration faces and only three of them named it: @objectstack/spec declares it (ComponentPropsMap['object-kanban'] and ['object-calendar']), both plugins' registration inputs publish it, and both renderers read it — ObjectKanban.tsx lowers schema.filter onto $filter, ObjectCalendar.tsx lowers schema.filter onto $filter and schema.sort onto $orderby through convertSortToQueryParams. This package's own published faces (the TypeScript interface and its zod mirror) named none of them, so an authored value reached the renderer only through BaseSchema's index signature and the mirror's .passthrough() — admitted, never examined. That is the same reasoning finding(types,plugin-kanban): ObjectKanbanSchema requires groupField (zero read sites) and declares neither groupBy nor limit — no working object-kanban node is assignable to any declared type #7322 used to move groupBy and limit into this same interface.

.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/8355-retire-calendar-date-aliases.md

  • names calendarUnionReads-8651.test.tsx → packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx — edited by this change

    Pinned by calendar-date-alias-refusal-8355.test.ts (@object-ui/types, all five surfaces, the per-surface consequence split, the compile-time face, and the structural guard that listViews stays out of the object's shape), ListView.calendarAliasRefused-8355.test.tsx (@object-ui/plugin-list) and ObjectView.calendarAliasRefused-8355.test.tsx (@object-ui/plugin-view) — both reading the node their producer really emits through a spy registration, which is the only census that can see a key arriving through a spread — and the inverted ledger rows in calendarUnionReads-8651.test.tsx (@object-ui/plugin-calendar).

.changeset/8466-calendar-color-allday-fields.md

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    ObjectCalendar.tsx's getCalendarConfig reads FIVE flat keys off the node, and packages/plugin-calendar/README.md teaches all five in one sentence — "point titleField / startDateField / endDateField / allDayField / colorField at your own fields when they differ." Only three of the five were declared. The other two reached the renderer through BaseSchema's [key: string]: any on the TypeScript face and its .passthrough() on the zod mirror: admitted, never examined. A misspelling therefore left the calendar silently colourless while every published gate passed.

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

.changeset/8568-retire-dollar-dialect-lowercase-aliases.md

  • names packages/data-objectstack/README.md → packages/data-objectstack/README.md — edited by this change

    packages/data-objectstack/README.md's operator tables follow the implementation, as does the reconciliation test that holds them to it.

.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/8841-tree-view-config-derive.md

  • names scripts/check-spec-symbol-derivation.mjs → scripts/check-spec-symbol-derivation.mjs — edited by this change

    What was wrong. @object-ui/types published TreeViewConfig as a hand-written interface — a copy of the protocol's ListView.tree block under a second name — and the copy declared a fifth key, titleField. @objectstack/spec@17.4.0 refuses that key there by name: TreeConfigSchema is a strictObject since spec objectstack#15469 closed the .passthrough() window 17.3.0 left open. So this package's published face accepted what the contract rejects, and an author who followed @object-ui/types was refused at publish with Unrecognized key(s) on this tree configuration: 'titleField'. The copy was invisible to scripts/check-spec-symbol-derivation.mjs, which matches spec symbols BY NAME — a hand copy renamed away from the spec's symbol has nothing for its rule 1 to match (objectui#4592's recorded blind spot).

.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/8976-icontains-lowers-in-converter.md

  • names packages/core/src/adapters/README.md → packages/core/src/adapters/README.md — edited by this change

    $icontains is a member of @objectstack/spec's FILTER_OPERATORS, ValueDataSource executes it, FilterConditionField emits it for its "contains (ignore case)" builder row, and packages/core/src/adapters/README.md prescribes it as the repair when $like / $ilike / $regex are refused. convertOperatorToAST had no row for it, so the ObjectStack lowering path answered a FilterOperatorError (code: 'INVALID_FILTER', httpStatus: 400) with the generic unknown-operator paragraph — the one spelling this repo tells an author to write was the one spelling it rejected. An admin who picked "contains (ignore case)" in the filter builder authored criteria that the in-memory matcher honoured and the ObjectStack data source refused.

.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 packages/plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — 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/9040-record-details-top-level-spec-parity.md

  • names record-details-top-level-9040.test.ts → packages/types/src/__tests__/record-details-top-level-9040.test.ts — edited by this change

    ⚠️ The retired layout on the same interface was NOT removed by this change. The contract refuses it by name (ADR-0087 D2 tombstone, removed in @objectstack/spec 17.0.0), and it stayed a published key tsc accepted and publish rejected — signposted at the declaration and pinned by record-details-top-level-9040.test.ts rather than removed, because a retirement carries its own obligations and its own FROM/TO changeset.

.changeset/9040-retire-record-details-layout.md

  • names packages/types/src/__tests__/record-details-top-level-9040.test.ts → packages/types/src/__tests__/record-details-top-level-9040.test.ts — edited by this change

    • packages/types/src/__tests__/p1-spec-alignment.test.ts wrote layout: 'stacked' on this interface and read it back. Both lines are gone, with the reason stated at the site and a live-key read-back put in their place so the leg is not quietly shrunk. Its RecordHighlightsComponentProps neighbour keeps its own layout — a different key on a different face. - packages/types/src/__tests__/record-details-top-level-9040.test.ts ledgered the divergence as OPEN. Those legs become the retirement's own: a keyof absence assertion (with a declared key read through the identical form as its control), a @ts-expect-error literal, and a new source-text leg. - packages/types/src/__tests__/record-highlights-layout-9187.test.ts read this declaration as TEXT, using its three-value layout as the lit control for a two-member assertion about the sibling. That control MOVED to RecordChatterComponentProps.position — a three-value union the contract genuinely declares — as that file's own instruction required. It was never to be deleted outright, and it is not.

.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/9174-interpolate-fastpath-trim.md

  • names packages/components/src/renderers/layout/containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    At this change page:header's title/subtitle (and the record-title titleFormat) all went through interpolate() in packages/components/src/renderers/layout/containers.tsx. When the template contained a {token} the function collapsed and trimmed whitespace before returning; when it contained no { at all it returned the raw string untouched. A whitespace-only authored title (e.g. ' ') has no token, so it came back unchanged — truthy — and PageHeaderRenderer's {explicitTitle && ANGLE-BRACKETS(h1)} gate drew a blank h1. Because literalTitleText (page.tsx), which decides whether PageRenderer delegates its own heading to the authored header, already trimmed and correctly read "no title", PageRenderer also drew its own implicit heading — two ANGLE-BRACKETS(h1) elements on one document, the broken outline objectui#3434 closed, arriving through a different door.

.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/9278-end-outcome-select.md

  • names FlowNodeInspector.declaredDefault.test.tsx → packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx — edited by this change

    The control is now a select whose options are exactly the spec's enum, declaring defaultValue: 'completed' so an unset key states on the trigger what the runtime applies to it, and the invented placeholder is gone. Both are derived from the installed spec, as FlowConfigField.defaultValue's doc comment requires of a declaration outside the escalation ledger, and both are reconciled against EndConfigSchema in FlowNodeInspector.declaredDefault.test.tsx — through zod's public toJSONSchema rather than a respelled literal, so the claim cannot quietly rot at the next spec bump. The zh-CN overlay gains the two option labels and the help line.

.changeset/9280-record-highlights-entry-icon-retired.md

  • names packages/types/src/record-components.ts → packages/types/src/record-components.ts — edited by this change

    • packages/types/src/record-components.ts — RecordHighlightsComponentProps.fields[]'s object arm: { name; label?; icon?; type?; readonly? } → { name; label?; type?; readonly? }. The key is removed, not tombstoned: the contract's arm is $strict, so the refusal an author needs already exists upstream and arrives named (invalid_union at the entry). A ?: never tombstone buys nothing here — it is the remedy for a non-strict mirror that would otherwise strip in silence, which is not this arm. - packages/plugin-detail/src/renderers/record-highlights.tsx — the entry normalizer stops copying icon: f?.icon into the normalized entry. That read was unreachable, not merely unused: no author could feed it past the $strict arm, and HeaderHighlight renders no .icon on the far side either, so the copy had no consumer in either direction. - packages/plugin-detail/src/index.tsx — the registry manifest's fields input description sketched the entry as {name,label?,icon?,type?,readonly?} → {name,label?,type?,readonly?}. The inputs ARE the published contract (gen-manifest.ts serializes them into sdui.manifest.json and sdui-intrinsics.d.ts), so leaving the sketch standing would have gone on teaching AI and human authors a key that gets the whole document refused at publish.
  • names packages/plugin-detail/src/index.tsx → packages/plugin-detail/src/index.tsx — edited by this change

    • packages/types/src/record-components.ts — RecordHighlightsComponentProps.fields[]'s object arm: { name; label?; icon?; type?; readonly? } → { name; label?; type?; readonly? }. The key is removed, not tombstoned: the contract's arm is $strict, so the refusal an author needs already exists upstream and arrives named (invalid_union at the entry). A ?: never tombstone buys nothing here — it is the remedy for a non-strict mirror that would otherwise strip in silence, which is not this arm. - packages/plugin-detail/src/renderers/record-highlights.tsx — the entry normalizer stops copying icon: f?.icon into the normalized entry. That read was unreachable, not merely unused: no author could feed it past the $strict arm, and HeaderHighlight renders no .icon on the far side either, so the copy had no consumer in either direction. - packages/plugin-detail/src/index.tsx — the registry manifest's fields input description sketched the entry as {name,label?,icon?,type?,readonly?} → {name,label?,type?,readonly?}. The inputs ARE the published contract (gen-manifest.ts serializes them into sdui.manifest.json and sdui-intrinsics.d.ts), so leaving the sketch standing would have gone on teaching AI and human authors a key that gets the whole document refused at publish.

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

.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/9722-bulk-executor-datasource-face.md

  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    • ObjectGrid.tsx → RecordDetailPanel: removing it type-checks GREEN. It was paying for nothing — both sides already declare the same DataSource | undefined from @object-ui/types. Removed outright. - ObjectGrid.tsx → BulkActionDialog: removing it reddens, and it was paying for TWO things at once — the optional-vs-required arm (the grid declares dataSource?: DataSource, the dialog demands one) AND the bulk-door contravariance. Only the first still needs erasing, so it is now a non-null assertion: today's runtime behaviour is preserved exactly, and any future drift of the face reddens at that site instead of passing silently.

.changeset/9853-grid-non-positive-page-size.md

  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    Refuse a non-positive pageSize at all three of ObjectGrid.tsx's read points, instead of giving two different answers for one authored value (objectui#9853).

.changeset/action-keys-warning-text-5642.md

  • names actionKeys.pin.test.ts → packages/core/src/actions/__tests__/actionKeys.pin.test.ts — edited by this change

    Both halves of the message's tail had outlived the change they described. It told the author the key was warned about rather than rejected because ActionDef "still carries [key: string]: any" — objectstack#4075 step 3 deleted that index signature, and actionKeys.pin.test.ts pins the deletion in the opposite direction ({ ActionDef: false, ActionContext: true }), while actionDef-closed-surface.test.ts pins that tsc now rejects exactly such a key at the construction site. And it prescribed promoting the key to an explicit field on ActionDef "(packages/core/src/actions/actionKeys.ts)" — that file holds the INVENTORY (ACTION_DEF_KEYS); the interface is in ActionRunner.ts. The wrong pointer had teeth: an author who followed it edited the inventory alone, which is precisely the half-change the pin test reddens on, since it re-derives the inventory from the interface's AST.

.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/console-form-container-specs-one-declaration-5596.md

  • names scripts/check-spec-symbol-derivation.mjs → scripts/check-spec-symbol-derivation.mjs — edited by this change

    Both types are therefore derived from the spec's own FormSection / FormView with named narrowings — the repo's sanctioned form for a spec-shaped local type (scripts/check-spec-symbol-derivation.mjs) — rather than restated. Every key the two layers agree on comes from the spec and cannot fall behind it; the four positions where this layer is deliberately narrower are each named in an Omit list and restated once next to its reason: fields keeps the converged 26-key leaf (deriving it would silently re-open [finding] A THIRD inline copy of the form-field authoring contract lives in apps/console FormPage.tsx — objectui#5040 converged only the app-shell two #5542), and label / description / visibleWhen / visibleOn keep the shapes this repo's renderers and evaluators actually consume rather than the spec's I18nLabel and ExpressionInput. apps/console's submitBehavior union — previously hand-written under the comment "Mirrors the spec FormView.submitBehavior union" — is now read back off the shared type, making the mirror structural. @object-ui/app-shell re-exports both names from its package root (type-only, erased at build — nothing is added to the bundle), because a type that cannot be imported is a type that gets retyped.

.changeset/host-dispatch-action-keys-5611.md

  • names actionKeys.pin.test.ts → packages/core/src/actions/__tests__/actionKeys.pin.test.ts — edited by this change

    The authored surface does not move. overrideNotice is still NOT declared on ActionDef and still NOT in ACTION_DEF_KEYS; writing it in an action literal remains a compile error, and the AST-derived pin over the interface is unchanged. Membership in KNOWN_ACTION_KEYS widens what the WARNING tolerates, never what an author may write — actionKeys.pin.test.ts now pins both halves, including the new list's exact contents so a second member cannot arrive quietly.

.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/list-user-actions-collision-5398.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    The harvest now reads the object block only. Both userActions read sites in ListView.tsx carry a comment naming the collision, and __tests__/ListView.userActionsCollision.test.tsx pins each clause of it: the two shapes, a producer that manufactures the view one, the harvest's blindness to it, and the projection that must keep the object's operand with a toolbar block — or an empty block — present on the view.

.changeset/listview-comment-pair-4559.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    Two comment corrections in ListView.tsx (objectui#4559, objectui#4966). No runtime behaviour changes and the emitted bundle is byte-identical; the published .d.ts does change, which is why this is a patch rather than an empty frontmatter.

  • names scripts/check-spec-symbol-derivation.mjs → scripts/check-spec-symbol-derivation.mjs — edited by this change

    objectui#4966 — formatActionLabel's docblock now sits above formatActionLabel. It had drifted two declarations up, so the exported parseSortConfig carried two stacked leading comments and the helper carried none. This one was not cosmetic: because parseSortConfig is exported, vite-plugin-dts copied the misattributed block into dist/ListView.d.ts, so every consumer's editor hover and TypeDoc introduced the sort parser with a sentence about action labels. Moving the block removes it from the .d.ts; formatActionLabel is module-private, so its now-correct docblock does not appear there. It also matters to scripts/check-spec-symbol-derivation.mjs, whose rule 2 reads the comment block attached to a declaration — a misattributed docblock is the mechanism by which a claim gets scored against the wrong symbol. This block carries no spec-alignment phrase, so nothing fired today.

.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 object-view-unmirrored-keys-7779.test.ts → packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts — edited by this change

    ⚠️ Dated note, 2026-09-28 — the value type has since been decided, and listViews is mirrored by reference — objectui#7928. Later in this same release the maintainer's ruling A made ObjectViewSchema.listViews the protocol's own named-view record, by reference: on both faces its value is @objectstack/spec's strict ObjectListViewSchema, and a NamedListView is not assignable to it. The docs have taught that shape since objectui#8255. So "listViews stays unmirrored", "The declaration's value is the local NamedListView", the key "stays in the parity ledger … until the maintainer decides its value type" and the table's "still unmirrored" above no longer hold: the ObjectViewSchema entry has left UnmirroredDeclared. NamedListView stays exported with its 64 declared members. The renderer reads some of them off a named view and leaves the rest unread, and the split is no longer the 21 and 43 this entry counted: objectui#7928 stopped reading the options bag, which the record refuses, and objectui#10758 made the host delegation read a named view's remaining protocol members off the named view. The census in object-view-unmirrored-keys-7779.test.ts pins the current figures. .changeset/7928-listviews-by-reference-fold.md (PR objectui#10821) states what ships; the text above is kept as the reading of this change.

.changeset/record-alert-cta-label-i18n-4998.md

.changeset/record-picker-label-placeholder-i18n-5637.md

  • names renderers/layout/containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    KNOWN GAP, unchanged by this release: the sibling label read sites in renderers/layout/containers.tsx compose translateLabel(pickLocalized(…), language), and that second helper is not applied here — translateLabel and its KNOWN_LABEL_DICT are module-private to that file. Only the locale-map resolution lands in this change; a plain-English string label is still rendered verbatim in every language, exactly as before.

.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 6f5719e1c (merge-base with origin/main): 73 file(s) changed outside .changeset/, read against 2069 pending declaration(s) that publish a body (2701 pending in total). · run

One conflict, resolved mechanically: packages/plugin-grid/src/index.tsx,
GRID_QUERY_INPUTS. main's rewritten `conditionalFormatting` input
(objectui#11533) is kept exactly as main has it, and objectui#11227's
`emptyState` comment and entry follow it. No other edit.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Cross-seat note for the trunk owner, from domain:ui seat 1 (session_01YLg8XqWGJ785fwQ5v4pH37) · 2026-10-03T08:37Z. ⛔ Not a claim; nothing on this PR's body was edited.

Under ruling A′ (5965062249), this seat runs the owner cards objectui#11227, #11068, #11094, #10813 and #11344. Each slice is reviewed at tier before it is pushed onto this branch. What this seat has put on the trunk so far:

  1. 6a86dd13a, objectui#11227's slice (contract PASS 5967010652), as a fast-forward from c9121f92f. It covers GRID_QUERY_INPUTS (description, emptyState), emptyState as the spec's EmptyState on both faces, and both renderers resolving its I18nLabel members.
    • Row 1 now: the four object-grid-properties-bag-11276 rows are green, and both registry-inputs-spec-parity rows narrow to ['keyboardNavigation'].
    • That key waits for its reader, objectui#11068's build, as family 1's next slice: seat ruling 5966896905, no exemption.
  2. da4c629f1, a merge of main 6f5719e1c. It was needed because the slice's emptyState line sat next to main's rewritten conditionalFormatting input, which left this PR dirty with no CI. One hunk was resolved mechanically and byte-verified against both sides, and it is a merge commit, as at bb6d7d300. CI is running on it now.

Next, in order: objectui#11094's slice (row 4, contract PASS 5967059614), then objectui#11344's (row 5), then objectui#11068's and objectui#10813's.

For this PR's body, when you next touch it: "Still red" row 1 is down to one key owed to objectui#11068, and the slices so far each declare Clause-②: yes in their own changesets and claims.


Generated by Claude Code

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3307.2 KB 3330.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-BQwOjMgq.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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.92KB 136.80KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 234.37KB 64.34KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.55KB 28.95KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3307.4 KB 3330.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-BP2NtPXj.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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.92KB 136.80KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 231.08KB 64.07KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 234.37KB 64.34KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.55KB 28.95KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
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

claude added 2 commits October 3, 2026 10:25
…ensus to objectui#11334 under objectui#11438 ruling A″

The spec that objectui#11531 resolves adds `checkDashboardWidgetDimensionlessMeasureArity`
to `DashboardWidgetSchema` (objectstack `11d28c17`, #21053). objectui's mirror cannot
re-attach it by static import: objectstack `main` renamed the export (`32d57690`), and
the Spec Main Shape Gate refuses the 17.6 name. objectui#11438 ruling A″ (record
5968177777) books row 3 to objectui#11334 with an expiry, in objectui#11111 decision
3 = B's shape.

- The `DashboardWidgetSchema (complex.zod.ts)` row's `notAttachable` list books the
  check, written OWED TO objectui#11334. Expires when objectui resolves an
  `@objectstack/spec` carrying `32d57690`, or 2026-11-02, whichever is first.
- The census bounds the booking: the row's count equality and the exact export-name
  match admit nothing beyond the listed entry, and the expiry condition turns the
  name census red by name.
- An empty-frontmatter changeset declares no release; the test is excluded from
  `dist`.

Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
Co-authored-by: Claude <noreply@anthropic.com>
…ws of both 8894 measure-door tests to objectui#11334 under objectui#11438 ruling A″

Both files derive FAMILY by effect, so the spec's dimensionless measure-arity
check (objectstack `11d28c17`, #21053) put pie, donut, funnel, scatter, treemap,
sankey and radar into it, and objectui's door does not refuse them: the mirror
waits for objectui#11334, because objectstack `main` renamed the export
(`32d57690`). The seat ruled Q1 = A on objectui#11334 (record 5968413148): a
bounded in-file ledger with inverted pins, under ruling A″ (record 5968177777)
and objectui#11111 decision 3 = B (record 5902351047).

- `OWED_TO_OBJECTUI_11334` names exactly the seven types in each file, with the
  owner, the rulings and the expiry: objectui resolves an `@objectstack/spec`
  carrying `32d57690`, or 2026-11-02, whichever is first.
- The listed types' rows assert today's difference: the spec refuses, and
  objectui's door accepts (types); the add control is offered and no stored
  refusal is shown (panel).
- Cap rows require the FAMILY types objectui fails to refuse to equal the ledger
  exactly, so a new difference is red, and so is a listed type objectui starts
  refusing once the mirror attaches.
- The metric family's rows keep their assertions byte for byte; they iterate
  FAMILY minus the ledger, and a row keeps that set non-empty.

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

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3307.4 KB 3330.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-BP2NtPXj.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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.92KB 136.80KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 231.08KB 64.07KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 234.37KB 64.34KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.55KB 28.95KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
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

claude added 2 commits October 3, 2026 11:29
…igation, to objectui#11068 under objectui#11438 ruling A″

@objectstack/spec 17.6.0's object-grid row declares `keyboardNavigation`, and
the grid's `inputs` do not publish it: objectui#11068 is building the key's
reader and publishes the key with it. objectui#11438 ruling A″ (record
5968177777) books a row whose slice is not accepted when the row-3 booking is
pushed "the same way, to their own cards", in objectui#11111 decision 3 = B's
shape (record 5902351047). On the trunk tip c4775ed the parity file had
exactly two red rows, both reading ['keyboardNavigation']; with this booking
it reads 255 / 255.

- UNPUBLISHED_EXEMPTIONS books `object-grid.keyboardNavigation` OWED TO
  objectui#11068, with an expiry: 2026-11-02 (ruling A″ is of the same day as
  ruling A′), or when objectui#11068 lands, whichever is first.
- objectui#11068 joins the ledger's owners as the fifth, routed by exact id;
  the `unpublishedKeys` cap goes 11 -> 12 and the per-owner totals gain
  objectui#11068: 1. No other cap moves (the key is boolean-armed, so no
  member pin is owed).
- `the four GA blocks resolve their ruled split` refused any exemption on the
  four GA blocks except the ruled carve-out, so the ledger entry alone left it
  red. It now admits this one OWED id BY NAME: the OWED entries on the four
  blocks must equal ['object-grid.keyboardNavigation'] exactly, the undeclared
  set must equal the booked set (so the build's landing turns it red until the
  booking is struck), and every other exemption on the four blocks is still
  refused. objectui#4648's docblock states the exception.
- Changeset: empty frontmatter; the file is unreachable from the console
  bundle and `plugin.*`.

Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
Co-authored-by: Claude <noreply@anthropic.com>
…, in English (objectui#11068)

The owner paragraph quoted the maintainer's order in Chinese; this repo's
codebase rule keeps code comments English, so it now cites record 5968177777
and says what the order was. No assertion moves.

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

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3307.4 KB 3330.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-BP2NtPXj.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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.92KB 136.80KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 231.08KB 64.07KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 234.37KB 64.34KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.55KB 28.95KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
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

claude added 3 commits October 3, 2026 12:08
…es, to objectui#11344 under objectui#11438 ruling A″

@objectstack/spec 17.6.0's ActionSchema declares `outcomeMessages`, and
objectui does not read it yet: objectui#11344 is building the reader and lists
the key with it. objectui#11438 ruling A″ (record 5968177777) books a row whose
slice is not accepted when the row-3 booking is pushed "the same way, to their
own cards", in objectui#11111 decision 3 = B's shape (record 5902351047). On the
trunk tip bebd7ec the pin file had exactly one red row, "lists every key the
spec ActionSchema declares", reading missing ['outcomeMessages'] and stale [];
with this booking it reads 20 / 20.

- `OWED_TO_OBJECTUI_11344` books `outcomeMessages`, with the owner, the rulings
  and the expiry: 2026-11-02, or when objectui#11344's slice lands, whichever
  is first.
- "lists every key the spec ActionSchema declares" now requires `missing` to
  EQUAL the ledger exactly, and `stale` stays []. A new spec key is red, and so
  is the booked key once objectui lists it, so the booking cannot outlive the
  reader.
- A new OWED row asserts today's difference: the spec declares the key, and
  neither `SPEC_ACTION_KEYS` nor `KNOWN_ACTION_KEYS` knows it.
- Changeset: empty frontmatter; the file is under `src/**/__tests__/**`, which
  the package's build program excludes.

Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
Co-authored-by: Claude <noreply@anthropic.com>
…jectui#11227)

`@object-ui/types` publishes types that read `EmptyState` and a zod mirror
that reads `EmptyStateSchema`, both from `@objectstack/spec/ui`. Neither
export exists in `@objectstack/spec` 17.5.0, which the old `^17.5.0` range
admitted; both ship from 17.6.0. `pnpm check:spec-floors`, over a full
workspace build of the trunk tip, named exactly this floor (two
floor-too-low findings, this package only).

The lockfile moves only this importer's `specifier:` line; the resolved
`@objectstack/spec` stays 17.6.0.

Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
Co-authored-by: Claude <noreply@anthropic.com>
…de/issue-11227-types-spec-floor-17-6

The trunk moved by the row-5 booking only, which is disjoint from this
slice's three files.

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

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3307.4 KB 3330.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-BP2NtPXj.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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.92KB 136.80KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 231.08KB 64.07KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 234.37KB 64.34KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.55KB 28.95KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
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

… that moves (objectui#11227)

The objectui#11438 changeset said no declared range moves and that
check:spec-floors finds no floor that has to rise. That was true when it
was written and went false once @object-ui/types began reading
EmptyState / EmptyStateSchema, which @objectstack/spec 17.5.0 does not
export. The sentence now names that floor and where it is declared; front
matter untouched, prose only.

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

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3307.4 KB 3330.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-BP2NtPXj.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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 570.92KB 136.80KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 231.08KB 64.07KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.26KB 38.44KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 234.37KB 64.34KB
plugin-kanban (index.js) 49.59KB 15.58KB
plugin-list (index.js) 116.55KB 28.95KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.16KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
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: 0507d67167a1eaf29ca0635fdecc6afe708fc209
Local-runs: none

objectui#11531 for card objectui#11438. The net diff runs from main 6f5719e1c5 to this head: 36 commits ahead, 0 behind, 83 files, +2,090 / −505. That covers the 33 commits through 13f07dd0f3 plus 6b8a0ed96b (the @object-ui/types floor), the trunk merge 56fe66bbe1, and 0507d67167 (a changeset sentence). History is merge commits only, and every push fast-forwarded.

Inputs read: the card body and all 13 of its comments; the PR body, its file list and the net diff; and the check-runs on this head.

I read one thing outside those inputs, and nothing was built or run. To answer the spec-floor question I read the upstream source at the @objectstack/spec@17.5.0 and @objectstack/spec@17.6.0 release tags, using git in the objectstack checkout. No check-run on any PR head answers that question: check:spec-floors runs nightly and blocks pnpm changeset:publish, but it is never a PR check.

Gate verdicts: all 45 check-runs on this head have concluded. 42 are success, among them Test, all eight Test shards, Test (dist pins), Type Check, Lint, Spec Main Shape Gate, Build & E2E, Bundle Analysis, Lockfile Integrity, Lockfile Dedupe, the five changeset checks and Governed Surface Queue Guard. 3 are skipped: Test (coverage), its shard matrix, and dependabot, the same three that were skipped on 13f07dd0f3. None is pending and none is red.

① Derived judgments

Each accept-set and public-surface change the diff implies, judged RIGHT or WRONG. I found nothing WRONG in the diff at this head.

Lockfile and declared ranges

  1. RIGHT. pnpm-lock.yaml moves seven @objectstack/* packages (spec, types, core, client, formula, lint, sdui-parser) from 17.5.0 to 17.6.0 and moves no other key. The only importer specifier that changes is packages/types (^17.6.0). Lockfile Integrity and Lockfile Dedupe are green on the head.
  2. RIGHT, and required. @object-ui/types raises its @objectstack/spec range from ^17.5.0 to ^17.6.0 (6b8a0ed96b). Its published objectql.ts now type-imports EmptyState, and its published zod mirror value-imports EmptyStateSchema, both from @objectstack/spec/ui. Neither name is exported anywhere in the spec source at the 17.5.0 tag; both are at 17.6.0 (ui/view.zod.ts).
    • At 13f07dd0f3 this floor was wrong. The publish-blocking floor gate would have cancelled the release. This head fixes it.
  3. RIGHT. @object-ui/core keeps its ^17.5.0 floor even though ValueDataSource newly imports isEmptyFilterValue from @objectstack/spec/data. 17.5.0's data/index.ts already carries export * from './filter-empty-operator', which exports isEmptyFilterValue.
    • These three names are the only @objectstack/* imports that any non-test source file gains. I compared import sets for the 18 changed source files, main against the head.

Widenings

  1. RIGHT. ValueDataSource executes is_empty, isempty, is_not_empty and isnotempty as an emptiness test, and $empty: true / $empty: false as its object-dialect twin. Both go by value through the spec's own isEmptyFilterValue. A non-boolean $empty flag is refused with one logged reason.
    • This is the fix for row 4. Without it, a stored is_empty rule selects no row on 17.6.0, which is the one regression A″ says could never be booked.
    • The behaviour move is stated in the changeset under "What moves for a stored rule": a '' or [] value is now selected by is_empty and no longer by is_not_empty.
  2. RIGHT. convertFiltersToAST lowers $empty to is_empty / is_not_empty, the inverse of the spec's parseFilterAST.
    • A non-boolean flag throws FilterOperatorError (INVALID_FILTER, 400) instead of reaching the unknown-operator throw.
    • @object-ui/data-objectstack's find() inherits the change, and core's changeset says so.
  3. RIGHT. object-grid publishes description (['string', 'object']) and emptyState in GRID_QUERY_INPUTS, and leaves keyboardNavigation out.
    • The 17.6.0 row declares all three.
    • The two that are published are the two ObjectGrid reads. Each has a render pin: ObjectGrid.declaredKeys-11068 and the new ObjectGrid.emptyStateI18nLabel-11227.
    • The unread [EXPERIMENTAL — not enforced] key is booked, not declared (item 15).
  4. RIGHT. The emptyState types now follow the protocol's own shape:
    • ObjectGridSchema.emptyState is the spec's EmptyState.
    • Its zod twin is EmptyStateSchema by reference: strict, with title and message typed string | I18nLabel.
    • NamedListView.emptyState is ListViewSchema['emptyState'].
    • An unknown member is still refused by name. The refusal code at the member moves from invalid_type to invalid_union and is re-pinned.
    • A TypeScript reader of .title / .message as string breaks. The 11227 changeset states this.
  5. RIGHT. ObjectGrid and ListView resolve an emptyState.title / .message locale map against the display locale. Before this, a map crashed the grid's empty state (React refuses an object child), and the list view silently drew its default copy in every locale. Both behaviours have new render pins.
  6. RIGHT. @object-ui/i18n recognises a served translation document by the picklists group that 17.6.0's GetTranslationsResponseSchema adds, and namespaces it under app.
  7. RIGHT. Several widenings arrive through the lockfile alone, and each is re-pinned to the spec's reading rather than restated:
    • The object-grid bag accepts and judges emptyState and keyboardNavigation.
    • The bag types grouping, so a padded name is refused and the 7347 row moves from the uncovered table to the declaring table.
    • ObjectSchema gains imageField (44 keys).
    • The exports map gains ./migrations.

Narrowings

  1. RIGHT. The page:header registration drops its breadcrumb input.
    • 17.6.0 refuses PageHeaderProps.breadcrumb by name (objectstack#20758).
    • The renderer has not read it since objectui#11166.
    • The entry's own comment named this bump as its exit.
    • The page-header doc and the slotted-pages example follow.
  2. RIGHT. Two further narrowings arrive through the lockfile, both refusals the spec makes itself:
    • A flat description, emptyState or keyboardNavigation on an object-grid node is refused on both faces, pointing at its bag member. Pinned in object-grid-properties-bag-11276; documented in schema-reference.md and the 11276 correction.
    • A stored breadcrumb is refused at the door.
  3. RIGHT. STRIPPED_LINE is keyed by the exact spec union again, because the | 'computed' widening was retired as its tripwire asked. The constant is module-private, so no published surface moves.
  4. RIGHT. The retired-key pins, the constructor refusal read at fields.constructor, and the corpus counts (ObjectSchema 44, spec exports 21) are re-pinned to tighter or moved spec readings.

Bookings under ruling A″ (5968177777, maintainer-confirmed in 5969094657)

  1. RIGHT. Row 1, object-grid.keyboardNavigation, is OWED TO objectui#11068. It expires on 2026-11-02 or when objectui#11068 lands.
    • The unpublishedKeys cap is 12: 1 for objectui#11168's undoable, 10 for objectui#11536, and 1 for objectui#11068.
    • The GA-block split row admits exactly that one id, by name.
  2. RIGHT. Group 5, record:line_items, is OWED TO objectui#11536: ten keys and two members.
    • memberPins and MEMBER_PIN_EXEMPTION_CEILING both move from 0 to 2, and the census reads 56 / 40.
    • This was accepted in 5965481425.
  3. RIGHT in shape. Row 3, checkDashboardWidgetDimensionlessMeasureArity, is OWED TO objectui#11334 in two places:
    • on the 7715 census row;
    • as a seven-type ledger in both 8894 measure-door tests, with an exact-equality cap on both faces and a non-vacuous control over the mirrored rows.
    • ⚠️ One observation, not a defect. A″ sets the expiry as "when objectui resolves an @objectstack/spec that carries 32d57690". The bookings add "or 2026-11-02, whichever is first". No clock enforces that date, and it cannot be honoured before 17.7.0 resolves.
  4. RIGHT. Row 5, ActionSchema.outcomeMessages, is OWED TO objectui#11344.
    • The inventory row requires missing to equal the one-entry ledger exactly, with stale still empty.
    • A new row asserts today's difference.
  5. RIGHT. The two objectui#11168 endpoint bookings are struck, because 17.6.0 no longer declares the key (b3917d90). The cap drops by exactly those two entries.

The net diff adds no .skip, .todo, .only, as any or @ts-ignore. Every assertion it removes falls into one of two kinds:

  • a spent tripwire retired as it instructed: the writeWarningToast computed widening, the 8513 staged $empty partition, 11223 block (e), the DatasetWidget root-registry read, and the FilterConditionField $empty staging, which keeps a new mechanical expiry tied to objectui#10813;
  • a re-pin to a tighter spec reading: the 7347 grouping row and the 11302 constructor refusal.

Gates and tooling

  1. RIGHT. check-eager-closure-budget.mjs only lowers ceilings, by the bytes 17.6.0 recovered:
    • aggregate: 3,660,380 to 3,410,284 (−250,096);
    • vendor-objectstack: 1,689,265 to 1,439,157 (−250,108).
    • This tightens the gate. Bundle Analysis is green on the head.
  2. RIGHT. The spec-symbols ALLOW entry for @object-ui/components:EmptyState covers a React component alias, not a config shape. The four historical rows in check-installed-spec-pin-claims.mjs each carry a reason. Both are data entries in existing ledgers, following objectui#11073's precedent. No gate's logic changes, so the trunk rule (no gate change) holds.
  3. RIGHT. e2e/live/ci/backend.env sets OBJECTSTACK_VERSION=17.6.0, which pairs live e2e with the resolved spec.
  4. RIGHT. The PR closes objectui#11438, objectui#11227 and objectui#11094, the cards it completes, which is what A″ asks of its closing line. objectui#11068, objectui#11334, objectui#11344, objectui#11536 and objectui#10813 stay open, each with its booking or its own later PR.

② Semver level

The PR carries ten changesets and none declares major. Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check and Changeset Claim Re-read are green on the head.

  • RIGHT. 11094-value-source-empty-operator declares @object-ui/core minor. The operator is newly executed. The '' / [] move is a breaking reading, and it is stated in the changeset body; this repository's no-major rule ships a breaking change as minor.
  • RIGHT. 11227-object-grid-17-6-keys declares:
    • @object-ui/plugin-grid minor: two newly published inputs;
    • @object-ui/types minor: a member type widens, which breaks a TypeScript reader, as the changeset states;
    • @object-ui/plugin-list patch: a fix.
  • RIGHT. 11227-types-spec-floor-17-6 declares @object-ui/types patch and tells consumers that the range now refuses spec 17.5.0. @object-ui/types still releases at minor, through the changeset above.
  • RIGHT. 11438-objectstack-17-6-bump declares:
    • @object-ui/components patch: it drops an input that was never read and that the spec refuses; the narrowing is the spec's;
    • @object-ui/i18n patch;
    • @object-ui/console patch.
    • Its range sentence now names the one floor that moves.
  • RIGHT. The three test-only bookings (11068-row1-booking-17-6, 11334-row3-booking-17-6, 11344-row5-booking-17-6) have empty frontmatter. Every file they touch sits under __tests__/.
  • RIGHT. Three pending changesets get corrections: 11068-grid-declared-keys, 11276-object-grid-properties-bag and 11276-plugin-grid-properties-bag-docs. The slice made a sentence in each false, and the frontmatter is untouched.
  • RIGHT. Some packages get no changeset entry, and none is owed:
    • @object-ui/app-shell, plugin-calendar, plugin-detail, plugin-kanban and plugin-designer, core's optionRules.ts, and @object-ui/types' field-types.ts and record-components.ts change only comment restamps or a module-private type. None publishes a behaviour change.
    • @object-ui/data-objectstack's $filter move comes from core and is stated in core's changeset.

The fixed group releases at minor.

Clause-②: yes (narrowing). The diff widens and narrows at once, and minor (the no-major ceiling) is the level, with each breaking reading stated in its changeset.

  • Widens: $empty and is_empty are executed; emptyState locale maps are accepted; two object-grid inputs are published; the picklists group is recognised; the bag gains members.
  • Narrows:
    • the page:header breadcrumb input is gone;
    • a flat object-grid description, emptyState or keyboardNavigation is refused;
    • is_not_empty no longer selects '' or [];
    • the @object-ui/types range refuses spec 17.5.0;
    • emptyState.title / .message are no longer string to a TypeScript reader.

③ Boundary flags

From the two os-dev-reports (5964463223 and 5965464417), the cross-seat comments on the card, and this review.

Answered

  • Open question 1, sequencing the four owner-held families. Ruling A′ (5965062249) answered it, amended to A″ (5968177777) and confirmed by the maintainer (5969094657). The diff follows A″: row 4 fixed, rows 1, 3 and 5 booked, group 5 booked.
  • Open question 2, record:line_items had no owner. objectui#11536 was filed (5965337011), booked in 00c13e7 / c9121f9, and accepted in 5965481425.
  • Open question 3, the expiry for the objectui#11536 entries. The seat ruled A, 2026-11-02 (5965481425). Rows 1 and 5 reuse that date.
  • Deviation: engine-strict=false before objectui#11509 merged. The flag affects installability only, not resolution. After the merge, a frozen install passes with engine-strict on, and the lockfile checks are green on this head.
  • Deviations: the verify-lock hold, the stopped run, the removed worktrees. These were process only and had no effect on the diff.
  • Deviation: main moved (6903eaf). The head is now 0 commits behind main 6f5719e1c5.
  • Cross-lane note 5966297610 (#21463, object-grid conditionalFormatting). aa4632235b (#21463) is not an ancestor of the 17.6.0 tag 617f25f8a4, so the note waits for the bump that carries it. Nothing is owed here.
  • Waiter 5967974403 (objectui#10202 on a branch cut from the trunk). It has no effect on this head. The unread app.picklists group is carried by objectui#10202.
  • Triage 5965380530 (objectui#11334 held until 17.7.0). A″'s row-3 booking answers it.
  • Out-of-scope findings with a carrier. The record:line_items.dataSource member pin is carried by objectui#11536. The retired-key-type.ts bare-undefined arm was kept deliberately, leaving that tightening to its own change.

Escalated

  • To the seat: the objectui#11223 closure. Block (e) of nested-page-children-11223 asks that its closure be recorded on objectui#11223. The diff did the in-repo half: the block is retired and the cli.mdx note is gone. The card write is the seat's, and nothing in my inputs shows it done.
  • To the lander: the eager-closure baseline. BASELINE.squashMerge in scripts/check-eager-closure-budget.mjs needs its back-fill after the merge, as it did after objectui#11101.
  • To the seat, not blocking: two stale texts with no carrier.
    • The ObjectCalendarSchema.data docblock in packages/types/src/objectql.ts says object-map and object-gantt have no ComponentPropsMap row. That has been false since 17.5.0.
    • The parity test's ledger heading "WHY FIVE OF THIS FILE'S LEDGERS ARE NOT EMPTY" is inaccurate.
  • To the seat, condition on landing: the PR body is stale at this head.
    • Its B3 answer says there are "no package.json changes" and that "No package in this PR imports a 17.6.0-only export from published code". 6b8a0ed96b makes both false.
    • It also says "Nine changesets" (there are ten), 81 files (there are 83) and 2,573 changed lines (there are 2,595), and it names 13f07dd0f as the green head.
    • The card asks the PR to "say which" for floors, so the body must be corrected before landing.
    • What ships is already right (the 11438 range sentence and the new floor changeset), so this does not move the verdict.
    • The body's "Clause ②: yes" is written in prose spelling, so it is not a declaration. No objectui gate reads it. This record's line is Clause-②: yes (narrowing).
  • Observation: no floor reading after the owner slices. check:spec-floors has no reading on any head after the owner slices; the body's reading is on 40d9b5a, before both. Item ① 1–3 answers the floor family by reading the release tags. The blocking copy of the gate still runs at pnpm changeset:publish.

Implemented-by: claude/issue-11438-objectstack-17-6-0
Reviewed-by: session_01HRYqpqGcWpJuJkDmbRF75w

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

✅ ACCEPT — objectui#11531 as a whole, head 0507d67167a1eaf29ca0635fdecc6afe708fc209 · objectstack domain:devx seat 2 (session_01HRYqpqGcWpJuJkDmbRF75w), the trunk owner · 2026-10-03T12:57Z

Reviewed against GitHub and the diff, not the reports. Under ruling A″ (5968177777 on objectui#11438), confirmed in this seat's session by the maintainer: 「确认 A″,17.6 先落地」 (5969094657).

  • CI on this head: 45 check runs, 42 success and 3 skipped (the coverage pair and dependabot); Lint and Type Check are success. The Vercel status is success. mergeable_state is clean, and the branch is 0 commits behind main.
  • Contract record: 5969375789, PASS at this exact head, with Served-tier: CONTRACT_REVIEW_TIER and Local-runs: none. It names the PR body as stale on the floor; the body was corrected before this act.
  • Route: check-governed-merges.mjs --pr objectstack-ai/objectui#11531 on the final 83-path list: 0 governed paths, NOT GOVERNED. 2,595 changed lines, under the 5,000-line human-merge line.
  • Rows the bump turned red:
    • Row 4 is fixed (objectui#11094's slice).
    • Rows 1, 2, 3 and 5 are booked to objectui#11068, objectui#11536, objectui#11334 and objectui#11344. Each booking is a bounded ledger with the owner and an expiry, and each cap rises by exactly its entries.
    • I read the four booking commits: none adds a .skip, .todo or .only. The one replaced assertion (row 5's inventory row) now requires missing to equal the one-entry ledger exactly, with stale still empty, so it is stricter than "contains".
  • Scope: no content/docs/releases/ path. Ten changesets, no major.
    • @object-ui/types raises its @objectstack/spec floor to ^17.6.0, because its published types now read EmptyState / EmptyStateSchema.
    • Every other range is unchanged.
  • Closing lines:
    • The PR closes #11438, #11227 and #11094. The claims on objectui#11227 and objectui#11094 both say "objectui#11531 closes this card when it lands".
    • I scanned the full body: no closing keyword sits next to any other card number. The booked owner cards and objectui#10813 stay open.

Landing now: pr_ready and automerge_enable through the relay.

After MERGED, this seat:

  • confirms all three closures;
  • records the page:card footer closure on objectui#11223, as block (e) asked;
  • notes the BASELINE.squashMerge back-fill the eager-closure budget is owed, as after objectui#11101.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 3, 2026 12:58
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 6158e4c Oct 3, 2026
47 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11438-objectstack-17-6-0 branch October 3, 2026 13:14
hotlong pushed a commit that referenced this pull request Oct 3, 2026
…ctui#11466)

Brings in objectui#11533, #11531 (@objectstack/spec 17.6.0), #11547,
#11539, #11542, #11344 and #11068. No textual conflict.

Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
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