Skip to content

feat(types)!: object-grid operations and the grid / kanban / calendar filter follow the @objectstack/spec 17.7.0 rows (objectui#6152, round 8) - #11969

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-6152-r8-17-7-member-moves
Oct 8, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-6152-r8-17-7-member-moves

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #6152 (round 8)

Clause-②: no

Round 8 of this card: the @objectstack/spec 17.7.0 member moves on object-grid, object-kanban and object-calendar, as triage booked them in comment 6029312212. Round 9 (ObjectCalendarSchema.calendar's .passthrough()) is not in this PR; #6152 remains open for it. Claim: comment 6058878246 (branch claude/issue-6152-r8-17-7-member-moves, cut from main 70e3d772).

This round narrows and widens nothing, hence Clause-②: no. The contract review at CONTRACT_REVIEW_TIER that the claim names is owed before the queue.

What changed

@object-ui/types

  • ObjectGridSchema.operations takes the object-grid row's strict { create?, update?, delete?, export? } block by reference: NonNullable of ObjectGridProps['operations'] on the interface, the row's own member .extend()-ed on the flat zod mirror (the ConditionalFormattingRuleSchema precedent). read and import are retired on both faces: ?: never with @deprecated on the interface, a retirementTombstone() on the mirror. No object-grid code reads either, and the row refuses both by name. The read refusal also names the view-level spelling, because the mirror is the source of the object-view table slot: write navigation: { mode: 'none' } or operations: { read: false } on the object-view node.
  • filter on ObjectGridSchema, ObjectKanbanSchema and ObjectCalendarSchema takes its row's own member by reference, the ViewFilterRule array, on the interface (ObjectGridProps['filter'], ObjectKanbanProps['filter'], ObjectCalendarProps['filter']) and on the mirror (stripImportedDefaults(...).shape.filter). These were any[] and z.array(z.any()), so the AST tuple array and the MongoDB-style record the rows refuse type-checked and parsed. The kanban and calendar flat mirrors are the authored arms, so their doors narrow. The grid's authored door already was the row (objectui#11276); its flat mirror narrows the object-view table slot.
  • The operators tombstone's guidance named { create, read, update, delete } as the shape to write; it now names the four toggles.
  • conditionalFormatting needed no stroke here. objectui#11533 (grid) and objectui#11522 (kanban) had already moved both rules onto the list view's { condition, style }.

@object-ui/plugin-view: ObjectView composed its grid node's operations whole ({ ...operations, create: false }). With no operations authored, that is the view's default, read: true included, so every such grid node carried a member its row refuses. The view keeps read (its row-click gate in handleRowClick) and hands the grid the other toggles.

Registrations (plugin-grid, plugin-kanban, plugin-calendar): the filter inputs describe the ViewFilterRule array instead of "JSON-rules form", and the grid's operations input names the four toggles instead of "create/read/update/delete/export/import".

Root README.md: the Data Grid example drops "read": true from operations. Its properties now parse on the installed object-grid row. Restoring read gives unrecognized_keys at operations, the lit control.

Console parity pins sentences: object-calendar.filter, object-kanban.filter, object-kanban.conditionalFormatting and object-grid.conditionalFormatting stop saying the row is z.unknown() or "constrains nothing inside a member". The kanban wire pin's header says the same.

Fixture triage over the rule's consumer radius:

  • re-spelled to the rule array, because each wrote the tuple array as the authored or documented value:
    • kanban-calendar-filter-sort-8174.test.ts (it also gains tuple and record refusal rows);
    • object-kanban-allow-collapse-retired-8801.test.ts;
    • ObjectGrid.filterContextTokens-10607.test.tsx;
    • ObjectGrid.recordIdFilterToken-7297.test.tsx. The wire assertions there follow toFilterNode's lowering, so the operator arrives as equals.
  • updated census rows in object-gallery-filter-9309.test.ts.
  • left as written: the untyped renderer and gate tests that feed the AST form at runtime (ElementDataSourceGate, the element data-source tests, export and grouping). They pin what a host composes, which the renderers still lower. The objectui#10199 split is written out on each interface member.
  • imported-defaults-8317.test.ts registers the two new spec crossings, ObjectKanbanPropsSchema and ObjectCalendarPropsSchema.

New pins: packages/types/src/__tests__/grid-kanban-calendar-members-round8-6152.test.ts (56 tests) and packages/plugin-view/src/__tests__/ObjectView.gridOperationsWithoutRead-6152.test.tsx (3 tests).

Measured before editing (the dispatch's mechanism assumptions)

  • H1, the sites:
    • Held for the README, the interface and mirror operations, ObjectView and the console pins sentences.
    • Partly falsified for conditionalFormatting. Both twins were already the list view's rule (objectui#11533, objectui#11522), and gridRowDecorationMembers-8071.test.tsx already pins its native rows as stored-rule compatibility reads.
    • The interface's second operations and the mirror's other two (ObjectViewSchema, objectui's ListViewSchema) belong to other blocks, measured below, and are untouched.
  • H2, the install surface (resolved @objectstack/spec@17.7.0, probed with lit controls):
    • ComponentPropsMap['object-grid'] takes { create, update, delete, export } and refuses read / import with guidance. An unknown toggle is refused too (the strictness control).
    • conditionalFormatting takes [{ condition, style }] and refuses the native members and an extra label.
    • filter on all three rows takes [{ field, operator, value }] and an empty array, and refuses the tuple array (at filter.0), the record and a string. The kanban and calendar rows declare no operations.
    • ComponentPropsMap['object-view'] is undefined, and the spec's ListViewSchema / ObjectListViewSchema declare no operations. So the object-view's own operations and objectui's list-view operations are this package's own members, not the grid row's.
    • The grid / kanban / calendar filter rows were already the rule array at the 17.6.0 tag (git show of the tagged component.zod.ts). The bump PR's table attributes them to 17.7.0. The mirrors were behind either way.
  • H3, the live read: the read stays, and there is no fork.
    • operations.read !== false in ObjectView reads schema.operations || schema.table?.operations || default. Its first feed is the view's own declared member, which the protocol does not govern (no object-view row) and which stays.
    • Only the table.operations fallback was fed by the grid's now-retired key. The behaviour stays reachable from the view node, and the slot's refusal names that spelling.
    • The runtime read of a stored table.operations.read is unchanged. Corpus census (fence-aware JSON and markdown walk plus a TS literal scan): zero authored table.operations.read / .import. The only grid-row read in the tree was the root README.

Tests and gates (head e8dee5a4)

  • pnpm exec vitest run --maxWorkers=2 packages/types/ packages/plugin-grid/ packages/plugin-kanban/ packages/plugin-calendar/ packages/plugin-view/ apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, under the verify lock: Test Files 749 passed (749), Tests 13272 passed | 95 skipped (13367).
  • pnpm exec vitest run --maxWorkers=2 scripts/__tests__/, under the lock: Test Files 179 passed | 2 skipped (181), Tests 5452 passed | 2 skipped (5454).
  • The 12 touched test files, run alone with the verbose reporter: Test Files 12 passed (12), Tests 667 passed (667). Each file was counted non-zero.
  • type-check (the script echoed in every row): @object-ui/types, core, plugin-list, sdui-parser, plugin-dashboard, plugin-detail, plugin-map, plugin-timeline, plugin-calendar, plugin-gantt, plugin-kanban, plugin-grid, plugin-tree, plugin-view, plugin-designer, app-shell and console. All are Done. That is every package whose source names ObjectGridSchema, ObjectKanbanSchema, ObjectCalendarSchema or ObjectViewSchema: the downstream consumers of the narrowed types, read against the rebuilt @object-ui/types dist. plugin-grid first went red on the two typed fixtures above, which are now re-spelled.
  • pnpm check:doc-snippets (784 of 784 blocks, 0 failed), check:doc-examples, check:skill-examples, check:doc-types, check:readme-exports, check:spec-symbols, check:component-surface-parity (report-only), check:changeset-claims, check:pending-changeset-literals, check:new-line-citations (0 new), check:control-bytes and node scripts/check-changeset-presence.mjs: all exit 0. The doc gates ran after a scoped turbo run build (35 tasks) of their own --build-filter.
  • ESLint on the 16 changed TypeScript files: 0 errors (pre-existing no-explicit-any warnings only).

Ablations (one-shot, through ablation-replace.mjs, mutation proven on disk, restored to the HEAD blob with an empty git diff HEAD):

  • ObjectView's ...gridOperations set back to ...operations. plugin-view's tsc against the rebuilt types dist gives TS2322 ("Types of property 'read' are incompatible"), which proves the narrowed declaration is the one consumers read. The new view pin goes 2 red / 1 green, and the green one is its table.operations control.
  • The kanban mirror's filter set back to z.array(z.any()). The round-8 pin and the 8174 pin go 8 red / 70 green: identity, the differential rows on the tuple array, the AST node and the unknown operator, and the authored-door rows.

Acceptance notes (observations, not filed)

  • ObjectGridSchema.defaultFilters is a string-keyed Record of any on the interface and z.record on the mirror. The grid row has declared it as the same rule array as filter since 17.6.0. It reaches an author only through object-view table.defaultFilters, where ObjectView composes it with named-view filters. It is not one of this round's three members. No carrier.
  • ObjectGanttSchema / ObjectMapSchema flat filter stay any[] while their rows take the rule array. Their authored arms are the rows themselves (the properties bag), so the flat members reach no authored door. Same family, not booked here. No carrier.
  • Other console pins sentences still call their spec rows z.unknown() or z.array(z.unknown()) (object-grid.bulkActionDefs among them, which 17.7.0 types). They are not this round's members. Carrier: the next PR that touches that file.
  • The dispatched union held the verify lock for 15m48s on a shared box, and the lock flags that as possible holder-side starvation.

Deviations

  • The base is main 70e3d772, not the d92b2a15 read at dispatch. main moved by one unrelated commit (objectui#11923) before the worktree was cut.
  • The changeset carries the Clause-②: no line too.

Size

18 files, +675 / −131 against 70e3d772. Not governed: node scripts/check-governed-queue-guard.mjs --test over the 18 paths prints "NOT GOVERNED".

Implemented in session https://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw (os-dev, domain:spec @ objectui seat 1).


Generated by Claude Code

claude added 2 commits October 8, 2026 11:56
…ter follow the 17.7.0 rows

`ObjectGridSchema.operations` takes the `object-grid` row's strict
`{ create, update, delete, export }` block by reference; `read` / `import`
are retired on both faces (`?: never`, `retirementTombstone()`), and the
`read` refusal names the object-view's own spelling. `filter` on the grid,
kanban and calendar faces takes each row's own `ViewFilterRule` array member
by reference. ObjectView no longer hands its own `read` toggle to the grid
node it composes. Registration descriptions, the root README grid example,
the console parity pins prose and the fixtures that wrote the tuple array as
the documented value follow.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw
…e array; escape the calendar pins sentence

The two plugin-grid files that type their node as `ObjectGridSchema` wrote
the AST tuple array as the authored `filter`; they now write the
`ViewFilterRule` array and read the lowered AST off `$filter`. The console
parity pins sentence for `object-calendar.filter` carried an unescaped
apostrophe that broke the file's parse.

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

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 337 chunks) 3309.1 KB 3312.0 KB
Main entry chunk (gzip) 71.4 KB 350 KB
Entry file index-CaGj7Xn7.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) 17.97KB 6.62KB
app-shell (runtime-config.js) 22.59KB 7.89KB
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.15KB 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) 41.19KB 11.12KB
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) 587.49KB 141.58KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 268.74KB 68.04KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
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.52KB 2.39KB
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) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.50KB 11.82KB
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.43KB 15.54KB
plugin-charts (index.js) 84.71KB 23.25KB
plugin-chatbot (index.js) 199.63KB 47.46KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 231.46KB 48.87KB
plugin-detail (index.js) 248.57KB 65.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.11KB 45.88KB
plugin-gantt (index.js) 179.17KB 45.07KB
plugin-grid (index.js) 248.22KB 68.84KB
plugin-kanban (index.js) 52.22KB 16.38KB
plugin-list (index.js) 117.68KB 29.40KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.10KB 11.81KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.09KB 22.94KB
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.31KB 2.07KB
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.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
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) 23.87KB 7.83KB
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.44KB 2.07KB
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) 1.13KB 0.65KB
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.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
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: e8dee5a4b37cbd0d24fc731f55b72626ed47c2b9
Local-runs: none

