Skip to content

test(plugin-list): pin all eight reported columns spellings on a kind:'html' page - #6787

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-6598-html-tier-columns
Aug 29, 2026
Merged

test(plugin-list): pin all eight reported columns spellings on a kind:'html' page#6787
os-sales merged 1 commit into
mainfrom
claude/issue-6598-html-tier-columns

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes#6598

The reported defect no longer reproduces — this PR is the measurement and the pin

⛔ No product code changes here. The first action on this card was to reproduce the
original symptom on current main (c6732825d) before writing anything, because the
merge that discharged the blocker was the one most likely to have already discharged
this card. It had.

The reported state: a kind:'html' page whose list-view block renders the row
count ("23 records") and the filter/group/sort toolbar, but no data columns at all —
only the index column
— with zero diagnostics, in all eight spellings the reporter
tried.

Measured on c6732825d, all eight spellings, end to end through the real page
renderer, the real html-tier compile against the real registry manifest, the real
list-view registration and the real object-grid:

#spellingoutcome on current mainheaders
1single-quoted JSX array literalrenders the authored projection# / Opportunity Name / Amount
2JSON string where an array is declaredrefused (type-mismatch warning), block defaults render# / Opportunity Name / Stage / Amount
3object-array with bare identifier keysrenders the authored projection# / Opportunity Name / Amount
4viewName referenceundeclared prop (unknown-prop), block defaults render# / Opportunity Name / Stage / Amount
5view referenceundeclared prop, block defaults render# / Opportunity Name / Stage / Amount
6child column elementspage-fatal, loud — compile-error block on screennone
7no columns attribute at allblock defaults render# / Opportunity Name / Stage / Amount
8akebab object-namepage-fatal, loud — "missing required prop objectName"none
8bkebab view-nameundeclared prop, block defaults render# / Opportunity Name / Stage / Amount

Not one of the eight lands in the reported state. Six render data columns; the two
that fail do so loudly, with the reason on the page — the opposite of the silent
vanish that was reported.

Why one symptom had three causes

The uniformity of the eight is what made this card hard to anchor: it read as one bug
and was never one. Three unrelated mechanisms happened to look identical from the page,
and each was already discharged elsewhere:

The card's title and its "Triage anchoring evidence" section remain disproven (the
block is list-view, not object-table; the live registration does declare columns;
parse.ts keeps every attribute and validateTree only warns). Re-titling is triage's
write, so it is flagged here rather than edited.

What this PR adds

Sibling files pin those mechanisms one at a time — literal-subset-6614.test.ts and
inert-expression-6598.test.ts own the grammar and its diagnostic;
ListView.unauthoredColumnProjection-6598.test.tsx owns the handoff against a stub
grid; htmlTierListViewDefaultColumns-6598.test.tsx takes the unauthored case end to
end.

⚠️ None of them pins this card's own claim, which is a statement about all eight
spellings at once. That can only be checked as a matrix, and only through the real live
registration. The invariant each spelling must satisfy is a disjunction: it either
renders at least one data column, or it fails loudly with the compile-error block
on screen. What no spelling may do is what all eight did when the card was filed —
render a populated table whose only header is the index column.

A spelling moving between those two is a design decision someone can argue about; a
spelling falling out of both is this card regressing.

Reverse verification — two ablations, from the committed state

