Repository navigation
finding(plugin-grid/docs): the published docs and skills teach { name, label } columns on a directly-authored object-grid, which ObjectGrid silently drops — before and after #5068 #5352
Description
Activity
Triage first-touch grading (finding centralized round, 2026-08-20, triage seat session
session_016A4EBi3ky1mjTi6vD2kCvA): promote topm:queue, type Task, scope = the docs half only. Re-verified onorigin/main:schema-reference.md:748-755and the skills page-builder guide still teach{name,label}columns on directly-authoredobject-grid, whichObjectGrid.tsx:1477silently drops (whilecolumnIdentitystill ships the dead column name to$select). The docs correction needs no ruling —object-grid's contract is already settled (strictListColumnSchema,field/label) — so fixing the two published examples that actively teach a broken shape is severable; the fold-vs-filter renderer question stays with #5349, and the wider alias-family ruling stays with #5120.
Generated by Claude Code
Claim: PM loop round 21
Session:session_01RV6yuVCxymHYE16PL9vQkE
Branch:claude/issue-5352-grid-column-spelling-docs
Worktree:objectui-issue-5352
Domain:repo:objectui
File surface:content/docs/api/schema-reference.md+skills/objectui/guides/page-builder.md— docs half only, per triage (stop on breach; explain in the report)
Container & model:M,mode:subagent
Clause-②: no — docs only, no accept-set change
Serial constraints cleared:packages/plugin-gridis free (#5349/PR5456 MERGED).⚠️ Premise partially moved: #5349 landed a diagnostic, so the drop this card calls "silent" is no longer silent — re-verify wording before writing.
Generated by Claude Code
- added a commit that references this issue
on Aug 21, 2026 { "issue": 5352, "status": "done", "branch": "claude/issue-5352-grid-column-spelling-docs", "pr": "https://github.com/objectstack-ai/objectui/pull/5463", "premise_still_valid": true, "summary": "The card's core premise held and is fixed: both published corpora authored object-grid columns in a `name` spelling ObjectGrid does not read, and both now spell `field`. Docs half only, per triage — ObjectGrid is untouched. TWO CORRECTIONS to the card's description. (1) 'Silently — no throw, no console line' is now only half true, and not the half the card implies: #5349/PR5456 landed a diagnostic, so the ALL-OBJECT array in page-builder.md now emits one console.warn naming each column; but the MIXED array in schema-reference.md is STILL completely silent, because partitionAuthoredColumns returns null when columns[0] is not an object and deliberately declines to judge the string[] arm. (2) The card frames schema-reference.md as one spelling defect; rendering proved a second, independent one — normalizeColumns dispatches the WHOLE array on columns[0], so with a bare string first the array takes the string arm and the trailing column object is dropped WHATEVER it spells. Renaming name->field alone left Status still missing (measured); the example had to become uniformly ListColumn objects. Also added the `columns` property-table row naming `field` plus the no-mixing rule, and a note in page-builder.md between the adjacent grid and form examples, which mean the opposite thing by the same pair of words (ListColumn.field vs FormField.name) — the documented cause of this defect family per packages/core/src/utils/column-identity.ts. The adjacent object-form example was verified correct and left alone. File surface honoured exactly: the two named corpora, plus the mandated changeset (.changeset/grid-column-spelling-docs-5352.md, empty frontmatter — docs/skills only, publishes nothing; objectui has no skip-changeset label).", "tests": "All readings on committed head e8714f782 (working tree clean); heavy runs wrapped in flock -E 99 -w 540 /tmp/os-heavy-verify.lock. RENDER MEASUREMENT (not type-reading): a throwaway vitest harness in packages/plugin-grid/src/__tests__/ extracted the object-grid JSON blocks OUT OF THE DOC BYTES themselves — `git show origin/main:FILE` for the before leg, working tree for the after leg — and rendered each through the real ObjectGrid; harness deleted before the commit (diff is 3 files). Note vitest.config.mts aliases every @object-ui/* specifier to src/, so no dist build gates this measurement and no ablation is involved. schema-reference.md: BEFORE headers [#,Name,Email,Company,Phone,Actions] body [1Open,Ada,ada@x.com,Analytical,555-1,''] DIAGNOSTICS 0 -> AFTER headers [#,Name,Email,Company,Phone,Status,Actions] body [...,Active,''] DIAGNOSTICS 0 (silent in BOTH legs — the drop was and would have stayed unreported). page-builder.md: BEFORE headers [#] only (row-number column, ZERO data columns) body [1Open] DIAGNOSTICS 1 ('[ObjectUI] ObjectGrid columns: object-grid (objectName: products) — 3 of 3 authored columns resolve to nothing... columns[0]: keys seen: name, label, type — no field key') -> AFTER headers [#,Name,Price,Status] body [1Open,Widget,9.50,Live] DIAGNOSTICS 0. NEGATIVE CONTROL: field-spelling-but-still-mixed rendered headers [#,Name,Email,Company,Phone] — Status STILL dropped, which is what forced the all-object rewrite. CONTRACT PROBE against the real strict ListColumnSchema (@objectstack/spec/ui 17.0.0): all 8 corrected columns -> PARSES; both old shapes -> REFUSED, invalid_type:['field'] + unrecognized_keys:['name']. SWEEP: a scanner parsed EVERY fenced json block in both corpora and applied the renderer's own two filters, recursing for object-grid/view:grid anywhere in the tree (grep alone misses the two nested grids). BEFORE: 35 blocks, 35 parsed, 0 parse-failed, 4 grid blocks found, 4 dropped entries. AFTER: 35 blocks, 35 parsed, 0 parse-failed, 4 grid blocks found, 0 dropped entries. COUNTER-PROBE for the zero: the same scan still reports 4 grid blocks by name after the fix (so the search works), parse failures are reported rather than skipped (0 of 35, so no block went silently unread), and the arm reading for schema-reference.md flipped string->object, confirming the dispatch change landed. GATES (green on e8714f782): check:control-bytes OK (4521 tracked text files); check:skills-paths OK (95/96 stated paths resolve, 1 baselined); check:doc-types OK (183 doc files, 1052 code blocks, every documented component type registered); check-changeset-presence.mjs OK (1 changeset added); check-changeset-no-major.mjs OK. Plus a manual control-byte grep over the three touched files: none found. NOT RUN — check:doc-snippets: it needs 15 built package dists and reads ONLY fenced ts/tsx snippets; this diff changes zero ts/tsx fences (mechanically: git diff --merge-base over the two files matches 4 json-language fences and zero ts or tsx fences). CI builds and runs it. CI on the PR was not awaited, per the report-at-draft-PR contract.", "open_questions": [], "out_of_scope_findings": [ "NOT filed, already open and unassigned as #5350: the type:'table' and type:'crud' examples in the SAME schema-reference.md also spell name/label against TableColumn (which declares header/accessorKey), and packages/components/src/renderers/complex/table.tsx tolerates both via `col.header || col.label` and `row[col.accessorKey || col.name]`. #5350 quotes the same property-table row and the same table.tsx line, so filing would have duplicated it. Not fixed here: different component, different contract, and the correct direction (retire the alias vs declare name on TableColumn) is an unruled maintainer call.", "NOT filed, already open as #5373: type:'crud' is documented in api/schema-reference.md as reference material but has no renderer — covers the crud half of the block above.", "No new issue was filed this round. Observation, deliberately not filed as it is already stated inside check-doc-snippet-types.mjs as #5138 shape 1 (left unruled on purpose): no gate in this repo could have caught this defect — check:doc-types verified the one key that was right (the 'object-grid' type literal), while check:doc-snippets excludes schema-key validity of JSON metadata blocks. That blind spot is how both corpora drifted." ] }
Generated by Claude Code
- added a commit that references this issue
on Aug 23, 2026
Found while running #5120's census (not claiming; observation class). Baseline objectui
main@ 9c60144, i.e. after PR5345 (#5068) landed.The fact
Two published corpora author
object-gridcolumns in thenamespelling:content/docs/api/schema-reference.md:748-755— a mixed array:"columns": ["name", "email", "company", "phone", { "name": "status", "label": "Status", "sortable": true }]skills/objectui/guides/page-builder.md:304— all-object:{ "name": "name", "label": "Name", "type": "text" }, etc.ObjectGridrenders neither. Both shapes are dropped silently — no throw, no console line, no empty header cell; the column is simply absent.Not a #5068 regression — verified both paths
Worth stating explicitly, because the timing invites the wrong conclusion:
ObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068, an all-object array reaches the ListColumn arm, whose filter iscol?.field && typeof col.field === 'string'. A{ name, label }column has nofield, so it is filtered out.ObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068, the same array met the retired dispatch:'accessorKey' in firstCol→ no;'field' in firstCol→ no; so it fell out of the object block entirely and into the string arm, whose filter istypeof fieldName === 'string'— which drops it too.schema-reference.md) hascols[0]as a string, sotypeof cols[0] === 'object'is false and it took the string arm both before and after; the one object entry is dropped by that sametypeof === 'string'filter, unchanged by finding(plugin-grid): ObjectGrid 在ObjectGridSchema.columns上容忍未声明的accessorKey/header拼写 —— 声明类型是 strict 的 ListColumn,#3104 的列身份门禁结构上看不见这条支路 #5068.So the outcome is identical on both sides of PR5345. This is a pre-existing docs-vs-runtime divergence that #5068's census did not surface because that census was looking for the
accessorKey/headerspelling, not this one.Why it is not merely a docs fix
ObjectGridis not downstream ofnormalizeListViewSchemawhen anobject-gridnode is authored directly — its own test file says so (packages/plugin-grid/src/__tests__/columnIdentity.test.tsx, docblock). So thename→fieldfold that rescues alistview's columns (normalizeColumnIdentities, #3104) never runs here. The same{ name: 'status' }column therefore does reach$select(getSelectFieldsresolves throughcolumnIdentity, which acceptsname) while not reaching the rendered column set: the server is asked for the field and the user is never shown it.That asymmetry is the part worth a decision — whether the fix is the docs, the fold, or the filter.
Recheck
Grading
finding, notpm:queue. Related: #5068, #5349 (the same silence, asked as a diagnostics question), #5120.