Round 8 of objectui#6152 (the @objectstack/spec 17.7.0 member moves on object-grid / object-kanban / object-calendar), reviewed by an isolated subagent at the contract tier. Inputs, and nothing else: card #6152 from comment 5957903936 on (triage 6029312212 and its "Next rounds" list, the pointer 5961014236, the round-7 landing 6058675815, the claim 6058878246, the round-8 os-dev-report 6060247686); PR #11969's body, its 18-file list and its net diff against main (merge base 70e3d772; origin/main read at 5ab2f19b, nine commits past the base, none of which touches a file of this diff); the @objectstack/spec@17.7.0 tag in objectstack (ui/component.zod.ts, ui/view.zod.ts, shared/strict-object.ts, shared/lazy-schema.ts); and the head's check-runs. Read-only throughout: git fetch / git show / git diff / git grep in the existing checkouts, gh api reads. Nothing built, run, re-run or ablated.

① Derived judgments

Each accept-set or public-surface change the diff implies, judged against the installed protocol and the renderers' reads.

  1. ObjectGridSchema.operations, TypeScript face — right. The member becomes the NonNullable of ObjectGridProps['operations'] intersected with { read?: never; import?: never }. At the tag, GridOperationsSchema is a strictObject of four optional booleans (create, update, delete, export) with read and import as guidance, not members. The six-toggle local block is replaced by the row's four plus two ?: never tombstones on the defaultSort precedent. The type face loses two keys and admits nothing the row refuses.

  2. ObjectGridSchema.operations, zod mirror — right. stripImportedDefaults(SpecObjectGridPropsSchema).shape.operations.unwrap().extend({ read: retirementTombstone(…), import: retirementTombstone(…) }). The spec block carries no default, so the strip walker hands it back reference-equal and the four toggles ARE the row's own objects (the round-8 pin asserts identity member by member). .extend on the spec's closed object keeps the strict catchall and the row's error map, so a misspelt toggle (creat) is still refused as unrecognized_keys at operations in the row's own words; the two tombstones turn the row's unrecognized_keys for read / import into invalid_type at operations.read / operations.import carrying the remedy. Same verdict as the row on every value, a sharper path on two. The read remedy naming navigation: { mode: 'none' } or the view's own operations: { read: false } is the correct one, because of item 3. The operators tombstone's guidance now naming { create, update, delete, export } is prose repair on a refusal string, and object-grid-operators-tombstone-9739.test.ts re-derives the spelling from the installed package anyway.

  3. The object-view table slot — right; a narrowing, not a lost behaviour. The slot is BaseSchema.extend(ObjectGridSchema.shape).omit({ type, objectName }).extend(OBJECT_VIEW_TABLE_WITHHELD).partial(), and neither operations nor filter is in the withheld set, so the slot inherits both moves: table.operations.read / .import are refused at their path on the tolerant face, the strict face and safeValidateSchema, and table.filter takes the rule array and refuses the tuple array at table.filter.0. This door is objectui-native (the protocol has no object-view row, confirmed by ComponentPropsMap['object-view'] being undefined at the tag), so the protocol did not already refuse it: this is objectui closing its own door. The spelling WAS live: ObjectView reads schema.operations || schema.table?.operations || default and gates the row click on operations.read !== false in handleRowClick, so table.operations.read: false on a view with no own operations reached a reader. The retirement is a tombstone whose prescription is the behaviour-equivalent view-level spelling, the runtime fallback read is untouched (a stored document keeps its gate), and the corpus at the head carries no table.operations.read / .import anywhere: the only writers of operations.read are content/docs/plugins/plugin-view.mdx and packages/plugin-view/README.md, both on the view node's own operations, which stays. Nothing an author could write and have honoured is left without a spelling.

  4. ObjectGridSchema.filter, both faces — right. TypeScript SpecObjectGridProps['filter'] (ViewFilterRule[] | undefined); zod stripImportedDefaults(SpecObjectGridPropsSchema).shape.filter, the row's z.array(ViewFilterRuleSchema, { error: ruleArrayFilterError(…) }).optional() by reference (no default inside, so identity). Was any[] / z.array(z.any()): every value the new member takes, the old one took. The authored object-grid door does not move: since objectui#11276 it is ObjectGridBlockSchema's properties, the row itself, which already refused the tuple array; the flat mirror reaches an author only through the table slot (item 3).

  5. ObjectKanbanSchema.filter and ObjectCalendarSchema.filter, both faces — right; the authored doors narrow. Same construction from each row's own member (surfaces "this object-kanban" / "this object-calendar", both .optional() at the tag; the kanban member is not the grid's, which the pin's negative control checks). These flat mirrors are arms of AnyComponentSchema (index.zod.ts), so an authored object-kanban / object-calendar node now refuses what z.array(z.any()) admitted: the AST tuple array (at filter.0), an AST and node, a rule with an operator the protocol does not know. The record form and a string clause were refused before and after (z.array never took a non-array). Every mirror verdict is held to the row's verdict on seven values, and the pin asserts both verdicts occur. Behaviour: the board and the calendar hand filter to $filter verbatim (the objectui#8176 / plugin-calendar: getCalendarConfig reads schema.filter.calendar as the calendar configuration container — the filter.map defect #4034 closed, still live on the calendar (ObjectCalendar.tsx:145) #7711 wire pins, re-documented, not re-asserted), so a value a host composes at runtime still reaches the wire; what moves is only what an author may write, and the protocol row already refused the tuple array there with the same ruleArrayFilterError prescription. Corpus at the head: no authored tuple-array filter on any node in md / mdx / json / ts / tsx outside tests (the git grep hits are CHANGELOG history, the new changeset's own FROM line and an ObjectGrid.tsx docblock), and the doc gates are green on the head.

  6. ObjectView hands the grid node operations without read — right; no document loses a behaviour. const { read: _viewRowClickGate, ...gridOperations } = operations; then operations: { ...gridOperations, create: false }. The view's own TypeScript operations is { create?, read?, update?, delete? } (no import), so the rest type fits the grid's block; the view's reads of read (row-click gate), update / delete (handlers) and create (the create button) are untouched. ObjectGrid reads operations.create / .update / .delete / .export only: a git grep over plugin-grid/src, components/src and plugin-list/src outside tests finds no reader of operations.read or operations.import, which is also what the spec's guidance text says. With no operations authored the grid now receives { create: false, update: true, delete: true } where it received the same plus an unread read: true; a view-level read: false stays the view's; a table.operations block still reaches the grid as authored. The new plugin-view pin reads the node off the registered renderer through the real SchemaRenderer, with a table.operations control. The dev's ablation (...gridOperations set back to ...operations) going red on TS2322 at read is the right direction and shows consumers read the narrowed declaration.

  7. Registration descriptions (plugin-grid, plugin-kanban, plugin-calendar) — right, prose only. No input added, removed or retyped (filter stays type: 'array', operations stays type: 'object'), so the registry surface and the manifest objectstack regenerates at the pin bump move in description text alone. The grid operations description now states the replace-not-merge rule ObjectGrid applies (explicitOperations ?? default), which is a true reading.

  8. Root README.md — right. The Data Grid example is a properties bag, which is the row (ObjectGridBlockSchema); the row refuses operations.read with guidance, so the example was off-protocol since 17.7.0 and is on it now. The dev's lit control (restoring read gives unrecognized_keys at operations) agrees with the tag's GridOperationsSchema.

  9. Console parity pins sentences (four) and the kanban wire pin header — right. At the tag, object-grid.conditionalFormatting is ListViewSchema.shape.conditionalFormatting by reference, and the list view's rule is z.array(strictObject({ condition, style })), so "takes the list view's own { condition, style } rule and refuses the native members and any other key" is a true reading; object-kanban.conditionalFormatting is the same member for the same reason. The two filter sentences now say the authored member is the row's rule array and the renderer reads none of it. conditionalFormatting needing no type stroke is correct: the flat grid rule has been SpecListViewRuleSchema.extend(…) since objectui#11533 and the kanban's since objectui#11522; the dev's "H1 partly falsified" is the honest reading and the right call.

  10. Fixture re-spellings — right; no pin weakened. kanban-calendar-filter-sort-8174.test.ts (FILTER_VALUE to the rule array, the Equal rows to ViewFilterRule[] | undefined, four new refusal rows for tuple / record on both nodes, which the kanban-mirror ablation turned red); object-kanban-allow-collapse-retired-8801.test.ts (one positive-direction row); ObjectGrid.filterContextTokens-10607.test.tsx and ObjectGrid.recordIdFilterToken-7297.test.tsx (the typed ObjectGridSchema fixtures, the two tsc reds). In those two the expected wire moves from ['owner', '=', USER] to ['owner', 'equals', USER] because toFilterNode lowers a ViewFilterRule through viewFilterRuleToNode with the spec's normalizeFilterOperator, under which equals is canonical and stays. The one assertion that compared the wire to the handed value (toEqual(handed)) now compares to the lowered form and keeps the property it pinned: an already-resolved rule is not re-resolved against another user (USER survives under someone_else). object-gallery-filter-9309.test.ts is a census of the source text and moves with it; imported-defaults-8317.test.ts registers the two new crossings. The untyped runtime tests that feed the AST form are left as written, correctly, under the objectui#10199 split each interface member now spells out.

  11. New pins — adequate. grid-kanban-calendar-members-round8-6152.test.ts reads the precondition off the installed protocol with lit controls, holds every mirror verdict to the row's differentially, covers all three doors, and @ts-expect-errors the retired spellings in a type-checked test project; ObjectView.gridOperationsWithoutRead-6152.test.tsx as in item 6.

  12. Fences held. ObjectCalendarSchema.calendar's .passthrough() (round 9) and navigation.ts / navigation.zod.ts (objectui#11070) are untouched on the diff. None of the 18 paths is a governed surface (Governed Surface Queue Guard green); this record is owed by the lane charter for a narrowing, not by a tier.

Conclusion of ①: every move is a narrowing toward the installed protocol (items 1 to 6) or prose (7 to 9); nothing widens an accept set or the public surface. Clause-②: no is right.

② Semver level

  • Changeset .changeset/6152-grid-kanban-calendar-17-7-members.md: @object-ui/types minor; @object-ui/plugin-grid, @object-ui/plugin-kanban, @object-ui/plugin-calendar, @object-ui/plugin-view, @object-ui/console patch.
  • What the diff publishes: packages/types/src/** (types); plugin-grid/src/index.tsx plus two tests (plugin-grid); plugin-kanban/src/index.tsx plus one test (plugin-kanban); plugin-calendar/src/index.tsx (plugin-calendar); plugin-view/src/ObjectView.tsx plus one test (plugin-view); apps/console/src/__tests__/registry-inputs-spec-parity.test.ts (@object-ui/console). Six released packages, all in the fixed group, each declared; the root README.md and the changeset publish nothing. Match.
  • Level: the types change is breaking (two keys retired, three members narrowed), and objectui's convention is minor with the break written in the body, never major (check-changeset-no-major green). The body carries the FROM to TO for every retired spelling: the tuple array to the rule array with the literal respelling, operations.read to delete-the-key or the view-level navigation: { mode: 'none' } / operations: { read: false }, operations.import to delete-the-key, and it names what did not move (the view's own read, the renderers' reads). plugin-view at patch is right for a composition change that moves no authored door. The console entry covers a test-only change inside a released package's src/, which the presence gate counts; patch on a fixed-group member is harmless.
  • Clause-②: no agrees across the claim 6058878246, the PR body and the changeset; no arm is given, and no alone is well-formed for a narrowing. The at-tier record the claim owes is this one.

③ Boundary flags

Deviations in 6060247686:

  • Base 70e3d772, not d92b2a15 — answered: verified as the merge base; main has since moved to 5ab2f19b (nine commits) with an empty intersection against this diff's files. No action for the record; mergeability is the seat's at landing.
  • The changeset carries Clause-②: no — answered: consistent with the claim and the PR body; nothing reads it adversely.
  • Type-check sweep bailed, console needed plugin-tree dist — answered: process notes; the head's Type Check check-run is the measurement, and it is green.
  • Files beyond the claim's literal list (four re-spelled fixtures, the 9309 census, the 8317 registration, two round pins) — answered: all inside the claim's stated surface ("with their tests", the plugin packages, the console pins file), on the per-round pin precedent of rounds 3 to 7; the seat may widen the claim's file surface in its ACCEPT, as round 7's did.

open_questions: none.

out_of_scope_findings in 6060247686 (also the PR body's acceptance notes):

  • ObjectGridSchema.defaultFilters (a string-keyed record on both faces while the row has declared the rule array since 17.6.0; reaches an author through object-view table.defaultFilters) — escalated to the seat. Same family, same two files, and it reaches an authored door (the table slot), so "no carrier" is not the right disposition: book it as a round of this card beside round 9, or file it. Not a defect of this PR, which is scoped to the three members triage booked.
  • ObjectGanttSchema / ObjectMapSchema flat filter: any[] (TypeScript face and z.array(z.any()) mirror, while their rows take the rule array; their authored arms are the rows) — escalated to the seat with the item above, as the same family on the published type face; lower priority since no authored door is wider than the row.
  • Other pins sentences still call their rows z.unknown() (object-grid.bulkActionDefs among them) — answered: carrier is the next PR that touches that file; accepted.
  • Verify-lock hold of 15m48s — answered: process; the seat's; accepted.

Check-runs on the head

Polled from 2026-10-08T12:53Z (42 runs: 26 success, 3 skipped, 13 in progress) until settled at 2026-10-08T13:04Z: 43 check-runs, 40 success, 3 skipped by design (Test (coverage), Test (coverage shard …/4), dependabot), 0 failure, 0 in progress. Green among them: Type Check, Lint, Spec Main Shape Gate, Test (shard 1/8) to Test (shard 8/8), Test (dist pins), Build & E2E, Bundle Analysis, Build Docs, the five changeset gates, the doc gates and Governed Surface Queue Guard. No failing step to report.

Implemented-by: claude/issue-6152-r8-17-7-member-moves
Reviewed-by: session_01DBZ9bntPZ7VKyQNtJeNsgw

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 8, 2026 13:07
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 8, 2026 13:07
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit d7e9e9a Oct 8, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-6152-r8-17-7-member-moves branch October 8, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants