fix(components): name a non-array node-level data on data-table instead of dropping it in silence - #6712
Merged
os-sales merged 2 commits intoAug 28, 2026
Conversation
`DataTableRenderer` takes its rows from `data: rawData = EMPTY_ROWS` off the
node and then collapses `Array.isArray(rawData) ? rawData : EMPTY_ROWS`, so
ANY non-array `data` an author wrote becomes zero rows with no error and no
warning: the table draws a correct-looking header over `No results found`,
which reads as a success receipt.
The reported spelling is a `${...}` expression string — the same expression is
evaluated under `properties` and NOT at node level — but the swallow is
general, so the predicate is too: `data` authored and not an array. The
expression shape only selects a sharper sentence.
Reuses the objectui#6575 channel (`dataTableBindDiagnostic.ts`) as a second
predicate rather than a widened one: these nodes carry no `bind` at all, so
that diagnostic's silence on them is correct behaviour, not a gap.
No behaviour change. The trap stops being silent; it does not stop being a
trap.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
Scored patch, matching objectui#6575's own changeset for the same family on the same file: no behaviour change, and nothing added to the published surface — the new predicate, message builder and prefix constant are module-internal and are not re-exported from the package entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
Contributor
✅ 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
deleted the
claude/issue-6665-data-table-string-data-diagnostic
branch
August 28, 2026 18:39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6665
DataTableRendererdestructuresdata: rawData = EMPTY_ROWSoff the node and then collapsesconst data = Array.isArray(rawData) ? rawData : EMPTY_ROWS. So any non-arraydataanauthor wrote becomes zero rows with no error and no warning: the table draws a correct-looking
header over
No results found, which reads as a success receipt.This names it. No behaviour change.
Step 1 — the four-leg table, re-measured
The card quoted this table from
skills/objectui/rules/protocol.md, which states it as ameasurement on
f1c27f037; nobody had re-run it since, and the triage seat pinned only themechanism, not the render. Re-run here on merge-base
5967be095, through the realSchemaRendererinside aSchemaRendererProviderholding{ customers: [ 2 records ] },identical
columnsin every leg, readingtbody td— on a clean tree with none of thisPR's code in it:
{ "type": "data-table", "data": "${data.customers}", "columns": [...] }No results found(1tbody tr){ "type": "data-table", "props": { "data": "${data.customers}" }, ... }No results found(1tbody tr){ "type": "data-table", "properties": { "data": "${data.customers}" }, ... }{ "type": "data-table", "data": [ 2 literal records ], ... }All four reproduce exactly, and every leg emitted zero
[ObjectUI]console lines — thesilence the card is about, measured rather than assumed. The header in the failing leg is
correct (
Name,Email), which is why it reads as success.The contrast IS the argument: the same expression is evaluated under
propertiesand notat node level. That is what makes this a defect rather than a design choice, so all four legs
are now pinned as one table-driven test instead of living in prose that ages silently.
The predicate
datawas authored, and it is not an array.It deliberately asks a different question than #6575's, rather than widening it. That one
is keyed on an authored
bind; these nodes carry nobindat all, so its silence on themis correct behaviour and not a gap. Widening it would have made that correct silence look like
the defect. Two predicates, one channel — the existing
packages/components/src/renderers/complex/dataTableBindDiagnostic.ts, reused, not duplicated.It is also deliberately wider than the reported spelling. The
${...}string is what wasreported, but
Array.isArray(rawData) ? rawData : EMPTY_ROWSswallows a number, an object, anulland a plain string exactly as silently, so a predicate keyed on the expression shapewould leave each of them to arrive as a fresh card. The shape only selects a sharper sentence:
data: '${data.customers}'` was never evaluated: ... read as a literal stringwas authored as the number42`, and data-table takes its rows only from an array`Both end with the one route the guides teach: resolve the rows in the host. The message does
not tell authors to move the expression under
properties— whether that is an authoringchannel is an open contract question (#4795), and a console line is the wrong place to settle
it.
What this deliberately does NOT do
Make node-level
dataevaluate expressions. That is a behaviour change on a publishedcomponent; the triage ruling put it on the maintainer floor and dispatched only the diagnostic
arm. Nothing here changes what renders. The trap stops being silent; it does not stop being a
trap.
Nothing is added to the published surface either: the new predicate, message builder and
prefix constant are module-internal and are not re-exported from the package entry — matching
#6575's own symbols.
Tests — red before, green after
Both required cases are pinned, and both were shown red by ablation on the committed tree
(mutation confirmed on disk by grep counts of the removed and injected text, plus a blob-hash
comparison against the
HEADblob; restored viagit checkout HEAD -- path, proven by anempty
git diff HEAD). No rebuild step is involved: the root Vitest config aliases every@object-ui/*specifier to the sibling package'ssrc/, so these suites run against source,not
dist.console.warnwiring indata-table.tsx${...}shape onlynames the expression string that was swallowedstayed green, so the tests really do forbid a${...}-only predicateGreen after, on final commit
41dc9a5ff:tsconfig.test.jsonincludessrc/**/*.test.tsx, so the typecheck genuinely covers the newtest file rather than passing by excluding it. Lint was run package-wide rather than
repo-wide; that narrowing is safe here because the diff touches only files inside
packages/componentsand no config file, andeslint.config.jsenables no type-aware linting(no
parserOptions.project/projectService), so no untouched file's verdict can move.One thing found and filed, not fixed here
Leg 2 of the table — the same expression under
props— is a different and wider shape:properties.*is hoisted onto the node bySchemaRenderer,propsis not, so a key underpropsnever reaches any renderer that reads onlyschema. This diagnostic is correctlysilent there (node-level
datais genuinely absent), and that silence is pinned by its owntest rather than left to be rediscovered. Recorded as #6708 for triage; reaching into
propsfrom a data-table predicate would patch one component against a repo-wide shape.
Changeset
@object-ui/components: patch. Scored to match #6575's own changeset for the same family onthe same file: no behaviour change, no published surface added, no type widened. Not
minorbecause nothing new is exported from the package entry; never
major, per AGENTS.md's versionpolicy for the fixed release group.
Generated by Claude Code