Repository navigation
test(plugin-grid,console): pin the members of object-grid's four toolbar keys (objectui#8071 slice 13) - #9836
Conversation
…bar keys objectui#8071 slice 13. `batchActions`, `pagination`, `searchableFields` and `selection` leave `MEMBER_PIN_EXEMPTIONS` and enter `MEMBER_PINS`, and `MEMBER_PIN_EXEMPTION_CEILING` follows to the new count in this same commit. The four were chosen by where the READS cluster, not by the card's enumerated list: all four are resolved in the single fold that assembles the `data-table` props, and each is the canonical half of a canonical-vs-deprecated pair whose precedence nothing asserted. Also repairs five figures in `registry-inputs-spec-parity.test.ts` that had rotted into present-tense claims about shared, ratcheting constants. They are rewritten as rules or as dated readings; today's numbers are deliberately not written in. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L
|
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
|
|
| added | removed | |
|---|---|---|
probe page:header |
0 | 0 |
probe page:header.actions |
0 | 0 |
control object-grid |
17 | 4 |
control MEMBER_PIN_EXEMPTION_CEILING |
4 | 3 |
Leg 3 — does it add an of or touch a registration?
| added | removed | |
|---|---|---|
probe of: ' |
0 | 0 |
probe ComponentInput |
0 | 0 |
probe registerComponent |
0 | 0 |
probe name: ' (an input declaration row) |
0 | 0 |
probe sdui.manifest |
0 | 0 |
probe member-type-mismatch |
0 | 0 |
control searchableFields |
18 | 1 |
control pins: |
4 | 0 |
control AWAITING_A_PIN |
0 | 4 |
That last control is lit on the removed side precisely because it is the four deleted exemptions. Every file this diff touches is a test file or the changeset; there is no registration source in it at all.
Leg 4 — shared file, not shared claim. That body describes the arm / of direction. This slice moves the member-pin direction. They meet in one file and nowhere else.
The gate's silence is not a clearance, so the sweep was widened
The gate judges name resolution, never meaning, and cannot see a claim spelled as a symbol or a package rather than a backticked filename. So all 1682 pending bodies were swept whitespace-normalised for every path and every symbol this diff touches.
Probe not line-blind, demonstrated on the flagged body's own wrapped phrase: parity gate in followed by the ledger path reads 0 line-anchored, 1 normalised.
Path hits: the ledger path in 4 bodies (8067-…, 8068-mandatory-per-block-member-pin, fix-parity-aria-line-ref, parity-gate-lazy-registrations); the three plugin-grid test paths in 0. Symbol hits: MEMBER_PIN_EXEMPTION_CEILING in 9, MEMBER_PIN_EXEMPTIONS in 6, MEMBER_PINS in 2, AWAITING_A_PIN in 2; ObjectGrid in 106, which is inert here because this diff restored ObjectGrid.tsx to its HEAD blob byte for byte after every ablation leg and ships no change to it.
Every ceiling claim among those is a BOUNDED TRANSITION — 62 -> 58, 46 -> 41, 41 -> 37, 37 → 33, 33 to 31, 31 -> 28, 24 -> 20, and 16 to 15 on a different backlog ceiling — each a statement about what its own change did, which no later slice can falsify. 20 -> 16 is simply the next one.
The single absolute reading was already dated, by the commit this branch is based on. 8171-calendar-sort-input.md reads "it read 62 at the commit that wrote this paragraph (35e63669d6, 2026-09-07), and that reading is dated on purpose" — objectui#9823's repair. A dated reading cannot rot, so it is untouched.
⇒ Nothing went false; nothing is ROTTED and nothing was BORN FALSE. No changeset body is edited by this PR.
Generated by Claude Code
Refs #8071 — slice 13. At least seven exemptions remain after this one, so the card stays open; this PR is deliberately written with no closing keyword anywhere in it.
Clause-②: no
What this slice does
Four
object-gridkeys leaveMEMBER_PIN_EXEMPTIONSand enterMEMBER_PINS, andMEMBER_PIN_EXEMPTION_CEILINGmoves to the new count in the same commit:batchActions,pagination,searchableFields,selection.It also repairs five figures in
registry-inputs-spec-parity.test.tsthat had rotted into present-tense claims about shared, ratcheting constants.The batch, and why it is this one
The dispatch deliberately did not name a batch. It handed over slice 12's reading and asked for one chosen by where the reads cluster. The constant was re-taken by this seat from the declaration itself, on
origin/main26ac50369, before the first edit — not from the card's prose list, which its own dated block says is stale in both directions.object-gridheld eleven. Four of the eleven are the ones slice 12 already read and ruled one-slice-each (columnspulls in the column fold and the$selectprojection;groupingpulls inuseGroupedData;filterandsorteach carry dedicated files that need reading end to end). That leaves seven, and four of those seven are one read:ObjectGrid.tsxresolves all four inside the single fold that assembles thedata-tableprops, and each is the canonical half of a canonical-vs-deprecated pair nothing had asserted the precedence of:paginationschema.pagination !== undefined, then.pageSize/.pageSizeOptionsshowPagination, flatpageSizesearchableFields!== undefined ? length is positive : showSearchshowSearchselectionschema.selection?.typeselectablebatchActionsschema.batchActions ?? schema.bulkActionsselection's last fallback arm)batchActionsis in the batch because its result is whathasBulkActionsreads, andhasBulkActionsis the third arm of the very chainselectionis pinned on. The four meet at one gate. Three files, two of them promotions after growth.The three keys left behind on this block after this slice —
aggregations,dataSource,navigation— plus the four slice 12 ruled, are the seven that remain.The finding the clustering surfaced
Two adjacent object-armed keys on one block read their own presence in opposite ways, and neither description says so.
paginationis read as!== undefined, so the object's presence alone enables paging and overrulesshowPagination: false.selectionis read as?.type, so the object's presence alone does nothing at all. That asymmetry is now pinned from both sides with its controls.Consequences an author suffers, named
selection— a grid declaringbulkActions: ['approve']andselection: { type: 'none' }renders with no checkbox in it.noneis an explicit off that beats both fallback arms, including the auto-enable the bulk-action declaration would otherwise trigger. The bar the author declared can never be populated; nothing is thrown, nothing is logged, and the schema reads as configured.pagination—pageSizeOptionsREPLACES the built-in rows-per-page list rather than extending it. An author who addspageSizeOptions: [200]to offer one larger step silently deletes 5 / 10 / 20 / 50 / 100 from the selector. The control still renders and still works; it simply no longer offers what it offered yesterday.searchableFields— an empty array is not "narrow nothing", it is search off: the toolbar box disappears. An author who empties the list while re-picking fields loses the control, not the narrowing.batchActions— a schema half-migrated tobulkActionsthat leavesbatchActions: []behind loses every bulk action. The checkboxes still tick and the selection bar still counts; only the buttons are missing.Every pin shown FAILING, with the restore proven
Five ablations. Each mutates the read site toward the plausible improvement, proves the mutation reached disk (anchor and injected text each counted before and after — a zero-hit edit tool exits 0 and would otherwise read as a run), runs the three pin files, then restores from
HEADunder a trap and proves the restore by blob hash plus an emptygit diff HEAD. Target blob atHEAD:552dc5a51f97698a655f7771b7b9507658dba7ca; every leg restored to exactly that.pageSizeoverpagination.pageSizepagination.pageSizeWINS over the deprecated flatpageSizepageSizeOptionspass-through, always use the built-in listpageSizeOptionsREPLACES the built-in rows-per-page listtype: 'none'as no opinion, fall through to the legacy/auto armsnoneis an explicit OFF that beats the bulk-action auto-enable;nonealso beats the deprecatedselectable: truesearchableFieldsfall through toshowSearchsearchableFieldsturns the search box OFFbulkActionswhen the legacy array is EMPTYbatchActionsstill wins — a declared[]is a VALUE, not an absenceOne reading was refused by its own ablation, and the prose was corrected rather than the ablation retried until it agreed. The
batchActionspin first said the empty array survives because the coalesce is nullish. Swapping??for||left all 28 tests green: an empty array is both non-nullish AND truthy, so the two operators are indistinguishable here. The docblock inbulkActionsSpecKey.test.tsxand thepinsprose in the ledger now say that explicitly, and the recorded mutation is the one that actually can fail it — an explicit length test, which is the repair a reader would really reach for.Set identity and the ceiling, in the same commit
Read out of the diff, not asserted:
MEMBER_PIN_EXEMPTIONS:object-grid.batchActions,object-grid.pagination,object-grid.searchableFields,object-grid.selectionMEMBER_PINS: the same four, nothing else, in either directionMEMBER_PIN_EXEMPTION_CEILING:20to16on one line of the same commit, and the live declaration below it holds exactly 16 entriesBoth readings were taken at
26ac50369, which is this branch's base andorigin/mainat push time — no merge intervened, so no count here spans one.The prose repair — as a rule or a dated reading, never today's number
Five figures repaired. Each had become a present-tense claim about a constant that ratchets under every later slice, which is the defect objectui#9781 names and repairs; writing today's value in would author it a third time this shift.
MEMBER_PIN_EXEMPTION_CEILINGreads 62"MEMBER_PIN_EXEMPTION_CEILINGstays 62"A sixth in the same class was repaired opportunistically while the file was open:
AWAITING_A_PIN's docblock opened "One shared constant rather than 58 near-copies", which reads as a live count of the list. It now says "rather than one near-copy per entry"; the measured population size stays in the string below it, where it is attributed to the card that measured it.Files
packages/plugin-grid/src/__tests__/gridPagerSelectionMembers-8071.test.tsx—paginationandselection. Neither had a file constraining its members at the grid.groupedPagination.test.tsxnames the block and the key and would satisfy a string locator, but its subject is GROUP paging and its onepaginationfixture exists to suppress a pager;data-table-selection-mode.test.tsxpins the vocabulary one layer down and never namesobject-grid, so this repo's own locator would have refused it. Neither was credited.serverSearch.test.tsx—searchableFields. Its ADR-0061 row really does pin the key's forwarding, a genuine near miss, but with a single-member array and no arity row. Grown by ordering (a deliberately non-alphabetical pair), the empty-array arm, and the precedence overshowSearch: false.bulkActionsSpecKey.test.tsx—batchActions. Its whole subject IS the alias precedence, but both fixtures are non-empty, so the empty-array arm was unstated. Grown by that row and by the auto-enable row.apps/console/src/__tests__/registry-inputs-spec-parity.test.ts— the four registrations, the four deletions, the ceiling, the slice-13 accounting section, the prose repairs..changeset/8071-grid-toolbar-member-pins-slice-13.md— empty frontmatter.A member with no read site, reported rather than frozen into the pin
The GROUPED pager ignores both
paginationmembers.ObjectGrid's own grouped pager hard-codes its rows-per-page choices and reads neitherpagination.pageSizenorpagination.pageSizeOptions, so an authoredpageSizeOptionsreaches the flat pager and is dropped the momentgroupingis authored. The pin asserts the flat path and says in its own prose that it does. Slice 9's choice, for slice 9's reason: an assertion that a member is dead has to be deleted before anyone can make it live. Handed back as a finding; no card filed from this seat.Changeset grade, MEASURED
Empty frontmatter, and measured rather than assumed. Both affected packages were built and their
files[]entries grepped for symbols this diff introduces, each with a lit control drawn from the same probed population:@object-ui/plugin-griddist,README.md,CHANGELOG.md,LICENSEgridPagerSelectionMembers0 · "the coalesce is nullish" 0 · "an EMPTY member list disables search" 0pageSizeOptions9 ·resolveRowCrudAffordances9 ·searchableFields16 ·batchActions4@object-ui/consoledist,plugin.ts,plugin.js,plugin.d.ts,README.mdMEMBER_PIN_EXEMPTION_CEILING0 ·MEMBER_PINS0 ·gridPagerSelectionMembers0object-grid21 ·searchableFields26 ·pageSizeOptions10Every probe zero, every control lit in the same files. Nothing this diff adds reaches published output.
node scripts/check-changeset-presence.mjsagrees and prints so.Verification
Exit codes captured to disk before any pipe, in every case.
packages/plugin-grid/(whole package)tsc -p packages/plugin-grid/tsconfig.test.jsonapps/consoletsc --noEmitcheck:control-bytescheck:changeset-presencecheck:pending-changeset-literalscheck:changeset-claimscheck:new-line-citationscheck:test-path-rootscheck:vi-mock-specifierscheck:sdui-registration-pinscheck:governed-queue-guard --test(the five changed paths)Typecheck coverage proven non-vacuous.
tsc -p packages/plugin-grid/tsconfig.test.json --listFileslists 1729 files; all three grid pin files appear exactly once each. The listing discriminates rather than swallowing everything:plugin-detailtest files 0, the console ledger file 0. The console's owntsc --noEmit --listFileslists 3765 files including the ledger file exactly once, withgridPagerSelectionMembers0 and anypackages/*/__tests__/0.Lint: a narrowing, declared, with the three readings that make it a measurement. ① The population is read from eslint's own config, not guessed:
files: ['**/*.{ts,tsx}']minus that config'signoresblock (dist,.next,node_modules,public,.source, plus its three literal build artefacts) — 4926 tracked files. ② Files actually linted, counted out of--format json: 4, the whole diff's lintable surface. 0 errors, 16 warnings, every one of them@typescript-eslint/no-explicit-anyon theas anyfixture casts these files already used; the lines this diff ADDS contribute 4 such occurrences, 3 of them the standardhasPointerCapture/scrollIntoView/schema: anyfixture spelling. ③ Invariance for the 4922 untouched files:eslint.config.jsdeclaresprojectService0 times,project:0 times andtsconfigRootDir0 times — linting is not type-aware here, so each file's verdict is computed from that file alone and nothing in this diff can move a verdict on a file it does not contain. The repo-widepnpm lintrun is CI's.Serial constraint
Re-taken over the open-PR set before the first write, not inherited: all 16 open pull requests were listed and each one's file list fetched. Zero of the 16 touch
registry-inputs-spec-parity.test.ts.object-form.sectionsentry'spins:prose insideMEMBER_PINS. Re-read at push time: it has not landed —origin/mainis still26ac50369, byte-identical to this branch's base on that file. So this pushes unmerged, as instructed, and the enqueue-time conflict is the dispatching seat's to take.For whoever merges the two: this diff does not touch the
object-form.sectionsentry. Its insertions intoMEMBER_PINSareobject-grid.batchActions(before theobject-grid.exportOptionsentry) and theobject-grid.pagination/searchableFields/selectiontrio (before theobject-kanban.cardFieldsentry).object-form.sectionssits a couple of entries above the first of those, so the two edits are near but not on the same lines. ⛔ Do not revert objectui#9833's line while merging — it is a deliberate repair of a sentence describing the old behaviour.Out of scope, noted and not filed
paginationmembers, above. Successor: this card's nextobject-gridslice, which has to read the grouping path forgroupingandaggregationsanyway.ObjectGrid'spageSizeresolution uses||, so a member of0falls through to the flat key and then to the built-in default. Not a defect anyone can reach (a page size of zero is not authorable in any useful sense) and not pinned. Successor: none.Generated by Claude Code