Repository navigation
fix(plugin-list,plugin-grid): a grouped list view under a toolbar search groups on the server, with the searched counts (objectui#11021) - #11243
Conversation
…rch groups on the server, with the searched counts ListView no longer takes a grouped grid's fetch back while a toolbar search is active: the header query takes the term since @objectstack/spec 17.5.0, so the grid that groups on the server is handed the term as its `search` prop and the view's searchable fields on its node, and puts them on both of its queries. ObjectGrid reads a host's `search` whenever one is passed, and drops its held group row query when it leaves server grouping, so turning grouping back on never asks, or paints, the query it held before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
…et, and correct the prose this change made false plugin-grid declares @objectstack/spec ^17.5.0, the release whose group header query takes a search (the lockfile specifier moves; the resolved version does not). The plugin-list and plugin-grid READMEs, the plugin-grid docs page, a useGroupedData comment, three plugin-list test comments and the grid half's pending changeset said ListView keeps grouping its own window under a toolbar search; they now say what the code does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
Brings in objectui#9547 (ObjectGrid onNavigate prop), which touches ObjectGrid.tsx in regions disjoint from this branch's hunks. Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
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
Size Limits
|
Contract reviewServed-tier: Inputs: card objectui#11021 (body and all 11 comments), PR objectui#11243 (body, 17-file list, net diff against ① Derived judgments(a) One channel, both queries — RIGHT. The widening is correct and bounded. (b) Re-entry reset — RIGHT, both stale ask and stale paint. (c) Every rewritten or removed comment states what the code does — RIGHT. (d) Test triage — RIGHT. The replaced 10881 case pinned Check-runs on the head (the gate verdicts): 44 runs; 39 ② Semver levelChangeset ③ Boundary flagsEvery dev deviation in report
Implemented-by: VERDICT: PASS |
…d displayField PR #11243 has landed, so the three column-building comments in ObjectGrid are in scope; they named reference_to and display_field, neither of which the copy set carries any more. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
…ational-target spelling objectui writes or reads; reference_to retires (objectui#11070, round 4) (objectstack-ai#11264) Refs objectstack-ai#11070 Clause-②: yes (narrowing). `LookupFieldMetadata`, `MasterDetailFieldMetadata`, and `DetailViewField` retire `reference_to` and declare `reference`, and the ingestion pass no longer stamps `reference_to` onto served defs, under the startup no-gradualism rule. It is priced in the changeset. Round 4 of objectui#11070, the `reference_to` round: the seat's answer A to Q1 (`5915992755`), under the maintainer ruling on objectui#6837 (`5475017957`, 2026-08-31, verbatim: 「objectui不是前端的项目吗?后端的元数据只要对,前端按协议执行就行了呀」, with the earlier question 「按 spec 拒绝面直接删不是更合理吗」). Claim `5916640555`. `reference` is now the only spelling ObjectUI writes or reads for a relational field's target object. The one fold that remains is the ruling's choke point: `normalizeFieldReferenceKeys` folds a foreign `reference_to` / `referenceTo` onto `reference` when `reference` is absent, keeps its dev warning, and never drops a key. ## What changed - **Types (`@object-ui/types`).** `LookupFieldMetadata` and `MasterDetailFieldMetadata` declare `reference` typed by reference to `@objectstack/spec`'s `FieldSchema.reference`. `DetailViewField` and its zod mirror `DetailViewFieldSchema` move from `reference_to` to `reference` in the same commit, so the two faces keep equal key sets. The `form.ts` comments and the form-field mirror's comment now say that the lookup and user widgets read `reference` only. `strict-face-read-keys-11070.test.ts` moves `reference_to` from the pending list to the retired list, and gains a type-level pin: both field metadata types carry the spec member, and none of the three contracts has a `reference_to` key. - **Ingestion (`@object-ui/core`, `reference-keys.ts`).** The pass folds onto `reference` and no longer stamps `reference_to`. The header prose that described a stamp of "BOTH snake_case keys" now describes the fold, and it records why the stamp protected nothing once both ends moved. The leave-arm rule stands. - **Readers read `reference` only:** `LookupField`, `UserField`, `LookupCellRenderer` and `UserCellRenderer` (only those two reads in `fields/src/index.tsx`), `InlineFieldInput`'s reference fallback, `schemaDefaults`' `current_user` seed, `sectionFields`' view override, and `MetadataProvider`'s inline-subform parent. - **Emitters write `reference`:** `paramToField`, `RecordDetailView`, `FlowReferenceField` (its one target line), `RecordDetailPanel`, `RecordMetaFooter`, `RelatedList`, `fieldEnrichment`, `buildDefaultPageSchema`, `sectionFields`, `bulkParamToField` and `ObjectGallery`. - **Copy sets and ledgers.** `plugin-grid`'s `RELATIONAL_META_READ_SET` loses its `reference_to` row and the `adapter-stamped` verdict that row alone held. `plugin-dashboard`'s `CELL_RELATIONAL_META_KEYS` and `FieldMeta` drop `reference_to`. `resolveActionParams`' unread `RuntimeField.reference_to` member goes. `FieldDefaultsSchemaLike` pins three members. - **Docs and fixtures.** `lookup.mdx` (typed fences, plaintext fences, prose, plus one paragraph on the retirement), `record-edit-modes.md`, `plugin-form.mdx`'s field-slot row and `plugin-form`'s README. The tests that fed `reference_to` to a widget, a cell or a served-def stub now feed `reference`. The pins whose job is the fold, or a refusal, keep `reference_to` as their input and assert the fold to `reference` with no stamp back, or the refusal. - **One changeset**, `.changeset/11070-reference-to-round4.md`, minor with the break stated (AGENTS.md §9: never `major`). Fifteen pending changesets that this round made false get an appended dated note, in the append-only shape: `6837-reference-to-arm-deletion`, `6837-gantt-tree-referenceto-arms`, `6837-recorddrawer-invented-target-arms`, `6694-dashboard-lookup-reference-meta`, `6597-retire-fieldmeta-referenceto`, `7166-retire-inert-fieldmeta-copies`, `paramtofield-reference-rule-derives-from-core-5312`, `6711-retire-reference-to-field`, `6874-retire-titleformat`, `7155-converge-lookup-dialect-camelcase`, `6528-resolve-reference-to-census`, `7324-plugin-form-nameable-parameter-types`, `11070-field-metadata-spec-spellings`, `10535-person-name-read-gate` and `6875-grid-relational-meta-derive`. ### Pins that flipped, and why These pins asserted the stamp. Each now asserts that no stamp happens, and that the fold still does: - `reference-keys.test.ts`: a `reference` def gains no `reference_to`; `referenceTo` folds to `reference` only; idempotence; the map and array containers. - `reference-keys.legacyWarning-6837.test.ts`, case 5: "the STAMP is unchanged" becomes "the FOLD still runs". The `referenceTo` case asserts no `reference_to`; the `reference_to` case keeps the input key, because the pass never drops one. - `MetadataProvider.itemReferenceKeys-7650.test.tsx`: the first pin asserted the stamp and now asserts its absence. The rest feed a legacy spelling, because a `reference`-only def comes back unchanged and cannot show that the pass ran. - `getObjectSchema.test.ts` (data-objectstack). - The emit-side pins that read `reference_to` off an emitted bag: `referenceArms-6837.divergent.test.ts` (plugin-detail), `RecordDetailDrawer.referenceArms-6837.test.tsx`, `HeaderHighlight.editable.test.tsx`, `relationalMetaCopySet-6711` / `-6874`, `lookupRelationalMeta-6694`, `sectionFields*`, `paramToField.test.ts`, `resolveActionParams.test.ts`, `bulkParamToField.test.ts`. - New refusal pins: the lookup cell, the user cell and `LookupField` each read no target from a `reference_to`-only def. Pins that assert something else were not "fixed green". Three copy-set floors, which required more than two keys in `RELATIONAL_META_KEYS`, now require more than one, because the set is now `reference` and `displayField`, and each floor now also names `reference`. ### Beyond the claim's file surface, stated - `ObjectDataTable.tsx` gains `ObjectDataTableRetiredReferenceToSnakeTombstone`, and both ObjectDataTable test files gain a directive and a counter-control for it. Retiring `FieldMeta.reference_to` removed the key from the derived refusal bands' pool, and `recordFields.tsx`'s own `FieldMeta` docblock requires that a retired member be re-refused by hand at that seam. This is the third tombstone, beside `decimals` and `referenceTo`. - Comment-only corrections to statements this round made false: `auditHistoryDisplay.ts`, `deriveRelatedLists.ts`, `useDatasetFields.ts`, `object-fields-io.ts`, `components/custom/field.tsx`, core `ActionRunner.ts` / `chart-series.ts` / `expand-fields.ts`, `data-objectstack/src/index.ts`, `RecordPickerDialog.tsx`, `lookupColumnDisplay.tsx`, `HeaderHighlight.tsx` and `ObjectGantt.tsx`, plus the stamp prose in the gantt / tree / drawer 6837 pins. - The named tail is folded. PR objectstack-ai#11243 landed, so the three `ObjectGrid.tsx` relational-metadata comments now name `reference` and `displayField` (seat message, 18:53Z). `ListView.tsx`'s two lines were left as they are, because both are true after this round: one says `FieldSchema` refuses `reference_to`, the other that a list column declares neither spelling. PR objectstack-ai#11233 landed, so the `form.zod.ts` comment, the `FormPage.tsx` comment, the `plugin-form.mdx` row and the `FormPage.sharedFieldResolver-10179` pin were folded as well (seat message, 19:54Z; the comment only in `form.zod.ts`, with no new declaration). `FormPage.sharedWidgets-10179`'s lookup fixture moved first, because that test went red on the change. ## Census, before and after Base: merge base `615346d` for the round's own diff. Code lines are non-comment lines in `packages/*/src`, `apps/console/src` and `examples/*/src`, excluding tests. The typed half comes from a TypeScript LanguageService `findReferences` over 5568 source files, with workspace packages resolved to source. | kind | before | after | | --- | --: | --: | | emitter sites writing `reference_to` onto a def or widget `field` | 11 | 0 | | ingestion stamp of `reference_to` | 1 | 0 | | copy sets carrying `reference_to` (grid ledger row, dashboard cell keys) | 2 | 0 | | reader lines reading `reference_to` (widgets, cells, inline editor, seeding, section override, subform parent) | 10 | 0 | | the ingestion fold's read of the legacy key (the ruling's choke point) | 1 | 1 | | declared `reference_to` members (field-types ×2, views, views.zod, RuntimeField, FieldMeta, schemaDefaults ×2) | 8 | 0 | | `reference_to?: never` refusal (tombstone) | 0 | 1 | | typed references to a `reference_to` member: production writes / test writes | 2 / 7 | no member left to reference | The eleven emitters are the PM census's eleven. The type-checker census found two of them typed (`FlowReferenceField`, `RelatedList`); the other nine write through `any` or `Record` bags. It found no typed reader: every reader was an untyped read. ## Runtime probe — the user-visible proof A scratch vitest file, never committed, ran against the source at merge base `615346d` and at head (`1972d01`, re-run at `338b19d` with identical readings). `ObjectForm` in create mode opens its lookup picker; `ObjectGrid` renders a lookup column with a primitive id; the referenced record is `{ id: 'a1', name: 'Acme Corp' }`. | case | base | head | | --- | --- | --- | | (a) served def with `reference` only, through `ObjectStackAdapter` | picker queries `probe_account`; cell shows `Acme Corp`; served keys `label, reference, reference_to, type` | picker queries `probe_account`; cell shows `Acme Corp`; served keys `label, reference, type` | | (a) the same def from a BYO `DataSource` | works | works | | (b) action param `referenceTo` through `paramToField` into `LookupField` | field carries `reference_to`; picker queries `probe_account` | field carries `reference`; picker queries `probe_account` | | (c1) `reference_to`-only def served through `ObjectStackAdapter` | folded (`reference` added); dev warning fires; picker and cell work | the same: folded, warned, picker and cell work | | (c2) `reference_to`-only def from a BYO `DataSource` | picker queries `probe_account`; cell shows `Acme Corp` | **no `find` call at all; the cell shows the raw id `a1`** | (c2) is the break, and the changeset's BREAKING paragraph names that host. ## Hypotheses - **H1 holds.** Read at objectstack `origin/main` `165c1d49e`. The example apps write `reference_to` zero times, against a control of 30 `Field.lookup` / `Field.masterDetail` calls in 19 files; both helpers write `reference`. `FieldSchema` refuses `reference_to` by name (installed 17.5.0: `unrecognized_keys`, "Did you mean `reference_to` → `reference`?"), and so does the spec's form-field schema. The `field-reference-to-alias` conversion (`packages/spec/src/conversions/registry.ts`) rewrites stored rows on rehydration and in `os migrate meta`. The only other hits are refusals (the SQL and Mongo doors, verify, lint), a reader of three spellings in `plugin-security`, and a comment in `plugin-approvals` that describes this repo's widget key (noted below). - **H2 holds.** Every production write is one of the eleven emitters, the ingestion stamp, or one of the two copy sets the brief listed as readers. No twelfth writer turned up, typed or untyped. - **H3 holds.** On the ObjectStack path the cells receive folded defs, as probe cases (a) and (c1) show. `RELATIONAL_META_KEYS` is derived to `reference, displayField`, and the grid's derivation gate re-extracts the cell's read set with `reference` in it. - **H4:** **false as posed.** The `reference_to` pair was not in M3's class (ii) at this base. Round 1 (PR objectstack-ai#11115) moved both `fields-lookup` fixtures to `reference`, and round 3 reported class (ii) without it. Measured with `scripts/measure-strict-authoring-face.mjs --json` at merge base `af9e957` and at `338b19d`: every refusal figure is identical (2224 nodes, 105 strict-refused, 66 strict-only, 39 red today, 599 documents, 98 refused whole-tree), and `reference_to` occurs in zero refusals at both. The only differences are the renderer-source word-mention counts, which the comment edits moved, and the error text of one authored module that fails to load under either build state. So this round moves M3 by zero in every class. The absolute class (ii) figure at this base is NOT MEASURED: round 3's shipped-face port of PR objectstack-ai#11069's `findUndeclaredKeys` was a scratch script and was never committed. ## Checks Heavy runs went through `os-verify-lock` (slot `issue-11070`). Exit codes were captured before any pipe. - **Build closure** (`check-doc-snippet-types --build-filter`, turbo `--concurrency=2`): `35 successful, 35 total`, before and after the first merge. - **type-check** of 21 packages, the ones this diff touches plus the console and the schema catalog (the type-checker census found no other typed reader): `Tasks: 56 successful, 56 total`, before and after the first merge. After the second merge, `@object-ui/types` was rebuilt and type-checked again, exit 0. - **Tests, full affected set** (the 21 packages' paths, 3536 files), before the first merge: `4 failed | 3527 passed | 5 skipped (3536)`. The four were pins that asserted the old shape: three copy-set floors of more than two keys, and the console shared-widget lookup fixture. They were fixed in `c684de4` and re-run: `Test Files 4 passed (4)`, `Tests 30 passed (30)`. - **Tests after the first merge** (`338b19d`), narrowed to the files both sides touched plus this round's relational surface (types, fields tests and widgets, the Flow inspectors, console components, plugin-grid, plugin-detail and plugin-dashboard tests, plugin-form, core reference-keys, the adapter, and app-shell providers and utils): `Test Files 1137 passed | 3 skipped (1140)`, `Tests 16884 passed | 31 skipped (16915)`. After the second merge (`16b43a7`, no file overlap): `packages/types/` `295 passed (295)`, `7375 passed (7375)`, including `zod-mirror-parity.test.ts`, whose totals did not move. - **Doc gates** at `338b19d`: `check:doc-snippets` `696 of 696 block(s) judged, 0 failed`; `check:doc-examples`, `check:doc-types`, `check:spec-symbols`, `check:doc-example-readers` and `check:doc-example-ids` all exit 0. - **At `16b43a7`**, all exit 0: `check:doc-fences`, `docs:check-links`, `check:control-bytes`, `check:pending-changeset-literals`, `check-changeset-presence` (`174 source file(s) of 20 released package(s) changed, and this change declares 1 changeset(s)`), `changeset:check` (no major), `check:new-line-citations` (`0 new citation(s)`), `check:test-path-roots`, `check:changeset-claims` (report-only; every named changeset was read), and `check-governed-queue-guard --test` over the 194 paths (`NOT GOVERNED`). - **Lint, a measured narrowing.** The population is `eslint.config.js`'s `**/*.{ts,tsx}` files entry; there are no `parserOptions.project` or `projectService`, so type-aware linting is off and this diff cannot move an untouched file's verdict. The 174 changed `.ts` / `.tsx` files were linted at `16b43a7` and at merge base `54a7830`: 0 errors at both, 1909 warnings at both, and no file is worse than base. - **Ablations**, each run on a committed, clean tree through objectstack's `ablation-replace.mjs`. In every case the anchor hit once, the blob moved, the blob was restored equal to HEAD, and `git diff HEAD` was empty afterwards. - A1: `lookup.mdx`'s fence writes `reference_to`. `check:doc-snippets` exited 1 with `696 of 696 block(s) judged, 1 failed`, TS2561 "'reference_to' does not exist in type 'LookupFieldMetadata'. Did you mean to write 'reference'?", which proves the gate read the rebuilt `.d.ts`. - A2: the fold stamps `reference_to` again. 6 red / 83 green, against 5 predicted: the three core stamp pins, the adapter pin and the provider pin, plus the empty-target pin, because an empty `reference` also gained a stamp. - A3: `LookupCellRenderer` reads `reference || reference_to` again. 2 red / 14 green, as predicted: the new cell refusal pin, and the grid derivation gate's unclassified-spelling check. - **Type-checker census** at `338b19d`: the seven contracts carry no `reference_to` member. The control run of the same instrument on `reference` finds 7 declarations, the same two typed production writes that moved, 1 production read, 3 test reads and 10 test writes. - **Diff size:** 194 files, +1022 / −647 against merge base `54a7830`. That is under the 5000-line human-merge threshold: 62 non-test files (16 of them changesets) and 132 test files. NOT MEASURED: - The repository-wide lint and the test shards outside the sets above. CI runs those. - Tests after the second merge outside `packages/types/`. Its three incoming commits share no file with this branch, and none contains `reference_to`. - A browser dogfood against a live objectstack app. The probe used `ObjectForm` / `ObjectGrid` with a stub or adapter-wrapped `DataSource`. - The absolute M3 class (ii) figure (see H4). - CI convergence. It was not waited on, per the dispatch contract. ## Acceptance notes - `docs/adr/0059-action-params-shared-field-widgets.md`'s decision section still records `referenceTo` → `reference_to` as `paramToField`'s mapping. It was left as written: it is the accepted decision's record (2026-07-19), and the ruling kept the historical record. Editing `docs/adr/**` would also make this PR governed. The seat may want a dated amendment line in a docs-only PR. - `ROADMAP.md`'s two hits are completed items and changelog history, not current behaviour, so they were not changed. - `.changeset/audit-field-def-reference-narrow.md` says the choke point "stamps both snake_case spellings". It has empty front matter, so nothing publishes it, and no note was appended. - objectstack `plugin-approvals`' `sys-approval-request.object.ts` has a comment saying the console resolves a lookup config as `reference_to: sys_user`. That spelling is now `reference`. It is a comment in the sister repo, not a producer; noted, not filed. --- _Generated by [Claude Code](https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #11021
Clause-②: no
The ListView half of objectui#11021. The grid half (PR objectui#11178, merged as
7e4fa1bb2) made a server-grouped grid send its search term on the group header query and on every group's row query. This PR makes the console's grouped list view use it. With this, all four of the card's acceptance lines hold through the list view, so the PR closes the card.What changes
packages/plugin-list/src/ListView.tsx:gridOwnsGroupedFetchloses its!searchTermcarve-out and its comment. That comment gave "$searchhas no counterpart on the header query" as the reason, which is false against the installed@objectstack/specplus PR objectui#11178. Under a toolbar search, a grouped grid over a data source that answersqueryGroupHeadersis still handed no rows. It gets the list's term as itssearchhost prop (an empty one too: the list owns the term), and the view'ssearchableFieldson its node, beside the effectivefilterit already carried.ListView's own fetch sends that same pair as$search/$searchFields.packages/plugin-grid/src/ObjectGrid.tsx, only in the three regions the claim names:hostOwnsSearch/querySearchTerm: a host that passessearchowns the term, under host-driven paging (unchanged) and also when the grid fetches for itself. The load effect's$searchreads that term, sogroupSearchOf(groupRowQuery)carries it to both group queries. With nosearchprop, the term is the grid's own box, as before.groupRowQuerygoes back tonullwhen the grid leaves server grouping. Before, re-entering grouping asked the first header query with the query held from the last grouped phase, and painted that answer before the fresh one (see the measurements).manualSearchOncomment is rewritten to say what the code does, and so is themanualSearchcomment.ObjectGridExternalPaginationPropsgains one paragraph:searchis read outside host-driven paging too.main, and the merge was clean).packages/plugin-grid/package.json: the@objectstack/specfloor goes^17.4.0to^17.5.0on both lines.pnpm installrewrote one lockfile specifier line, and the resolved version did not move (it was already17.5.0).ListViewkeeps grouping its own window under a search. Those arepackages/plugin-list/README.md,packages/plugin-grid/README.md,content/docs/plugins/plugin-grid.mdx, and auseGroupedData.tscomment. The grid half's still-pending changeset.changeset/11021-grouped-grid-search-both-queries.mdended on the same sentence, and that paragraph is removed; this is a prose correction to a not-yet-released declaration, and its package names are untouched. Three plugin-list test comments carried the same claim and are corrected too..changeset/11021-listview-grouped-search.md, with@object-ui/plugin-listand@object-ui/plugin-gridat patch.Measurements of the dispatch's mechanism assumptions (all at
origin/main3c13675e5f)ListView+ realObjectGrid, with no source edits. The new pinpackages/app-shell/src/__tests__/listViewGroupedSearch-11021.test.tsxuses 186 rows in five units (86/61/31/7/1) and the term#1. The term matches 34 rows, and the view's page is 20. On base, the searched grouped list drew{ Northgate Operations: 11, Northgate Plant: 9 }: the page of 20 grouped in the browser. The query's answer is{ 11, 11, 11, 1 }. The result wasTests 3 failed | 2 passed (5).ListViewfed the grid no search at all before, since its flat grid is handed a window that is already searched. The grid's existing host propsearchnow carries the term. The measured widening beyond "server-grouped mode" is deliberate. UndergridOwnsGroupedFetch, the grid can still fetch a flat or bucketed window of its own, when the grouping key is unreadable or known-masked. Readingsearchonly when server-grouped would drop the term there, which is a regression, so a passedsearchis read wherever the grid fetches for itself. Searchable fields ride the node's declaredsearchableFields, the key the grid's own$searchFieldsalready reads. No new prop was added. The box stays hidden: a host that owns the term but passes noonSearchChangegets none.search: '#1'andsearchFields: ['subject']. A second ablation leg (below) switched the query-level check off and left only the paint check. Without the reset, both pins then went red on a painted searched header set,{ 11, 11, 11, 1 }, before the unsearched one. With the reset, no re-entry header query carries the term and no searched set paints, while at least one set was sampled.manualSearchOncomment: rewritten.manualSearchOnitself does not change. A grouped grid renders no flat table, and each group's table issearchable: false, so this flag governs only the flat table.17.5.0.pnpm install --frozen-lockfileanswered "Lockfile is up to date".Tests
packages/app-shell/src/__tests__/listViewGroupedSearch-11021.test.tsxmounts the realListViewand the real registeredobject-grid. It has five cases:search/searchFields;plugin-gridserverGroupedSearch-11021.test.tsx: the clearing case now asserts no stale ask and no stale paint on re-entry. It used to tolerate both, in a comment. A new case covers a host'ssearchprop driving both queries and clearing them.plugin-list:ListView.groupedGridOwnsFetch-7189.test.tsxgains the searched handoff (no rows;searchandsearchableFieldsequal to the list's own$search/$searchFields; the filter unchanged) and an ungrouped control (a searched window, no term handed). InListView.groupingNeedsHeaderQuery-10881.test.tsx, the case that pinned "a grouped grid handed a searched window" pinned the very branch this PR deletes. It is replaced by the same question asked of the new behaviour: no window and no host paging.Ablation, one-shot, from committed
620c07cd76, through objectstack'sscripts/ablation-replace.mjs. Every mutation was proven on disk (anchor x1 to x0, replacement x0 to x1, blob moved). Every restore was proven by the blob equal to HEAD and an emptygit diff HEAD, and no permanent test file was left. The pins resolve@object-ui/plugin-gridand@object-ui/plugin-listthrough the vitest alias tosrc, so nodist/is in the path.Tests 2 failed | 7 passed (9). The grid clearing case and the list re-entry case went red on a re-entry header query carryingsearch: "#1".Tests 2 failed | 7 skipped (9), both onexpect(counts).not.toEqual(SEARCHED).&& !searchTermrestored:Tests 5 failed | 10 passed (15). SEARCHED, clearing and re-entry through the list failed, and so did the 7189 searched handoff and the 10881 replacement.searchread only under host paging:Tests 4 failed | 5 passed (9). The grid host-search case failed, and so did the three searched list cases.Gates
Branch head
cee5c02158:620c07cd76merged withmainatdded788ada, which brought in objectui#9547. Every exit was captured before any pipe. Heavy runs went through the shared verify lock.At
cee5c02158:pnpm install --frozen-lockfile: exit 0, "Lockfile is up to date".pnpm turbo run build --filter='@object-ui/app-shell^...' --concurrency=2: exit 0, 28/28 tasks. This closure contains both@object-ui/plugin-list^...and@object-ui/plugin-grid^....pnpm --filter @object-ui/plugin-grid type-check && … plugin-list … && … app-shell …: exit 0. Each run echoedtsc --noEmit && tsc -p tsconfig.test.json.pnpm exec vitest run packages/plugin-grid/: exit 0,Test Files 174 passed (174),Tests 1596 passed (1596).Tests 148 passed (148). That is the new app-shell pin, the six changed plugin-list files,displayPageSizeFromSpec-9853, four plugin-viewObjectViewsuites, two app-shellObjectViewsuites anddata-objectstackqueryGroupHeaders-7189.scripts/markdown-test-inputs.mjs --listnames as readers of the five changed markdown files (doc-version-claims.test.tsamong them): exit 0,Tests 841 passed (841).check-changeset-presence("10 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)");check-changeset-no-major,check-changeset-fixed;check-changeset-claimsandcheck-changeset-overwrite(both report-only);check:pending-changeset-literals,check:installed-pin-claims,check:control-bytes;check:new-line-citations("0 new citation(s)");check:doc-fences,check-doc-links("Links are valid across 17 scan roots"),check-doc-expression-carriage,check:doc-types,check-doc-example-ids;check-lockfile-integrity("VERDICT clean"),check-lockfile-dedupe("VERDICT deduped"),check:phantom-deps;check:test-path-roots,check-vi-mock-specifiers,check:unreferenced-sources,check-type-check-coverage,check-lint-coverage,check:spec-symbols;markdown-test-inputs --audit;check-governed-queue-guard --testover the changed paths ("An ordinary pull request").check:spec-floorsexited 1 on 5no-artifactfindings, forapp-shell,cli,plugin-gantt,plugin-timelineandplugin-tree: packages outside this diff that this worktree did not build. That is a prerequisite refusal, not a verdict.plugin-grid, whose floor moved, was built and judged, with no finding.check:readme-exportsexited 1 on 88 "./dist/index.d.tsis not on disk" refusals, none of them for the two READMEs changed here. This diff changes 0 fence lines in any doc.At
620c07cd76(the same diff before the merge):pnpm exec vitest run packages/plugin-list/, in two shards: exit 0 both times, 55 + 54 files, 387 + 814 tests. The merge changed noplugin-listfile.pnpm exec vitest run scripts/__tests__/, in two shards: exit 0 both times, 177 files passed and 2 skipped of 179, 5371 tests passed and 2 skipped.tsc -p tsconfig.test.json --listFilescounts: the new app-shell pin appears once, the grid pin once, and the five changed plugin-list suites once each.react-hooks/set-state-in-effectinObjectGrid.tsx, from the reset effect. The config is not type-aware, so no untouched file's verdict can move.CI is not waited on; its verdict is the merge queue's.
Deviations from the declared file surface (each forced by what the change made false, or by the pin the dispatch asks for)
ListView-plus-real-ObjectGridpin lives inpackages/app-shell/src/__tests__/, notpackages/plugin-list/src/__tests__/.plugin-listdeclares noplugin-gridedge, so a pin there would need either avitest.config.mtsheavyDomTestsentry (a root config that dozens ofscripts/__tests__suites read) or an undeclared test import (check:phantom-deps).app-shellalready declares both packages, the routedisplayPageSizeFromSpec-9853.test.tsxtakes.useGroupedData.tscomment, the pending grid-half changeset and the three test comments listed above.Acceptance notes
ObjectGrid.tsxgains onereact-hooks/set-state-in-effectwarning, from the reset effect. The file carries that pattern already (itssetSearchTerm('')reset on an object change), and eslint reports 0 errors. Every other changed file's per-rule warning set is identical to base.7470afd89band620c07cd76end with aCo-Authored-Bytrailer that carries a model name, copied from the harness's attribution reminder. The model-free pair is what AGENTS.md asks for, and the merge commit carries it. History is not rewritten: objectui forbids force-push.Session:
https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZGenerated by Claude Code