Skip to content

fix(plugin-view): the registered object-view reads a named view's grid members (objectui#10885) - #10937

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-10885-object-view-route2-named-grid
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-10885-object-view-route2-named-grid

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Part of #10885
Clause-②: no

Member 1 of objectui#10885: route 2, the registered object-view renderer's own grid path, reads a named grid view's grid members off the named view. Member 2 is not taken and member 3 is not in this PR (see Acceptance notes), so #10885 remains open.

Claim 5865109811, seat domain:ui#2, PM session session_014mXUNuFomfj24w7s1pZzhN (https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN), mode subagent.

What changed

  • packages/plugin-view/src/ObjectView.tsx, the gridSchema memo: the object-grid node ObjectView hands ObjectGrid when no host passes renderListView.
    • Ten members are read off the active named view first. pagination and selection then fall back to the node's table, as they did before. rowHeight, resizable, searchableFields, conditionalFormatting, rowActions, bulkActions, bulkActionDefs and exportOptions are named-view sourced, like grouping / rowColor beside them. There is no activeView rung and no new node read.
    • A named view's hiddenFields is subtracted from the resolved column projection, in both the fields and the columns slot (new helper withoutHiddenFields). It is not relayed as a key: object-grid does not declare it, and ObjectGrid has no read of it.
    • A named view's exportOptions written in the protocol's legacy bare-array spelling is lifted to { formats } (new helper gridExportOptions). That is the lift the protocol's own parse makes, and the one ListView makes for the delegation. ObjectGrid reads exportOptions.formats.
    • conditionalFormatting and bulkActionDefs carry a type assertion to the grid's declared element type. The protocol's expression wire is wider than that type (measured by tsc), and ObjectGrid hands both to the shared evaluator, which reads the wire.
  • The objectui#5097 HOST-COMPOSITION fence (the delegation) is byte-identical. The text between the two #region markers hashes to 40bc2292 on the base and on the head.
  • Docs (the docs-driven rule of AGENTS.md section 5): one prose paragraph each in packages/plugin-view/README.md and content/docs/plugins/plugin-view.mdx, beside the objectui#10758 paragraph. Neither gains a code fence.
  • Changeset .changeset/10885-object-view-route2-named-grid.md: '@object-ui/plugin-view': patch, with the claim's Clause-②: no line. @object-ui/app-shell gains only a test file, so it is not listed; check-changeset-presence passes.
  • No shared helper. The order allowed one helper for both routes only if the delegation's behaviour and pins stay untouched. objectViewHostSurface.test.tsx section 1b derives the fence's named-view read set by name from the fence text, and walks the rungs of the renderListView literal. Moving the reads out of the fence changes both derivations, so those pins would have to be edited. The two sinks also differ: ListView subtracts hiddenFields and lifts exportOptions itself, and ObjectGrid does neither. So the two routes share the precedence, not the code.

H1: reproduced on main (733fd5ac65)

Read from the DOM through the real stack: the real ViewPreview, the real SchemaRenderer and registry, the registered object-view renderer and the real ObjectGrid. The pin file ViewPreview.routeTwoGridMembers-10885.test.tsx was run on an untouched base tree.

  • A stored grid view { type: 'grid', columns: ['name', 'amount', 'stage'], hiddenFields: ['amount'] } still draws the hidden column. The header span reading Budget Amount is rendered (expected SPAN to be null).
  • The same view with rowHeight: 'compact' draws no row-height control: Unable to find an element with the title: Row height: compact.
  • Lit control, green on the base: columns: ['name', 'stage'] off the same named view IS honoured on route 2. Pipeline Stage is drawn and Record Owner, which is not projected, is not.

Members, per route

The measured set is bucket ① of the objectui#7924 ruling, all 23 members. Route 2 takes a member when three things hold: the installed @objectstack/spec 17.4.0 declares it under the same name on a named view (ObjectListViewSchema) and on object-grid (ComponentPropsMap['object-grid']), and ObjectGrid reads it. The pin re-derives both declarations.

member delegation (route 3, unchanged) route 2 before route 2 after
pagination named, host, node table.pagination named, then table.pagination
selection named, host, node table.selection named, then table.selection
rowHeight named, host (through the fold) none named
resizable named, host, node none named
searchableFields named, host, node none named
conditionalFormatting named, host, node none named
rowActions named, host, node none named
bulkActions named, host, node none named
bulkActionDefs named, host none named
exportOptions named, host none named (a bare array lifted to { formats })
hiddenFields named, host, node none named, subtracted from the projection (not relayed)
navigation named, host, node none none: excluded (Acceptance notes)
inlineEdit named, host, node none none: excluded (Acceptance notes)
description named, host none none: object-grid does not declare it
emptyState named, host, node none none: object-grid does not declare it
addRecord, allowPrinting, aria, compactToolbar, filterableFields, sharing, showRecordCount, userFilters named, host, node none none: list chrome with no object-grid slot

Route 2's named-view reads on the grid node go from 5 (columns, filter, sort, grouping, rowColor) to 16.

The ten are not the whole set that meets the test. Outside bucket ①, label and data are also declared on both and read by ObjectGrid, and navigation meets it too; none of the three is read off the named view on route 2 (Acceptance notes).

Pins and ablation

