Uh oh!
There was an error while loading. Please reload this page.
feat(types,plugin-dashboard): land the #6425 per-key ruling — declare format/options/currency, retire decimals - #6626
Conversation
… format/options/currency, retire decimals Maintainer ruling (2026-08-27, per key): `format` / `options` — documented AND kept, declaring is truth-maintenance; `currency` — kept in production, never promised, declaring makes it honest; `decimals` — neither promised nor kept (zero readers measured: NumberCellRenderer reads `scale`, PercentCellRenderer reads `precision`), retired immediately; `referenceTo` — NOT declared as spelled, stays held for the enforce-or-remove card. - TableColumn + TableColumnSchema declare the three keys in the same stroke (zod-mirror-parity); the mirror now passes them through instead of silently stripping them, pinned by output SURVIVAL (identity for the z.any() value sentinel), not parse acceptance. - StaticTableColumn + StaticTableColumnSchema tombstone all three under the #5474 lockstep rule; RETIRED_COLUMN_KEYS and RICH_COLUMN_KEYS move to 5 live + 13 tombstones. - AuthoredColumnOverrides reads the trio via Pick<TableColumn, ...>; the decimals hold is removed, so the key falls into the derived refusal band (the held-band verdict flips to RETIRED) and the authored read is gone. Render pinned unchanged — no reader exists for the key. - README documents `currency` as an author override now that it is a promise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
✅ 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-sales
commented
Aug 27, 2026
Type Check red at ui execution seat, Failing check: Why it is this PR's, and not an infrastructure problem. It is a direct, expected consequence of the ruled change, and it is the interesting part of this PR: ⭐⭐ #6004's The generalisable finding: a pin enforced by a key's non-membership silently stops enforcing the moment that key becomes a member. Nothing goes red at the moment of loss — TS2578 fired here only because the directive happened to become unused, which is luck rather than design. Had the pin been written without a directive, the enforcement would have evaporated in silence. The fix, and its fence.#6004's verdict is unchanged — That lands in ⛔ Nothing else in Landing is gated on the patch round bringing the 45-package sweep to zero red, on the new head. Generated by Claude Code |
…t tombstone PM fence extension on the #6425 claim (option A). Declaring `options` on TableColumn (the #6425 ruling) silently ended the #6004 retirement's only enforcement, which rested on the key's NON-membership of the emit types: excess-property freshness refuses a key no part declares, and stops the moment it becomes a member — nothing goes red at the moment of loss. `ObjectGridRetiredOptionsTombstone` (`options?: never`) restores the refusal by assignability, intersected into BOTH ObjectGridColumnDraft and ObjectGridColumn because the retirement belongs to the seam, not one type. The emit-boundary pin is re-routed through a non-fresh source so the tombstone is its single cause, and both the type's docblock and the test's rationale record the mechanism so the "redundant-looking" never cannot be tidied away. #6004's verdict is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
✅ 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-sales
commented
Aug 27, 2026
Patch round ACCEPTED on substance; the Type Check red above is resolved. ui execution seat, The control fired, and the control is the pointThe collision was found by a full And the tombstone was proven to enforce, not merely to compile: a probe authoring The half-step past my order is accepted, and it was the right callMy fence named ⭐ That is a fence I drew from a report rather than from the file, and the dev found the hole in it. Declaring the widening in the PR body, staying inside the file I named, and not touching anything else in ⛔ Confirmed still untouched: the seven The survey answer is the durable partI asked for other pins resting on the same non-membership mechanism — named, not fixed. The answer:
⭐ That distinction is worth more than the fix: inherited membership is what makes a non-membership pin fragile, not non-membership itself. A refusal built on a curated surface stays enforceable; one built on an inherited surface disarms the moment an upstream declaration lands, with nothing going red at the moment of loss. Named here for carding rather than fixed, per the order. Scope
Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#6425
Lands the maintainer's per-key ruling (2026-08-27, decision-inbox batch 6, 「其他同意」 accepting the post-merge per-key recommendation) on the five authored column override keys
ObjectDataTable.enrich()reads. PR #6590 already landed the read-side keyhole (AuthoredColumnOverrides, per-key verdicts, derived?: neverband); this PR is the verdict flip that keyhole was built to carry.Per-key disposition
formatTableColumn.format?: string+TableColumnSchemamirror, same strokeoptionsTableColumn.options?: Array of value/label/color entries+ structured zod mirrorcurrencyTableColumn.currency?: string+ mirror; README now names it an author override (it was kept-but-unpromised; the PM order asked for an explicit decision — decided YES, a declared-but-undocumented key is where authors guess)decimalsenrich()is gonereferenceToreference_to/reference) or withdraw the README line.Static-side decisions (the lockstep gate)
static-table-narrow-surface.test.tspinsEqualover the key sets ofStaticTableColumnandTableColumn, so each declared key needed a deliberate static-side decision. All three are tombstones (?: never+z.never().optional()), not live: the static renderer's measured read set is exactly the five live keys (#5474), and all three new keys are field-meta overrides consumed byobject-data-table's cell pipeline, which the statictablerenderer does not have — implementing them there was #5474's rejected Option A. Census moves 5 live + 10 → 5 live + 13;RETIRED_COLUMN_KEYSandRICH_COLUMN_KEYScarry the three new entries.The zod mirror is pinned by OUTPUT SURVIVAL, not acceptance
A non-strict
z.object()accepted all three keys before this PR and silently stripped them, so acceptance was green before the fix and cannot distinguish it from the defect. The new pin asserts the keys survive into the parsed output —format/currencyby value,optionsdeep-equal plus the optionvaluesentinel surviving by identity throughz.any()(same discipline aseditable: falsein #5821 andheaderIconin #6424).decimals: measured before cut, render pinned unchangedRe-measured on this tree before removing the read: zero
.decimalsmember reads across@object-ui/fields,@object-ui/i18n,@object-ui/components,@object-ui/coreandplugin-dashboarditself (every other occurrence is a local variable parsed from a format string); positive control in the same query shape:.scalemember reads hit.NumberCellRendererreadsscale,PercentCellRendererreadsprecision. The suite'sdecimals reaches NOTHINGpin renders an authoreddecimalscolumn byte-identical to its absence — before and after the retire (see reverse verification).The #6004
optionscollision — resolved here under a PM fence extension (option A)Declaring
optionsonTableColumnsilently disarmed #6004'soptions-retirement atObjectGrid's emit: that refusal rested on the key's non-membership (excess-property freshness refuses a key no part of the type declares), and membership arrived wholesale throughOmit of TableColumn. Nothing went red at the moment of loss —columnEmitBoundary-6004.test.ts:167merely reported TS2578 (unused directive), which is luck, not design. The PM extended this claim's fence by exactly two files, and the patch round (3f5c1bc7) restores the enforcement while changing nothing about the verdict:ObjectGridRetiredOptionsTombstone(options?: never) inObjectGrid.tsx, with a docblock recording the mechanism so the "redundant-looking"nevercannot be tidied away. It is intersected into bothObjectGridColumnDraft(the type the order named) and the post-foldObjectGridColumn— deliberately half a step past the order's letter, inside the named file: the post-fold type is the emit that actually reaches thedata-tableslot, itsoptionsmembership arrived through the same inheritance, and tombstoning only the draft would leave the very seam finding(plugin-grid): ObjectGrid'sgenerateColumns()is untyped (any[]), so nothing type-checks what it writes intoDataTableSchema.columns: TableColumn[]— the hole that hid #5853 and #5453 #6004 ruled about re-openable by a fold-site write. Flagged here so the choice is reviewable, not silent.The general rule, stated for the record: a pin enforced by a key's non-membership silently stops enforcing the moment the key becomes a member — and inherited membership (an
Omit/extends of a published type) is where this dies silently, because someone else's declaration moves your type. Survey ofcolumnEmitBoundary-6004.test.tsfor other pins on the same mechanism: none —summary/labelrest on the derivedRetiredListColumnKeyband (assignability), the #5853lookuppin on union membership; theoptionspin was the file's only freshness-based refusal, per its own former comment. Nearest relative outside the file, named for carding rather than fixed:overrideSource-6425.test.tsx'sscalepin refuses by non-membership too, butAuthoredColumnOverrides' membership is curated (an explicitPickplus the holds), not inherited — aTableColumndeclaration alone cannot silently disarm it; only a deliberate adjudication into the keyhole can, and that edit's own type-check reports the unused directive. Structurally the safer shape.Verification
Patch-round readings at final commit
3f5c1bc7(clean tree; every heavy run through the shared verify lock, exits from its VERDICT line, never through a pipe); first-round readings atc63f6913where noted:turbo run type-checksweep — the control that found the collision — nowTasks: 81 successful, 81 total, all 45 package type-check tasks ran, zero red, wrapperVERDICT command-exit 0.optionson both emit types went red exactly as predicted — TS2322 at the probe's two lines (…is not assignable to type 'ObjectGridColumnDraft'/…'ObjectGridColumn') — then removed with the restore proven by observation:git diff HEADempty AND worktree blob == HEAD blob (1d1bc3cb…both sides), never by exit code.pnpm exec vitest runover types (lockstep + zod-mirror-parity), components (both data-table suites),columnEmitBoundary-6004.test.ts, and all ofpackages/plugin-dashboard—Test Files 87 passed (87)/Tests 832 passed (832),VERDICT command-exit 0, the run itself printingHEAD: 3f5c1bc7.@object-ui/plugin-grid: patch: presence (8 source file(s) of 3 released package(s) … declares 1 changeset(s)), no-major, overwrite — each exit 0 with its own OK line.check:control-bytes/check:vi-mock-specifiers/check:phantom-depsre-run — exit 0.c63f6913:tsc --listFilesproves the edited suites are program inputs (2 + 1 hits); fullpnpm build43/43 thencheck:readme-exportsreporting 0 unbuilt (population intact, NOT the collapse self-report); fullturbo run lint47/47 green.@object-ui/types/zod→packages/types/src/zod/index.zod.ts), so no dist rebuild is part of either leg.Changeset:
@object-ui/typesminor +@object-ui/plugin-dashboardpatch +@object-ui/plugin-gridpatch (no major — repo rule).Out-of-scope finding filed: #6625 (
FieldMeta.decimalsis schema-written but read by nothing — the dead member this retire exposes; left in place becauserecordFields.tsxis outside the fence).Draft on purpose; landing is the PM/maintainer's.
Generated by Claude Code