Repository navigation
finding(components): the static table renderer reads 9 of the 20 keys TableSchema/TableColumn declare — hoverable, striped, align, sortable, cell and 6 more are inert, and the reference page documents two of them as working #5474
Description
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Aug 21, 2026 Triage (first-touch): routed to the decision inbox (needs-user-decision, domain:ui, type Task). Eleven declared-but-inert keys on a published authoring surface, two of them documented as working — this is an enforce-or-remove contract-shape call, which is the manual floor. Chinese four-facet analysis below.
os-decision-facets(四棱卡面块;标记按字面文本写入)
一句话问题:静态表格组件的「使用说明书」列了 20 个旋钮,实际接线的只有 9 个 —— 文档还专门教用户去拧那 11 个没接线的(斑马纹、悬浮高亮、右对齐都在内),拧了没反应也不报错。
选项与真实代价:
- A. 把没接线的旋钮实现掉:业务上 = 静态表格长出排序/筛选/编辑,和交互表格 data-table 越长越像。真实代价:重复建设一套 data-table 已有的能力,养两个交互表格。
- B. 从说明书上删掉没接线的旋钮(ADR-0049 退役),指路 data-table:业务上 = 「简单表格就是简单表格,要交互用 data-table」,一句话讲清;AI 生成器不再产出无效配置。真实代价:存量 schema 里写了这些键的会被严格校验响亮拒绝,需按退役正道走(墓碑 + 迁移提示);TableColumn 是共享类型,DataTableSchema 等消费者要先查清再动。
- C. 拆类型:富形状归 data-table,静态表格声明自己的窄子集 —— 每个渲染器 declared = enforced。业务上 = 说明书按产品分册,各自诚实。真实代价:比 B 多一次类型拆分与迁移,但共享消费者问题就地解决。
- D. 不动:AI 和用户继续拧假旋钮,静默无效 —— 本仓反复付过账的那一类。
四棱:
- ① 项目长远合理性:B/C 收敛契约,A 是能力面扩张;C 结构最诚实(声明即强制按渲染器成立)。
- ② 实际业务拉动:零拉动实现(A)违背 implementation-first;今天的真实伤害是假旋钮(右对齐金额列是生成器最常写的),删除即止血。
- ③ 防 AI 犯错:B/C 让无效配置在编写期响亮被拒;A 治标不治「声明先于实现」的病根;D 是静默容忍的温床。
- ④ 创业阶段不扩散:B 最瘦;C 次之但一步到位;A 扩面。
- 推荐:C(回退:B —— 若共享消费者排查证明拆分成本过高)。回一个字母即可。
置信缺口(本分析看不见什么):TableColumn 的全部消费者面未清点(卡内点名 DataTableSchema,可能还有别家);存量用户 schema 里这 11 个键的实际书写量未测(若大量存在,B/C 的迁移提示要更周全)。裁后执行:C 或 B 均按 ADR-0049 退役正道立实施卡入 ui 车道(墓碑、schema-reference 文档同步、palette/生成器扫尾),A 则拆卡按能力逐个排队;文档先行修正(schema-reference 删 hoverable/striped 教学)可作首段独立小卡。
Generated by Claude Code
huangyiirene commented
on Aug 22, 2026 CollaboratorMore actionsMaintainer ruling recorded (2026-08-22, decision-inbox digest with the skills seat,
session_01ApyDuQY2fkunMCqXiqvBhR)The full decision inbox (46 cards) was presented with per-card four-axis recommendations; the maintainer accepted the batch, verbatim: 「接受所有」.
Ruled: Option C — split the types.
TableColumnremains the rich shared shape thatdata-tablehonours, and the statictablerenderer gets its own narrow declared subset, sodeclared = enforcedholds per renderer. Execution follows the ADR-0049 retirement path for the keys leaving the static renderer's surface (tombstones, schema-reference doc sync, palette/generator sweep), and the shared-consumer surface ofTableColumn(DataTableSchemaand any others) must be enumerated before the split. Attached condition from the batch: the teaching-material removal (deleting thehoverable/stripedteaching fromschema-reference.md) may be split out as its own standalone first card. Fallback recorded in the analysis stands: if the shared-consumer audit shows the split's cost is prohibitive, the fallback is Option B (plain retirement pointing authors atdata-table).State:
needs-user-decisionremoved →pm:queue(ready for dispatch).
Generated by Claude Code
Claim —
domain:uiexecution seat.- Session:
session_01EuPCi56cnGyykygi3z9w4m - Branch:
claude/issue-5474-static-table-narrow-types - Seat post: [PM seat] domain:ui @ objectui — 🟢 os-steve · session_016djJF12Qt14ejKR5Vjt4sK · batch 3 · 2 landed #5560
Dispatching this round (R27) at the contract-review tier — the maintainer's ruled Option C splits a published type, and the keys leaving the static renderer's surface go down the ADR-0049 retirement path.
Generated by Claude Code
- Session:
- added a commit that references this issue
on Aug 23, 2026 os-dev-report
{ "issue": 5474, "status": "done", "branch": "claude/issue-5474-static-table-narrow-types", "pr": "https://github.com/objectstack-ai/objectui/pull/5822", "premise_still_valid": true, "summary": "Option C executed verbatim: new narrow StaticTableColumn (header/accessorKey/className/cellClassName/width) + interface/zod exports; TableSchema.columns moved to it; the 11 never-read keys retired as ADR-0049 tombstones (?: never / z.never().optional(), crud.ts confirm convention) so authored values are refused loudly with the key named — rich TableColumn byte-untouched and pinned untouched. Census re-derived with a stronger instrument (full-file read + SchemaRenderer prop-flow; the instrument now lives in-tree and fails on destructure/computed/helper patterns that would blind it): card's 9-read/11-inert numbers exact. Shared consumers enumerated (DataTableSchema, CRUDSchema, views.ts relations, CRUDBuilder, zod DataTableSchema) — all stay rich; fallback B not needed. Doc sync: schema-reference §TableSchema loses the hoverable/striped teaching (example + table + intro), columns row now names the enforced subset; sweep cleaned types/examples json + site playground; palette inputs description gains cellClassName.", "tests": "All at c3cb8c3c4 (the branch's single commit). Union: pnpm exec vitest run packages/types/ packages/components/src/renderers/ scripts/__tests__/doc-version-claims.test.ts scripts/__tests__/check-doc-links.test.ts -> 'Test Files 126 passed (126) / Tests 1318 passed (1318)'. Typecheck: 5 tsc projects green (types: noEmit+examples+tests; components: noEmit+tests) against the rebuilt turbo closure — components leg imports StaticTableColumn through dist/index.d.ts, a symbol only the new build carries, so green cannot be stale. Reverse verification, both legs from committed state, predicted direction red observed: (A) soften hoverable tombstone -> 'Tests 2 failed | 19 passed' (refusal pin + tombstone-set pin); (B) delete the renderer's cellClassName read -> instrument red on 'declared live but never read'. Ablation rebuild statement: no build leg needed — the root vitest config aliases @object-ui/types and /zod to src, so the mutated files ARE what vitest loads; mutations confirmed on disk by anchored grep before each run (leg A marker=1/removed-anchor=0; leg B col.cellClassName=0), restores proven by inverse counts, trap-guarded scripts. Gates: check-changeset-presence OK ('5 source file(s) of 2 released package(s) ... declares 1 changeset(s)'); check:control-bytes/doc-types/spec-symbols exit=0; turbo lint types+components '3 successful'. check:doc-snippets self-reported NOT RUN locally (needs full workspace build) — declared narrowing, closed by CI. CI read once by name at ~10.5 min after run start (13 runs on head c3cb8c3c4): all completed, 12 success + Dependabot Auto-merge skipped, zero failure/cancelled, mergeable_state clean — including Doc Snippet Types success and CI success. No 'Build Docs'-named workflow materialized on this head; the completed/no-failure/clean judge holds over the actual 13.", "open_questions": [], "out_of_scope_findings": [ "filed as #5821: rich TableColumnSchema zod mirror omits `editable` — a key data-table reads at 3 sites is silently stripped by validation, so a column locked editable:false re-opens after parse (#4605 class; my rich-accept test loop excludes editable with a comment pointing at it)", "NOT re-filed: stale skills teaching of `label` on a static table column (skills/objectui/guides/schema-expressions.md) already open as #5473 — search-first caught it; nothing new added there" ] }
Generated by Claude Code
- added a commit that references this issue
on Aug 23, 2026 - added 4 commits that reference this issue
on Sep 1, 2026
Found while implementing #5350 (retiring that renderer's undeclared column aliases). Observation class — filed unassigned and deliberately NOT fixed there, because which way it resolves is an ADR-0049 enforce-or-remove contract decision, not a re-spelling. #5350 stayed inside the spelling question the family ruling settled.
Measured
Every key
packages/components/src/renderers/complex/table.tsxreads, derived from the file rather than recalled:Nine. Against that,
packages/types/src/data-display.tsdeclares:TableSchemacaption,columns,data,footerhoverable,stripedTableColumnheader,accessorKey,className,cellClassName,widthminWidth,align,fixed,type,sortable,filterable,resizable,editable,cellEleven declared keys are never read.
hoverableandstripedeven carry@defaultannotations (true/false) describing behaviour that does not exist on this renderer.The published page documents two of them as working
content/docs/api/schema-reference.md§TableSchema:hoverablebooleanstripedbooleanand its copyable example sets
"hoverable": true, "striped": true. Both are inert. The section header one line above likewise reads "A data table with columns, optional striping, and hover effects."This is the same declared-but-unenforced shape as #5373 (
type: 'crud': four declaration faces, no renderer), one level down: the type renders, but a majority of what it declares does not. #5350 corrected the same section's spelling contract and deliberately lefthoverable/stripedin the example, because deleting them would have pre-empted this decision.Not merely cosmetic for AI authoring
alignandsortableare the two most likely for a generator to emit — a right-aligned amount column is the obvious thing to author, and the pre-#5350 reference example did exactly that ({ "name": "amount", "label": "Amount", "align": "right" }). It is accepted, type-checks, and does nothing, with no diagnostic. Same silent class as #5349.The routes, not pre-decided
hoverable/striped/alignare a few lines each;sortable/filterable/resizable/editable/cellare substantially more, and arguably whydata-tableexists).TableSchema/TableColumnunder ADR-0049 and point authors atdata-tablefor the interactive set — the narrow reading being thattableis deliberately the dumb static renderer and its type over-declares.TableColumnas the rich shared shapedata-tablehonours and give the static renderer a narrow declared subset, sodeclared = enforcedholds per renderer.Route 2 or 3 look consistent with the startup-focus / implementation-first standing instruction, but the pick is a maintainer call. Note
TableColumnis shared:DataTableSchemaand others consume it, so a retirement must be checked against those consumers first — this is not a single-renderer edit.Reproduce
Related: #5350 (the spelling half, which left this alone), #5373 (same enforce-or-remove class), #5349 (the silence).
Generated by Claude Code