Red on the base 733fd5ac65 (the two new files copied onto an untouched base worktree), green on the head 56ad7e8774.

  • packages/plugin-view/src/__tests__/ObjectView.routeTwoNamedGridMembers-10885.test.tsx, 11 tests. It mounts through SchemaRenderer and the registered renderer, with ObjectGrid mocked as the sink.
    • Member set, 3 tests, green on both trees: each relayed member is declared on both protocol schemas; hiddenFields is declared on the named view and not on object-grid; the full fixture parses under the strict ObjectListViewSchema. The control is allowExport, which is on neither.
    • THE FIX, red on the base: pagination did not arrive from the named view: expected { pageSize: 100 } to deeply equal { pageSize: 5, …(1) }. The bare-array exportOptions lift is also red on the base.
    • The node control is green on both: table.pagination and table.selection apply when the named view omits them, and the other eight stay undefined although the node's table carries them.
    • hiddenFields, 5 tests. Four are red on the base: both slots lose the hidden field and no hiddenFields key reaches the grid; an object-shaped column keeps its shape; the node's table.columns is narrowed too; hiding every projected field keeps []. One is green on both: with no projection anywhere, nothing is invented.
  • packages/app-shell/src/views/metadata-admin/previews/ViewPreview.routeTwoGridMembers-10885.test.tsx, 4 tests, the whole real stack with DOM readings. hiddenFields and rowHeight are red on the base. The lit columns control and the neither-declared control are green on both.
  • Base: 8 failed, 7 passed (15). Head: 15 passed.
  • The delegation's objectui#10884 pins (ObjectView.namedViewProtocolKeys-8980.test.tsx, objectViewHostSurface.test.tsx) are untouched and green.