Both mutate, prove the mutation reached disk by grep counts of the injected and
deleted text plus a blob-hash change, run, then restore via
git checkout HEAD -- PATH proven by an empty git diff HEAD and the blob back at the
HEAD value. Each script carries a trap on EXIT INT TERM with absolute paths. No
dist rebuild applies: the root vitest config aliases @object-ui/* to src, so these
runs read source.

Ablation A — undo the handoff fix (ListView.tsx, blob ec955200 to 840764f2;
hasAuthoredColumns hits 4 to 0, injected text 1):
Tests 5 failed | 4 passed (9). The five reds are forms 7, 2, 4, 5 and 8b — every
"no projection this tier can read" case — and each fails on the card's own invariant
line
, i.e. it reproduces the reported symptom exactly. Forms 1 and 3 (authored
projection) and 6 and 8a (loud) stayed green, so the pin is not red for a general
reason.

Ablation B — undo the grammar widening (parse.ts, blob e162048c to 0d9c4dec;
readLiteral call hits 1 to 0, marker 1): Tests 2 failed | 7 passed (9). Only forms
1 and 3 go red, and — as predicted before the run — they fail on the exact-projection
assertion, not on the card invariant: expected [ '#', 'Opportunity Name', ...(2) ] to deeply equal [ '#', 'Opportunity Name', 'Amount' ]. That separation is the useful
result. PR #6679 alone is what keeps the page out of the reported state; PR #6669 is
what makes it honour the author's projection instead of the defaults.

Verification

Union at final HEAD 3d3103371, working tree clean, all under the shared verify lock,
each exit code captured before any pipe.

  • pnpm exec vitest run packages/plugin-list/ packages/sdui-parser/ scripts/__tests__/
    = Test Files 152 passed (152) / Tests 3309 passed (3309) (includes the 9 new cases).
    scripts/__tests__/ is run because the diff edits vitest.config.mts — deriving gate
    families from changed paths does not answer "what tests read the thing I changed".
  • pnpm --filter @object-ui/plugin-list run type-check clean, and proven to cover
    the new file: tsc -p tsconfig.test.json --listFiles shows 1 hit for the new test and
    1 for ListView.tsx.
  • pnpm run check:control-bytes = check-control-bytes: OK (scanned 5648 tracked text file(s); skipped 85 binary).
  • pnpm run check:phantom-deps = Every in-scope import is declared by the package that publishes it.
  • pnpm run check:self-import = No package names itself inside its own src/. (run
    because that script reads vitest.config.mts).
  • node scripts/check-changeset-presence.mjs and check-changeset-no-major.mjs both
    green; the changeset carries an empty frontmatter, the first-class "releases
    nothing" declaration for a tests-only change.
  • Lint, 0 errors in both units containing a changed file: pnpm --filter @object-ui/plugin-list lint = 439 problems (0 errors, 439 warnings); pnpm run lint:root (covers vitest.config.mts) = 28 problems (0 errors, 28 warnings). The
    new file contributes 2 warnings, both no-explicit-any on the data-source fixture,
    matching the sibling end-to-end file.

⚠️pnpm run check:sdui-registration-pins is reported as NOT MEASURED, not as a
failure: it exits 2 with No console build to weigh at apps/console/dist/assets — a
declared prerequisite miss, not a verdict. It is not derived from this diff either (no
registration and no side-effects array is touched). CI builds the console and runs it.

Scope

packages/plugin-list/ and packages/sdui-parser/ were the declared surface; the diff
lands one new test file in packages/plugin-list/src/__tests__/, the one-line
heavyDomTests registration it needs in vitest.config.mts, and the changeset. The
sibling surfaces held by other seats are untouched.


Generated by Claude Code

…nd:'html' page
The reported defect no longer reproduces on main. Re-measured every one of the
eight spellings objectstack#12649 tried: none lands in the reported state (a
populated table whose only header is the index column, with zero diagnostics).
Six render data columns — forms 1 and 3 render exactly the authored projection,
forms 2, 4, 5, 7 and 8b render the block's defaults — and forms 6 and 8a fail
loudly with the compile-error block on screen.
Three separate mechanisms produced one symptom, and each was fixed elsewhere:
the braced literal subset (#6614 / PR #6669), the unauthored-projection handoff
(PR #6679), and the grid's default-column derivation (#6677).
What none of those pinned is the card's own claim, which is a statement about
all eight spellings at once. This adds that matrix, through the real page
renderer, the real html-tier compile against the real registry manifest, the
real `list-view` registration and the real `object-grid` — so no future change
can put any spelling back into the reported state.
Tests only; the changeset declares an empty frontmatter accordingly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 45 chunks)3174.0 KB3222.7 KB
Main entry chunk (gzip)148.2 KB350 KB
Entry fileindex-DfChq7wZ.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)11.89KB4.50KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)511.75KB116.33KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)173.10KB47.96KB
fields (index.js)240.93KB60.76KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.92KB12.93KB
plugin-charts (index.js)64.68KB18.35KB
plugin-chatbot (index.js)190.33KB45.10KB
plugin-dashboard (index.js)133.48KB34.51KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)245.46KB62.46KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)133.03KB32.64KB
plugin-gantt (index.js)165.23KB40.37KB
plugin-grid (index.js)201.57KB54.55KB
plugin-kanban (index.js)53.14KB14.64KB
plugin-list (index.js)113.15KB27.59KB
plugin-map (index.js)20.20KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)28.94KB8.33KB
plugin-tree (index.js)9.00KB3.08KB
plugin-view (index.js)85.87KB21.12KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)72.12KB23.98KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)2.40KB1.20KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-sales
os-sales marked this pull request as ready for review August 29, 2026 13:58
@os-sales
os-sales added this pull request to the merge queueAug 29, 2026
Merged via the queue into main with commit 4c9afc1Aug 29, 2026
32 checks passed
@os-sales
os-sales deleted the claude/issue-6598-html-tier-columns branch August 29, 2026 14:12
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-sales@claude