Uh oh!
There was an error while loading. Please reload this page.
fix(types): DataTableSchema.rowActions mirrors the declared boolean (#6940) - #7447
Conversation
…#6940) The hand-written zod mirror declared `rowActions: z.array(z.any()).optional()` while every other face of the key says boolean — the TS declaration it mirrors, the renderer's destructuring default, its truthiness gates and colSpan arithmetic, the registered `type: 'boolean'` authoring input, `defaultProps`, and the renderer's own docblock example. The mirror was the outlier and the published one, so `safeValidateSchema` refused the spelling the component's documentation, defaults and authoring UI all teach, and two shipped schema-catalog entries failed validation for that and no other reason. Maintainer ruling 2026-09-02 (director seat, summon #8), option A. Option B (a `boolean | array` union) was not taken: it would permanently accept a shape the renderer only truthiness-tests. Pinned in data-table-declared-keys-6882.test.ts: `true` and `false` validate, `[]` is REFUSED and refused ON `rowActions` (every issue path asserted, so a document rejected for an unrelated reason cannot read as a passing narrowing), the published `safeValidateSchema` surface moves in both directions, and the two catalog entries validate unchanged. The list view's same-named `rowActions` (`ObjectGridSchema`, `z.array(z.string())`) is a different key, is in parity with its own TS twin, and is pinned here as separate rather than touched. The #5684 mirror-parity ratchet was NOT blind to this drift: it had measured and ledgered it as `KnownDrift['data-display.zod.ts#DataTableSchema']`, noting "one of the two is dead; which is a ruling". That ledger fails on a repair exactly as it fails on new drift, so correcting the entry to its measured four remaining keys is part of this change, not a widening of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
os-project-manager
commented
Sep 3, 2026
|
| regions touched | |
|---|---|
| this PR | ~L57 (a count comment), ~L732-754 (the DataTableSchemaKnownDrift entry) |
| #7432 | ~L131, ~L147, ~L354, ~L521, ~L1483 — all blocks.zod.ts imports, MIRRORS/Declared entries and one EXCLUSIONS row |
Disjoint. A textual merge should apply cleanly in either order.
The one residue is prose, not a gate: this PR's header line reads "37 entries … 52 keys", and #7432 removes nine blocks.zod.ts mirrors, so whichever lands second leaves that count stale. Measured that this cannot redden CI — the ledger's entry/key counts are documentation, with no Object.keys(KnownDrift).length assertion anywhere (control: the file contains 13 expect( calls, so the search instrument fires). Only the MIRRORS population is derived and checked, and #7432 removes from both halves so they still agree.
⇒ No action needed from either PR. Recorded so that a stale count found later reads as known prose rot rather than a missed conflict — the class objectui#7433 tracks.
Full review follows once the dev's structured report is in, including the ruling's rider (why #5684's mirror-parity ratchet did not catch a boolean declaration against an array mirror).
Generated by Claude Code
✅ 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
|
os-project-manager
commented
Sep 3, 2026
Contract review — VERDICT: PASSImplemented-by: objectui execution seat ( ① Derived judgments. Executes the #6940 ruling (2026-09-02, 「7189 A 其他同意」, option A): ② Semver / changeset. ③ Boundary flags. No governed path. Same-line collision with #7468 on the Landing. Carrier cleared, ready, auto-merge (SQUASH). All checks green on Generated by Claude Code |
…counting The merge queue dequeued PR #7447 after #7344 (PR #7468) landed. Both changes touch the same ledger; the conflict is in two places and neither side was correct on its own. 1. The KnownDrift docblock region. main added a real new entry from #7344 ('crud.zod.ts#DetailSchema': 'onBack') in the same lines where this branch rewrote the rowActions prose. BOTH are kept: main's entry with its own docblock, then this branch's rewritten rowActions paragraph documenting DataTableSchema, whose union is now the measured four keys. 2. The header census — un-enforced prose, so re-derived BY COUNTING the merged interface rather than by taking a side: KnownDrift 39 entries / 55 keys (main's 39/56 less the repaired rowActions; entry count unmoved) UnmirroredDeclared 17 entries / 98 keys (untouched by this change) RuntimeOnlyDeclared 7 entries / 24 keys 160 - 39 = 121 pairs with no KnownDrift entry The "no entry in either" figure was also re-derived: |U u R| = 18, so 160 - 18 = 142, which is what the file already said — checked rather than assumed, because the same figure was silently stale in the sibling merge. Verified: pnpm --filter @object-ui/types run type-check exit 0, 0 'error TS' (script name echoed in the log, so not a zero-match filter); pnpm exec vitest run packages/types/ -> Test Files 94 passed, Tests 1601 passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
os-project-manager
commented
Sep 3, 2026
Merge conflict resolved — |
| ledger | entries | keys |
|---|---|---|
KnownDrift | 39 | 55 |
UnmirroredDeclared | 17 | 98 |
RuntimeOnlyDeclared | 7 | 24 |
39 / 55 is main's 39 / 56 less the one key this PR repaired — the entry count correctly does not move, which is what this PR's own body predicted. 160 − 39 = 121 was already right.
⭐ The "no entry in either" figure was checked rather than assumed: |U ∪ R| = 18, so 160 − 18 = 142, which is what the file already said. Worth stating because in the sibling merge (#7464) that same figure had gone stale and git flagged nothing — it merged cleanly since only one side touched it. Here it was genuinely still correct.
Verified before pushing
pnpm --filter @object-ui/types run type-check→ exit 0, 0error TS, with> @object-ui/types@17.6.0 type-checkechoed in the log (not the zero-match filter trap).pnpm exec vitest run packages/types/→ Test Files 94 passed, Tests 1601 passed.
⛔ Not re-enqueued and auto-merge untouched — the landing is the director seat's. Nothing in the contract review changed; only the merge with main.
Generated by Claude Code
✅ 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
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#6940
DataTableSchema.rowActionsinpackages/types/src/zod/data-display.zod.tsbecomesz.boolean().optional(). Maintainer ruling 2026-09-02 (director seat, summon #8,verbatim 「7189 A 其他同意」), option A. Option B (a
boolean | arrayunion) wasnot taken: it would permanently accept a shape the renderer only truthiness-tests.
The mirror was the single outlier and the published one, so
safeValidateSchemarefusedthe exact spelling the component's TS declaration, destructuring default, truthiness
gates,
colSpanarithmetic, registeredtype: 'boolean'authoring input,defaultPropsand docblock example all teach.
rowActions— confirmed distinguishedOnly the data-table one moved. The list view's key is untouched, and
git diffproves it.zod/data-display.zod.tsDataTableSchemazod/objectql.zod.tsObjectGridSchemaz.array(z.any())toz.boolean()z.array(z.string()), unchangeddata-display.ts—rowActions?: booleanobjectql.ts—rowActions?: string[]KnownDriftThe separation is now pinned, so a later sweep that "harmonises the two
rowActions" onthe strength of a shared name turns red here instead of silently retyping a key no ruling
covers.
git diff --name-only -- packages/types/src/zod/objectql.zod.tsreturns empty.The rider — the ratchet was NOT blind, and this is the measurement
#5684's mirror-parity ratchet did catch this drift. It measured it and recorded it in
its
KnownDriftledger:with an inline note that named the exact question this card later answered — TS declares
rowActions?: boolean, the mirror declaredany[], "One of the two is dead; which is aruling." The ratchet's header records the same entry surviving #5927's sweep
("
DataTableSchemakeptrowActions").So there is no structural gap, and there is nothing to file. The ratchet's design is
to convert a drift it cannot adjudicate into a ledgered, citable question rather than a
silent pass. It did exactly that; the question sat in the ledger until the maintainer
answered it on 2026-09-02.
The brief listed
packages/types/src/__tests__/zod-mirror-parity.test.tsas held by openPR #7432. This PR edits it anyway, and the reason is mechanical rather than
discretionary — flagging it explicitly for the reviewer.
That ledger is bidirectional by design: "the entry fails when new drift appears on that
mirror AND when the recorded drift is fixed — a stale entry cannot rot quietly."
Repairing
rowActionstherefore turned the package's own gate red:Correcting the entry to its measured remaining four keys is the toll the ratchet charges
for every drift repair — it is not "fixing the ratchet" and not a widening of scope.
Without it
pnpm --filter @object-ui/types run type-checkcannot pass and the PR isunreviewable.
Collision with #7432 measured, not assumed: zero. Fetched
pull/7432/headanddiffed. Every one of its hunks in this file is in the
blocks.zod.tsregion (lines~132–148 imports, ~355
MIRRORS, ~522Declared, ~1484EXCLUSIONS), removing the nineblock pairs. This PR's edits are the
KnownDriftentry near line 747, its docblock, andthe header key census near line 60 — disjoint regions, no textual conflict either way.
Changes are three: drop
'rowActions'from the union, rewrite the docblock paragraphthat would otherwise be a false statement sitting next to the change, and move the header
census from 53 keys to 52.
Tests
Pinned in
packages/types/src/__tests__/data-table-declared-keys-6882.test.ts(the homethe ruling named), 7 new cases:
rowActions: truevalidates.rowActions: falsevalidates — it is a boolean, not a truthy-only flag.rowActions: []is REFUSED — and every issue path is asserted to berowActions, so a document rejected for an unrelated reason cannot read as a passingnarrowing pin. This is the load-bearing half: a union would have satisfied a
"
truevalidates" assertion on its own.safeValidateSchemamoves in both directions. Measured at this levelrather than inferred, because it is a
z.unionand a sibling member accepting thedocument would have left the published surface unchanged.
rowActions: trueand always did.rowActionsstill takesstring[]and rejectstrue.Red-then-green ablation
Reverted only the mirror fix, with the pin left in place.
d1d427dbtode3a6332, plus anchoredgrep counts (boolean spelling 1 to 0, array spelling 0 to 1).
de3a6332is exactly thepre-fix blob on
origin/main.[]refusal and thesafeValidateSchemacase.the two same-named keys really are independent.
git checkout HEAD -- ...(absolutepath, pinned to
HEADrather than the polluted index), then blob equality against theHEADblob and an emptygit diff HEAD. Green leg re-run: 8/8.trap ... EXIT INT TERMwith absolute paths throughout.'../zod/data-display.zod.js',a relative same-package specifier vitest resolves to TypeScript source, so no
dist/copy can serve a stale mutation.
Gates, all on the final commit
f17e08244pnpm --filter @object-ui/types run type-checkpnpm exec vitest run packages/types/pnpm exec vitest run packages/plugin-grid/ packages/plugin-view/ examples/schema-catalog/pnpm --filter @object-ui/types run lintnode scripts/check-control-bytes.mjsnode scripts/check-changeset-presence.mjsobjectui checkon the catalogobjectui checkwas run with the real built CLI, and the builtdistwas confirmedto carry the change (
rowActions: z.ZodOptionalofZodBoolean) rather than a stalecopy.
user-table.jsonandfull-featured-table.jsonno longer appear in its failingbucket; the five entries that remain there are the
components-basic-textones held by aseparate in-flight PR.
Consumer sweep — the narrowing has no casualties
Grepped the repo for
rowActionsauthored as an array. Every hit outside this PR's owntests is the list-view/ObjectGrid key:
p1-spec-alignment.test.ts(type: 'list-view'),objectViewHostSurface.test.tsx, theplugin-gridlegacy bare-name suite andresolveLegacyRowActions,plugin-grid/README.md,schema-reference.mdandplugin-grid.mdx. Zero documents author an arrayrowActionson a data-table, whichmeasures the ruling's stated basis for a patch bump rather than assuming it.
Changeset
@object-ui/types, patch. The body states the reasoning the ruling requires: noauthor can have relied on an array value, because the renderer never reads the array — it
only truthiness-tests the key, so even
[]rendered identically totrue(#6318 measured42 elements either way, against 39 with the key absent). An array here could never have
carried meaning to any consumer, so the narrowing removes a spelling that was accepted but
inert.
Review status
Clause ② yes. Draft, carries
needs:contract-review, not enqueued, notauto-merged, not self-reviewed. Waits on the project director seat.
🤖 Generated with Claude Code
https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
Generated by Claude Code