Ablation, run with ablation-replace.mjs on the committed head 695a6ce635 (the later 56ad7e8774 changes one test-header comment only). The directions were predicted before the run.

  • Leg A put the base's two table rungs back in place of the ten member rungs: anchor 1 → 0, blob dcce880456e3 → 57515b34b699.
  • Leg B neutralised the hiddenFields read: anchor 1 → 0, blob → a01a7bdbbcf4.
  • On disk, the named rowHeight reads went 2 → 1 (the fence's own stays) and the gridExportOptions call 1 → 0.
  • The run covered the whole packages/plugin-view/ suite, both ViewPreview pin files and three types census files. Result: 8 failed, 789 passed, 59 files. The 8 are exactly the new rows.
  • The restore was proven: the blob equals HEAD (dcce880456e3) and git diff HEAD is empty.

Consumer sweep

git grep over test files for 'object-view', ObjectView mounts and imports, ViewPreview, and the tests that read plugin-view's ObjectView.tsx, plus the objectui#7924 / objectui#7779 census tests. Everything ran on the head under the verify lock.

  • Batch A: 75 files, 1882 tests passed, VERDICT command-exit 0, at 695a6ce635. It covers the whole packages/plugin-view/ suite and the ten packages/types tests that read named views or the object-view docs. The census object-view-unmirrored-keys-7779, schema-reference-named-list-view-keys-7923 and object-view-listviews-by-reference-7928 are among those ten. The rest are from plugin-map, plugin-list, plugin-grid, core, react, examples and scripts.
  • Batch B: 38 files, 350 tests passed, VERDICT command-exit 0, at 695a6ce635. It covers app-shell's ViewPreview, StudioDesignSurface, ResourceEditPage and AppContent tests, the ObjectView.* tests (the relay census ObjectView.relayRungCensus-7559 among them), and five apps/console tests.
  • The 18 tests that read the changed markdown (from scripts/markdown-test-inputs.mjs --list): 829 tests passed.
  • Census: no number moved. The census counts a member as read when any route reads it off a named view. Every member route 2 now reads was already read by the delegation, so the partition stays 43 read / 21 unread of 64, with bucket ① empty. No census test was edited.

Gates

Each exit was captured redirect-first.

  • Exit 0 at the head 56ad7e8774:
    • check-changeset-presence ("3 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"), check-changeset-no-major, check-changeset-fixed, check-changeset-overwrite, and check-changeset-claims (6 pending paragraphs name a touched file; each was read, and none is made false);
    • check:pending-changeset-literals, check:new-line-citations ("0 new citation(s)"), check:control-bytes, check:test-path-roots, and the three check:vi-mock-* gates;
    • check:spec-symbols, check:phantom-deps and check:handler-key-reads;
    • check:doc-types, check:doc-fences, check:doc-example-ids, check:doc-example-readers, check-doc-expression-carriage and check-doc-links;
    • check-governed-queue-guard --test on the 6 paths: "An ordinary pull request".
  • type-check exit 0 at 695a6ce635 for @object-ui/plugin-view and for @object-ui/app-shell. Each runs tsc --noEmit && tsc -p tsconfig.test.json, after its dependency closure was built. --listFilesOnly finds each new test file in its package's test program. The app-shell run used a 6144 MB heap, because its test program is the largest in the repo.
  • ESLint --no-inline-config on the 3 edited TS/TSX files, which is the whole population: eslint.config.js covers them with files: ['**/*.{ts,tsx}'], and --format json reports 3 files.
    • 0 errors. ObjectView.tsx has 60 warnings, per rule identical to the base (53 / 4 / 3). The new pins have 6 and 1 no-explicit-any warnings.
    • Not type-aware: projectService / parserOptions have 0 hits against a languageOptions control of 1, so no untouched file's verdict can move.
  • NOT MEASURED:
    • check:readme-exports, reason: prerequisite not met. 86 self-imports could not be judged because the workspace dists are not all built. This diff adds no fenced block to any README.
    • check:doc-snippets and check:doc-examples: not run, because no fenced block was added.
    • The full app-shell and types suites, and the repo-wide lint: CI runs them.

Serial

  • PR objectui#10914 (head 2b3d2061a2) edits ObjectView.tsx in one comment of the view-switcher icon map. This PR's hunks are the column helpers and gridSchema. git merge-tree --write-tree against its head is clean (tree 4a03a230b6). Against a fresh origin/main (733fd5ac65) it is clean too (tree 749f02ef74).
  • ViewPreview.tsx is not edited (PR objectui#10906). The pin is a new file.
  • packages/plugin-grid/src/ObjectGrid.tsx is not edited (PR objectui#10278).

Fix round 1

The contract review of 56ad7e8774 failed on wording only. The code, the precedence, the hiddenFields composition, the exportOptions lift, the fence, the census, the pins, the ablation and the semver level all held. One commit, 097ba79141, text only:

  • Changeset, third paragraph, replaced with the review's text: it names the ten as ten members read off the named view first, and adds that label, data and navigation, also declared on both a named view and object-grid, are still not read off the named view on this path.
  • README and docs paragraphs, the same edit in each: "Ten grid members …" instead of "The grid members …", and the sentence that label, data and navigation, also declared on both, are not read off the named view on this path.
  • The withoutHiddenFields docblock now states its one divergence from ListView: an entry with no field identity is kept, where ListView drops such an entry whenever hiddenFields is non-empty. Comment only: the diff of ObjectView.tsx changes no code line.
  • Re-run at 097ba79141, under the verify lock:
    • the two pin files, object-view-unmirrored-keys-7779 and the 18 tests that read the changed markdown: 21 files, 1077 tests passed, VERDICT command-exit 0;
    • sweep batch A (the whole packages/plugin-view/ suite and every test that reads plugin-view's ObjectView.tsx): 75 files, 1882 tests passed, VERDICT command-exit 0.
  • Gates at 097ba79141, exit 0 each: check-changeset-claims, check:pending-changeset-literals, check:control-bytes, check:new-line-citations ("0 new citation(s)"), check-doc-links, check:doc-fences, check-changeset-presence, check-changeset-overwrite and check:handler-key-reads.
  • Fence: the text between the two #region markers still hashes to 40bc2292.
  • Serial: git merge-tree --write-tree is clean against a fresh origin/main (733fd5ac65, tree 46037fd4fc) and against PR objectui#10914's head (2b3d2061a2, tree 605c556b1d).

Acceptance notes

  • Premise correction for member 1. The card says ObjectGrid reads each of the eight members. Measured: it reads seven. It has no hiddenFields read, and object-grid does not declare the key.
    • hiddenFields is therefore honoured the way the protocol composes it (objectstack#15184 ruling B: columns projects, hiddenFields subtracts). It is subtracted from a declared projection, as ListView does for the delegation.
    • With no columns anywhere, the grid derives its own columns and the hidden field still shows. ListView has the same limit.
  • The full set beyond the eight. searchableFields, bulkActionDefs and exportOptions are also taken: each is declared on both schemas and read by ObjectGrid.
  • navigation is excluded. It is declared on both schemas, but ObjectView passes ObjectGrid its own onRowClick, and useNavigationOverlay obeys an onRowClick first. Relayed, the member would be read by nothing.
    • Route 2's row click is owned by ObjectView's navigationConfig, which reads the node's navigation.
    • Making it read the named view would also move the delegation's click path, because the delegation hands ListView the same handleRowClick. That is outside this rung.
  • inlineEdit is excluded. ObjectGrid reads editable, not inlineEdit. ListView translates one into the other under its objectui#4647 grant gate. That is a key translation with a permission contract, a new host path, not the named-view-first rung.
  • fieldOrder, label and data, which are not in bucket ①. The delegation reads all three off a named view, and route 2 reads none of them.
    • fieldOrder is the composition's third key, so route 2 does not apply a named view's order.
    • ObjectGrid reads label for its caption and export filename, while route 2 passes table.title.
    • ObjectGrid reads data for its fetch source; route 2 passes none.
  • Member 4 of objectui#10885. fieldOrder, label, data, navigation and inlineEdit on route 2 are member 4 of objectui#10885, recorded by the seat on the card.
  • Member 2 is not taken. The delegation does not relay a named view's eight view-kind blocks.
    • The rung this PR adds is on route 2. Covering member 2 would add named-view reads inside the objectui#5097 fence.
    • That moves the delegation's behaviour and its pinned named-view read set (objectViewHostSurface.test.tsx section 1b), and this order keeps both untouched.
    • Reach is unchanged: no in-tree host passes both listViews and renderListView.
  • Member 3 is not in this PR. The three census changesets are untouched, and finding(plugin-view): the registered object-view renderer (route 2) ignores a named view's grid members, and the Studio view preview hands it stored views — the objectui#7924 named-view family successor card #10885 remains open for its own prose-only PR. This change moves no census figure: 43 read / 21 unread of 64, with bucket ① empty.
  • Type narrowness, noted. The protocol's named view declares a conditionalFormatting rule's condition as an expression input, which admits the { dialect, source } wire, and a bulkActionDefs visible wire that may carry ast and no source. ObjectGridSchema in @object-ui/types spells neither; the spec's object-grid declares both slots loosely (conditionalFormatting as unknown, bulkActionDefs as an array of unknown), so the gap is against the named view's wire, not against object-grid. The runtime reads both through the shared evaluator. The two rungs assert the declared type. Widening the declared condition type would be a Clause-② type move, so it belongs on the backlog; not filed here.
  • An observation, not filed. The protocol's object-grid also accepts exportOptions as a bare format array, and keeps it an array at parse. ObjectGrid reads only exportOptions.formats. This is a source reading, not a measured render. Carrier: PR objectui#10278, which holds ObjectGrid.tsx.
  • Beyond the claimed file surface: the README and docs paragraphs (the docs-driven rule of AGENTS.md section 5), and the app-shell pin file (the order's ViewPreview pin).

Generated by Claude Code

…amed view (objectui#10885)

The registered object-view renderer passes no renderListView, so an
authored node and the Studio ViewPreview land on the object-grid node
ObjectView builds for ObjectGrid. That node now reads the bucket-1
members the protocol declares on both a named view and object-grid
(pagination, selection, rowHeight, resizable, searchableFields,
conditionalFormatting, rowActions, bulkActions, bulkActionDefs,
exportOptions) off the named view first, then the node only where it
already read the node (table.pagination, table.selection). A named
view's hiddenFields is subtracted from the resolved column projection.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
…view's grid members; changeset (objectui#10885)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
…clared shape (objectui#10885)

A named view's exportOptions may be the protocol's legacy bare format
array, which the protocol lifts to { formats } at parse; the grid reads
exportOptions.formats, so the array is lifted here the way ListView
lifts it for the host delegation. The conditionalFormatting and
bulkActionDefs rungs assert the grid's declared element type: the
protocol's expression wire is wider than it, and ObjectGrid hands both
to the shared evaluator that reads it.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
… sets apart (objectui#10885)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
@github-actions github-actions Bot added documentation Improvements or additions to documentation plugin tests package: app-shell labels Sep 28, 2026
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 6 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/6726-find-envelope-records-arms.md

  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    | module | what it does | | --- | --- | | components/src/hooks/related-count-store.ts | related-list tab badge count | | components/src/renderers/basic/data-list.tsx | element:repeater rows | | components/src/renderers/basic/elements.tsx | element:number client-side aggregate | | components/src/renderers/basic/record-picker.tsx | element:record_picker options | | plugin-detail/src/renderers/record-activity.tsx | record:activity self-fetch | | plugin-detail/src/renderers/record-history.tsx | record:history self-fetch | | plugin-view/src/ObjectView.tsx | non-grid (kanban / calendar / gallery / timeline) fetch |

.changeset/7070-no-invented-gantt-date-fields.md

  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.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/7499-gantt-non-axis-floors-omitted.md

  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.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/8221-retire-legacy-string-sort.md

  • names content/docs/plugins/plugin-view.mdx → content/docs/plugins/plugin-view.mdx — edited by this change

    Docs teach the array only: content/docs/plugins/plugin-map.mdx, content/docs/plugins/plugin-view.mdx and packages/plugin-view/README.md.

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

    Docs teach the array only: content/docs/plugins/plugin-map.mdx, content/docs/plugins/plugin-view.mdx and packages/plugin-view/README.md.

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

  • names packages/plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — 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/object-view-unmirrored-keys-7779.md

  • names packages/plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    What was measured. Every reading was taken on the object-view node renderer (packages/plugin-view/src/ObjectView.tsx, registered by plugin-view/src/index.tsx) with schema.objectName / schema.layout as the positive controls of the same schema.KEY query, so each zero is a reading; the repo-wide census of viewTabBar finds the key in no source file outside @object-ui/types (two doc tables listed it as authorable and are corrected here). The spec side was read through the installed pin (@objectstack/spec@17.2.0, ui entry, 117 exported object schemas walked; control keys objectName / columns / navigation / listViews hit): the three spec-modelled keys are optional slots on ListViewSchema and ObjectListViewSchema; the six local keys have no spec slot anywhere.

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

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

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

Compared the checked-out tree with 29c76e573 (merge-base with origin/main): 5 file(s) changed outside .changeset/, read against 1669 pending declaration(s) that publish a body (2264 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3096.2 KB 3104.5 KB
Main entry chunk (gzip) 148.6 KB 350 KB
Entry file index-BhSmwSPe.js —
Status PASS —

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


📦 Bundle Size Report

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

① Derived judgments

  1. Member parity with the delegation. Measured against @objectstack/spec 17.4.0 (ComponentPropsMap['object-grid'] and ObjectListViewSchema) and head ObjectGrid.tsx.
    • The fence reads 31 members off the named view, and filter / sort are read upstream.
    • Route 2 now reads 16: columns, filter, sort, grouping, rowColor, the 10 new rungs, and hiddenFields applied to the projection.
    • The delegation reads 17 members that route 2 does not:
      • Ten bucket-① chrome members: description, emptyState, filterableFields, sharing, addRecord, userFilters, showRecordCount, allowPrinting, aria, compactToolbar. None is declared on the spec's object-grid, and ObjectGrid reads none of them (0 hits each). The exclusion is right.
      • inlineEdit: not declared on object-grid, which has editable, and 0 grid reads. The exclusion is right for this rung.
      • navigation: declared on both and read by ObjectGrid's useNavigationOverlay. That hook obeys the onRowClick it is handed first (if (onRowClick) { onRowClick(…); return; }), and route 2 always passes handleRowClick. The exclusion is right for this rung.
      • Outside bucket ①: fieldOrder, appearance and userActions are not declared on object-grid. label and data are declared on both, and ObjectGrid reads each: schema.label for the caption and export filename, and getDataConfig, which calls resolveRecordSourceConfig(schema, 'view-data').
    • The dev's Acceptance notes and open question name label and fieldOrder but omit data. data is not read off the named view anywhere outside the fence, on any view type.
  2. Precedence is correct.
    • pagination and selection read the named view, then table.*. The other eight read the named view only.
    • There is no activeView rung, matching this branch's existing grouping / rowColor, and no new node read.
    • THE FIX row pins the named value beating table. The CONTROL row pins the unchanged table fallback, and that the other eight take nothing from table.
    • Keys that are now undefined are harmless. ObjectGrid has no key-presence read of these, and showRowHeightToggle tests !== undefined.
  3. hiddenFields follows the protocol's composition.
    • Spec main view.zod.ts (#15184 ruling B) says hiddenFields "subtracts from that projection", and that an empty columns "declares no projection". ListView's effectiveFields makes the same subtraction, and the fence already relays it.
    • Edge cases:
      • A hidden name the view does not project is a no-op, which is the spec's "subtracts nothing". It is unpinned but trivially true.
      • With no projection, undefined passes through (pinned, green on base as the control).
      • When every projected field is hidden, [] is kept. That is ListView's case 2 (pinned).
      • fieldOrder: route 2 carries none, so the two do not interact.
    • Non-blocking divergence: the helper keeps a column entry with no identity. ListView drops such an entry when hiddenFields is non-empty (fieldName != null && …). The input is off-protocol, but the docblock's "the way ListView makes it" overstates the match.
  4. exportOptions lift is the spec's own.
    • Spec 17.4.0 ListViewShape.exportOptions says: "A bare format array is the legacy spelling and lifts to { formats: [...] } at parse". The pin asserts that parse directly. ListView.resolvedExportOptions makes the same lift.
    • It applies only on the named-view path. Route 2 had no node exportOptions read before and has none now.
  5. The casts cover only a declared-type gap.
    • SpecConditionalFormattingRule.condition is typed string. The spec's rule condition is ExpressionInputSchema. ObjectGrid passes it to resolveConditionalFormatting, whose ruleToPredicate returns a FieldRulePredicate (string | { dialect?, source }).
    • BulkActionDef.visible is string | { dialect?, source }.
    • These are the same values the delegation already hands ObjectGrid through ListView, so nothing new reaches runtime.
    • The dev's second out-of-scope note is imprecise. The spec's object-grid declares conditionalFormatting: z.unknown() and bulkActionDefs: z.array(z.unknown()), so the gap is against the named view's wire, not against object-grid.
    • It deserves a backlog carrier, not "none": a type-only widening of condition to FieldRulePredicate, which is a Clause-② type move. Not blocking.
  6. The fence is byte-identical. Extracted from the #region line through the #endregion line: 186 lines, sha1 40bc22920811a42b0284f478746ff5a5f6b18d10 on both base and head, and diff is empty.
  7. The census has not moved.
    • object-view-unmirrored-keys-7779 derives the whole-file named-view read set by key. Route 2 adds only keys already read inside the fence, so the count stays 43 read / 21 unread of 64, with bucket ① empty.
    • readSites is asserted only for label (2) and name (1), and both are untouched.
    • Neither 7923 nor 7928 has route-2 prose. No row distinguishes routes, and none should change.
  8. Pins are sound, judged by reading.
    • Red on base by construction: 8 rows, namely THE FIX, the lift, 4 hiddenFields rows and the 2 ViewPreview rows. The 7 green on base are 3 static spec-derivation rows, the node control, the no-projection control and 2 ViewPreview controls. That matches the dev's quoted 8 failed | 7 passed (15), then 15 passed.
    • The ViewPreview pin mounts the real ViewPreview, SchemaRenderer, registered object-view and ObjectGrid (not mocked), and reads the DOM.
    • Ablation: leg A plus leg B turn exactly the 8 new rows red out of 797.
    • 695a6ce635..56ad7e8774 is verified to be a 2-line header-comment change.
  9. Docs and changeset contain a false sentence.
    • Changeset paragraph 3 says route 2 "now reads … each member the protocol declares under the same name on both a named view and object-grid, and that ObjectGrid reads: [ten]".
    • The README and mdx paragraphs make the same claim: "The grid members the protocol declares under the same name on a named view and on object-grid — [ten] — come from the active named view first".
    • Both present the ten as the whole set. label, data and navigation meet the same test and are not read off the named view on route 2. The changeset is frozen once released, which is the class of error member 3 of this card exists to fix.
    • Every other sentence checks out against the code: "nothing else" on base, the table fallbacks, "only a declared projection", "delegation unchanged" and Clause-②.
  10. Open question: I recommend A, widened by data. Member 4 would be fieldOrder, label, data, navigation and inlineEdit, dispatched after member 3.
    • Real need. ViewPreview spreads the whole stored body into the named view. The card records that the console persists inlineEdit per view. fieldOrder is the spec's declared third composition step. label feeds the grid caption and export filename, and data feeds the grid's fetch source. I did not measure stored-view usage of data.
    • Long-term fit, measured. navigation is currently inert on both routes. navigationConfig = schema.navigation reads only the node, and its handleRowClick is the onRowClick that both ObjectGrid and ListView's useNavigationOverlay obey first. One named-first read, outside the fence, fixes both routes. The fence stays byte-identical and the census stays unmoved.
    • AI-error resistance. ObjectGrid gates editable itself: inlineEditable = (schema.editable ?? false) && objectInlineEditable. Handing it the named inlineEdit cannot widen editing past a grant, so neither member needs a ruling, only pins. B, ruling them out for route 2, would leave keys that parse and are then dropped, which is the declared-not-enforced trap. The spec gives no per-route lever to rule a member out on one route.
    • Startup focus. It is one PR with no new host path or gate. C is smaller, but it parks two members for a ruling that the source shows is not needed.

② Semver level

patch holds, and so does Clause-②: no.

  • The two new helpers are module-private.
  • No declared type, accepted key or export moves.
  • @object-ui/app-shell gains only a test file.
  • The level is not major.

③ Boundary flags

  • CI at head (final): 43 check runs. 39 succeeded, including all 8 Test shards. 3 were skipped: the coverage matrix jobs and dependabot. 1 failed: Spec Main Shape Gate, whose only annotation is packages/types/src/__tests__/report-chart-query-spec-parity.test.ts line 747, TS1360. That is the objectui#10916 line, so nothing in this PR causes the failure.
  • Merge-tree: each is clean.
    • Against main 733fd5ac65, which is also the PR base (main has not moved): tree 29fd8ca3b1.
    • Against PR objectui#10914 head 2b3d2061a2: tree 0e88458c20.
    • Against PR objectui#10906 head: tree e3fc545ce7.
  • Other open PRs (23 scanned):
    • objectui#10914 touches ObjectView.tsx and ViewPreview.tsx; the merge is clean.
    • objectui#10906 touches ViewPreview.tsx, which this PR does not edit. Its change is i18n text only, and the new pin reads grid DOM, not preview text.
    • objectui#10278 is parked on ObjectGrid.tsx, which this PR does not touch.
  • check-governed-merges: NOT governed (0 of 6 paths). The PR has 516 changed lines, under the 5000-line human-merge threshold.
  • State: draft. Assignee os-elon-musk. mergeable_state is blocked because the PR is a draft.

Implemented-by: claude/issue-10885-object-view-route2-named-grid
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: FAIL

The code, pins, fence, census and semver hold. Only the wording must change before landing.

  1. .changeset/10885-object-view-route2-named-grid.md, paragraph 3. Replace it with:
    "It now also reads, off the active named view first, ten members the protocol declares under the same name on both a named view and object-grid and that ObjectGrid reads: pagination, selection, rowHeight, resizable, searchableFields, conditionalFormatting, rowActions, bulkActions, bulkActionDefs and exportOptions. pagination and selection still fall back to the node's table when the named view omits them; the others have no node fallback on this path, as before. Three other members declared on both, label, data and navigation, are still not read off the named view on this path."
  2. packages/plugin-view/README.md and content/docs/plugins/plugin-view.mdx. Replace "The grid members the protocol declares under the same name on a named view and on object-grid —" with "Ten grid members the protocol declares under the same name on a named view and on object-grid —". After "(objectui#10885).", insert: "label, data and navigation, also declared on both, are not read off the named view on this path."
  3. PR body, Acceptance notes. The seat applies this, since the dev may not patch the body. Change the bullet "fieldOrder and label, which are not in bucket ①" to read "fieldOrder, label and data, which are not in bucket ①", and add: "ObjectGrid reads data for its fetch source; route 2 passes none." Add data to the open question's member list as well.

… declared-on-both set (objectui#10885)

Contract review round 1, wording only. The changeset, README and docs
paragraphs presented the ten members route 2 now reads as the whole set
the protocol declares on both a named view and object-grid; label, data
and navigation meet the same test and are still not read off the named
view on that path, and now say so. The withoutHiddenFields docblock
states the one way its subtraction differs from ListView's: an entry
with no field identity is kept. No behaviour change.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3096.2 KB 3104.5 KB
Main entry chunk (gzip) 148.6 KB 350 KB
Entry file index-BhSmwSPe.js —
Status PASS —

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


📦 Bundle Size Report

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

This is an in-seat delta review of fix round 1 (56ad7e8774 to 097ba79141, one commit), against record 5866387245 (FAIL, wording only).

① Derived judgments

  • Item 1, the changeset's paragraph 3: fixed, verbatim. It now says "ten members" rather than presenting them as the whole set, and names label, data and navigation as also declared on both and still not read off the named view on this path.
  • Item 2, README and mdx: fixed. Each reads "Ten grid members …" and adds the label / data / navigation sentence. The words are the order's, re-wrapped to each file's width.
  • Item 3, the withoutHiddenFields docblock: fixed. It states its one divergence from ListView (an entry with no field identity is kept). The ObjectView.tsx diff has no non-comment line (the seat's grep of + / - lines outside comments exits 1), and the fence still hashes to 40bc2292.
  • The PR body r2 (applied with this record):
    • The Acceptance notes name fieldOrder, label and data, with "ObjectGrid reads data for its fetch source; route 2 passes none".
    • They record member 4 on the card.
    • They correct the type-narrowness note to the named view's wire, per judgment 5, with a backlog carrier.
    • A Fix round 1 section is added. Line 1 is Part of #10885. No path:line reference.
  • Re-runs (the dev's quoted outputs): the two pins, the census reader and the 18 markdown readers give 21 files and 1077 tests passed. Sweep batch A (every reader of plugin-view's ObjectView.tsx) gives 75 files and 1882 tests passed. All the doc and changeset gates exit 0.
  • The open question: the seat rules A, widened by data, as the review recommended. Member 4 of objectui#10885 is fieldOrder, label, data, navigation and inlineEdit on route 2, dispatched after member 3.
    • navigation is inert on both routes today, so one named-first read outside the fence fixes both.
    • ObjectGrid gates editable itself, so relaying inlineEdit needs pins, not a ruling.
    • The seat records member 4 on the card at release.

② Semver level

'@object-ui/plugin-view': patch, Clause-②: no. ⛔ Not major.

③ Boundary flags

  • CI: Spec Main Shape Gate is red on every PR until objectui#10916's fix (PR objectui#10934) lands. The only annotation on this PR was the report-chart-query-spec-parity.test.ts line. The ACCEPT and the landing wait for every check on the landing head to be final and green, with git merge-tree against current main re-run first.
  • Merge: clean against 733fd5ac65 and against PR objectui#10914's head.
  • NOT GOVERNED.
  • Draft, assigned to os-elon-musk.

Implemented-by: claude/issue-10885-object-view-route2-named-grid
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: PASS

…0885-object-view-route2-named-grid

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3096.2 KB 3104.5 KB
Main entry chunk (gzip) 148.6 KB 350 KB
Entry file index-BhSmwSPe.js —
Status PASS —

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


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.70KB 2.23KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 557.59KB 133.60KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 226.44KB 63.00KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.96KB 14.83KB
plugin-charts (index.js) 83.99KB 22.86KB
plugin-chatbot (index.js) 197.67KB 46.90KB
plugin-dashboard (index.js) 136.93KB 36.48KB
plugin-designer (index.js) 215.03KB 44.21KB
plugin-detail (index.js) 233.48KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.00KB 9.09KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.15KB 22.35KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.27KB 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
objectstack-fleet Bot marked this pull request as ready for review September 28, 2026 09:06
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit b73e15b Sep 28, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10885-object-view-route2-named-grid branch September 28, 2026 09:46
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Oct 7, 2026
…e` read the named view expression slots by reference (objectui#10946) (objectstack-ai#10977)

Fixes objectstack-ai#10946

Clause-②: yes — widens two published types to the spec's
expression-input wire (triage execution note 3).

## What changed

`SpecConditionalFormattingRule.condition` and `BulkActionDef.visible` in
`@object-ui/types` now read the named view's own expression slots BY
REFERENCE, from the authoring (`z.input`) face of
`ObjectListViewSchema`. That is the derivation
`ObjectViewSchema.listViews` already uses (objectui#7928). There is no
hand-written copy of the spec wire.

| Member | Before | After |
|---|---|---|
| `SpecConditionalFormattingRule.condition` | `string` | `string`, or
the slot type of
`ObjectListViewSchema.conditionalFormatting[].condition` |
| `BulkActionDef.visible` | `string \| { dialect?: string; source:
string }`, spelled inline | `ExpressionWire` (the same union, now by
name), or the slot type of
`ObjectListViewSchema.bulkActionDefs[].visible` |

- **Zod mirror.** The mirror moves with the type. Two mirrors carried
`condition: z.string()`: the list view's rule union and
`KanbanConditionalFormattingRuleSchema`. Both now read one
module-private `SpecRuleConditionSchema`. Its first arm is `z.string()`,
so a string condition parses exactly as before: it is not canonicalized
into an envelope, and `''` is still accepted. The spec slot alone would
do both of those things to a string. Its second arm is the spec's own
slot schema, taken by reference; a pin asserts reference identity. The
`zod-mirror-parity` ledger rows name keys, not value types, and no key
moved, so the ledger is untouched. `BulkActionDef` has no standalone zod
mirror. The list view's `bulkActionDefs` is already the spec's schema by
reference.
- **Relays.** `ObjectView` route 2 drops the two assertions PR objectstack-ai#10937
added: `conditionalFormatting … as
ObjectGridSchema['conditionalFormatting']` and `bulkActionDefs … as
ObjectGridSchema['bulkActionDefs']`. Both relays now type-check as
written.
- **No runtime behaviour change.** No evaluator, renderer or relay
changed. A type assertion compiles to nothing.
- **Changeset.** `@object-ui/types: minor`. It is breaking for
TypeScript readers of these members, and the changeset says so.

## Assertions the PM listed that stay, and why (measured)

- **`plugin-list` `ListView`: kept.** The four casts are
`schema.conditionalFormatting as unknown[] | undefined` and the three
`(schema as any).bulkActionDefs` reads. With all four removed,
`plugin-list` `tsc --noEmit` exits 0 even against BASE-shaped types
(ablation leg A[4] below). Their targets are `readonly unknown[]`
parameters or an untyped node literal, so this gap never forced them.
They are outside this card and untouched (see Acceptance notes).
- **`plugin-grid` `resolveBulkActions`: kept.** `action.visible as
BulkActionDef['visible']` stays because `action` is `NamedActionDef`, an
`unknown` pass-through bag. Removing the cast is red WITH the widened
types (leg C: TS2322, `visible?: {}`), so it exists for a different
reason.

## The two spec lines differ on these slots

| | `condition` / `visible` slot | `ast`-only envelope |
|---|---|---|
| installed `@objectstack/spec` 17.4.0 (the pin) |
`ExpressionInputSchema`, where `source` is optional | admitted |
| spec `main` at `dbddf02c` (what the Spec Main Shape Gate compiles
against) | `EvaluatedExpressionInputSchema`, where a non-blank `source`
is required | refused |

- Because the members index the slot rather than naming
`ExpressionInput`, they follow whichever line is installed. They narrow
with the next spec bump, with no local edit.
- **Local spec-main probe, not the CI gate.** I compiled the pin file
plus the ObjectView-shaped relays against spec `main` SOURCE, with
`@objectstack/spec` mapped to `git archive origin/main
packages/spec/src`. The installed 17.4.0 was absent from the program.
Result: 0 errors in objectui files or pins. Of the 8 errors, 5 are
`React` namespace errors from the probe's empty `types` and 3 are in
spec source (missing `pg-connection-string` and node types). A
`@ts-expect-error` on an `ast`-only value was consumed, which confirms
spec `main` refuses that value on the slot.
- **Runtime answer for the `ast`-only envelope the installed line
admits.** It is an evaluation fault. The formatting rule does not match,
the bulk def qualifies no record, and the fault is warned. Both paths
are pinned.

## Verification at `6f5bfdcb0`

- **type-check.** `turbo run type-check --continue`, locally, over
`types`, `core`, `plugin-grid`, `plugin-view`, `plugin-list`,
`plugin-kanban`, `app-shell` and `plugin-report`. All 8 scripts ran, 0
`error TS`, VERDICT command-exit 0.
- **vitest.** The whole `packages/types/` suite plus the 37 other test
files that name `conditionalFormatting`, `bulkActionDefs`,
`BulkActionDef` or the rule types: `Test Files 306 passed (306)`, `Tests
6765 passed (6765)`.
- **New pins.** `spec-expression-wire-slots-10946.test.ts` (types, 14
tests) and `specExpressionWire-10946.test.tsx` (plugin-grid, 5 tests)
are green. Their type halves are compiled by each package's
`tsconfig.test.json`.
- **Gates.** Each of these exits 0: `check-control-bytes`,
`check-new-cross-file-line-citations` (0 new),
`check-spec-symbol-derivation`, `check-changeset-presence`,
`check-changeset-fixed`, `check-changeset-no-major`,
`check-changeset-claims`, `check-changeset-overwrite`,
`check-pending-changeset-literals`, `check-type-check-coverage`,
`check-test-path-roots`, `check-vi-mock-override-shape`,
`check-phantom-dependencies`, `check-package-self-import`,
`check-unreferenced-sources`, `check-node-esm-load --specifiers-only`.
`check-governed-queue-guard --test`: NOT GOVERNED.
- **Lint, narrowed and declared.** I ran `eslint --no-inline-config
--format json` over the 5 changed TS files. It reported 5 files, 0
errors and 95 warnings, all on untouched lines (none in the added lines
or the two new files). The population is the root `eslint.config.js`
`**/*.{ts,tsx}` block, which includes all 5 files. That config enables
no type-aware linting (no `parserOptions.project` or `projectService`),
and no rule in `eslint-rules/` reads the filesystem. So this diff cannot
move a verdict on an untouched file. The repo-wide `pnpm lint` belongs
to CI.

## Reverse verification (ablations; each leg mutated with
`ablation-replace.mjs`, anchor hit proven on disk, `@object-ui/types`
rebuilt, dist marker counted)

**Leg A** reverts all three derivations to the BASE shapes: the rule
alias to `{ condition: string }`, the bulk alias to `{ visible?: never
}`, and `SpecRuleConditionSchema` to `z.string()`. It also removes the
four `ListView` casts.

1. `plugin-view` `tsc --noEmit`: exit 2. TS2322 on the route-2 grid
schema: `conditionalFormatting`, then `condition`, is not assignable to
`string`. TS names only the first incompatible member.
2. `types` `tsc -p tsconfig.test.json`: exit 2, with 7 errors, all in
the new pin: the five relays, the envelope rule, and the `ast` excess
property.
3. `plugin-grid` `tsc -p tsconfig.test.json`: exit 2, with 2 errors in
the new grid pin.
4. `plugin-list` `tsc --noEmit` with the `ListView` casts removed: exit
0. This is the control showing those casts are not this gap's.
5. vitest on the types pin: 7 failed and 7 passed. The failures are
envelope acceptance on both mirrors, the envelope-refusal cases on both
mirrors (their valid-envelope control fails), the reference identity on
both mirrors, and the reference control. That control throws on a
`z.string()` that has no `.options`. The string and empty-string
controls stay green.

**Leg B** reverts only the `visible` arm. `plugin-view` `tsc --noEmit`
exits 2: `bulkActionDefs` is incompatible, then `visible`, then
`source`.

**Leg C** keeps the widened types and removes the `resolveBulkActions`
cast. `plugin-grid` `tsc --noEmit` exits 2 (TS2322).

**Restore.** Every leg was restored with `git checkout HEAD -- PATH`,
and each restore was checked: blob equal to the HEAD blob, and `git diff
HEAD` empty. `@object-ui/types` was rebuilt, all 3 mutation markers
counted 0 in dist, and `git status --porcelain` came back empty.

The plugin-grid runtime cases characterize pre-existing behaviour, so
they stay green under a type-only ablation by construction. Their type
half is leg A[3].

## Declared surface extension

`packages/plugin-grid/src/__tests__/specExpressionWire-10946.test.tsx`
is a new file outside the claim's file surface. The card's "evaluates"
pin needs the real grid, and `@object-ui/types` has no evaluator to
import. It is a new file only; no existing file outside the claim was
edited.

## Not measured locally (CI owns)

- The Spec Main Shape Gate. It is covered only by the source probe
above.
- Full `pnpm test` (8 shards).
- Full `pnpm lint`.
- `pnpm type-check` for the packages not listed above.

## Acceptance notes

- **`ListView` casts (polish, not filed; carrier: none).** The four
casts are redundant, as leg A[4] measures, but for a reason outside this
card. They were left untouched.
- **`@object-ui/core` `FieldRulePredicate` (observation, not filed).**
It declares `source` as required, which is narrower than the installed
slot. Every call site that hands it these members already casts, and it
converges with spec `main`'s narrowing.
- **Model-named trailer on `17393ae3c`.** That commit carries a
model-named `Co-Authored-By` trailer. The dispatch contract asks for
model-free trailers. History was not rewritten, because the branch is
never force-pushed. `6f5bfdcb0` is model-free.

---

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

---------

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

Labels

documentation Improvements or additions to documentation package: app-shell plugin tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants