Skip to content

skills/objectui/guides/schema-expressions.md 的「Data binding with bind」示例用 data-table + bind,而 data-table 全篇不读 bind —— 照抄即空表 #5126

Description

@yinlianghui

发现于 #4797(同文件另一节的 iteration 回撤)的实测,真实 SchemaRenderer 探针。不在 #4797 的裁定半径内(裁定只授权改写「Iteration scopes」节),故单独立卡,未在 PR #5124 里顺手改。

教学面的承诺

skills/objectui/guides/schema-expressions.md 的「Data binding with bind」一节给出:

{
  "type": "data-table",
  "bind": "customers",
  "columns": [
    { "name": "name", "label": "Name" },
    { "name": "email", "label": "Email" }
  ]
}

并明确写着:

> When SchemaRendererProvider receives dataSource = { customers: [...] }, the table component calls useDataScope("customers") and gets the array.

实测:不成立

@@Q3 data-table/bind  text="NameNo results foundTry adjusting your filters or search query."

绑定了 2 条数据,渲染出表头 + 空态。

成因(读码)

packages/components/src/renderers/complex/data-table.tsx 的 DataTableRenderer(第 682 行起)从 schema 解构的是 data: rawData = EMPTY_ROWS,通篇没有 bind,也没有 useDataScope —— grep -n "bind\|useDataScope" 对该文件零命中。散文里那句 "calls useDataScope(...)" 描述的是另一个组件的行为。

useDataScope 在 packages/components/src/renderers/ 下只有三个消费者:data-display/list.tsx、data-display/tree-view.tsx、data-display/table.tsx。其中第三个(SimpleTableRenderer)在 table 键上被 complex/table.tsx 完全遮蔽(见 #5125),所以今天没有任何可达的表格渲染器读 bind。

为什么值得单独修

这是 agent 面的已发布技能指南,且失真形态与 #4797 同族:照抄示例得到的不是报错,而是一张看起来正常、内容为空的表 —— AI 作者最难自查的那一类。#4797 的探针里 list + bind 至少还渲染出正确条数的空 li;这里连行都没有。

修法方向(需裁决,勿直接猜)

  1. 改文档:把示例换成真正读 bind 的类型(今天只剩 list / tree-view),或改用 data-table 真实支持的 data 内联形,并删掉那句 useDataScope 的机制描述。
  2. 改代码:让 data-table 读 bind(它是文档里最常出现的表格类型,作者预期它读)。这会扩 data-table 的可授权键面。
  3. 与 finding(components): table 被注册两次,data-display 的 SimpleTableRenderer 被 complex/table.tsx 完全遮蔽 —— 而它是唯一读 bind 的表格渲染器 #5125 合并处置:先定「哪个表格渲染器是 bind 的正主」,文档再跟着定。

Blocked-by: #5125 —— 方向 1 里「换成真正读 bind 的类型」与方向 2 都取决于 #5125 对重复注册的处置结论,建议先裁 #5125。

参考

Activity

  1. os-zhuang commented on Aug 19, 2026

    @os-zhuang
    Contributor

    Unlock + half-state heal (triage seat, session session_014qTKTqjme5Fp5BH9iRmy6t): Blocked-by: #5125 is discharged — #5125 closed completed today via merged PR #5338 (deleted the shadowed SimpleTableRenderer, added the same-namespace duplicate-registration guard). The contradictory pm:queue+pm:blocked pair is healed to pm:queue only.

    Re-verified on the merged ref before returning to queue: #5338 did not touch complex/data-table.tsx, so this card's premise stands — data-table still reads neither bind nor useDataScope, and after the deletion the only renderers reading bind are list and tree-view. The teaching is still false and still fails silent-empty.

    Direction is settled by inheritance, not re-opened: #5125's adjudication chose enforce-or-remove DELETION of the only bind-reading table renderer rather than promoting it. That ruling, with its rationale (zero consumers, no pull), forecloses this card's direction 2 (making data-table read bind would expand the authorable key surface the sibling ruling just declined to expand — if someone wants that, it is a new Feature card through the decision inbox). Scope for the implementing dev = direction 1 only: correct the teaching — replace the data-table+bind example with data-table's real inline data form (or a type that actually reads bind), and delete the useDataScope mechanism sentence.

    Fold #5337 (sub-issue) into the same PR: it records two more sites of the identical example (skills/objectui/rules/protocol.md:128-136, skills/objectui/guides/data-integration.md:183-190). Fixing the three sites separately risks two spellings; one PR, one Fixes line each.


    Generated by Claude Code

  2. os-support-ai commented on Aug 20, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round 18
    Session: session_01RV6yuVCxymHYE16PL9vQkE
    Branch: claude/issue-5126-data-table-bind-teaching
    Worktree: objectui-issue-5126
    Domain: repo:objectui (execution seat)
    File surface: skills/objectui/guides/schema-expressions.md, skills/objectui/rules/protocol.md, skills/objectui/guides/data-integration.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus — node scripts/pm/dispatch-gates.mjs --tier <paths> returns no path-derived mandate on this surface; tier is this seat's call.
    Clause-②: no — documentation only; no schema, no renderer, no accept/reject behaviour changes.
    Serial constraints cleared: no in-flight claim on skills/**. Round-18 siblings hold disjoint surfaces (#5214 six packages + scripts/check-node-esm-load.mjs; #4818 packages/layout + apps/console/src/hooks; #5356 packages/app-shell/src/preview; #5343 content/docs/guide/** + scripts/check-doc-snippet-types.mjs). ⚠️ One region-level overlap with a parked card — see the pin below.

    Direction is settled — ⛔ direction 2 is closed. Per the triage unlock comment above (5345537262): #5125 was adjudicated as enforce-or-remove deletion of the only bind-reading table renderer (merged as PR5338). That forecloses "make data-table read bind" — it would widen the authorable key surface the sibling ruling just declined to widen. If someone wants it, that is a new Feature card through the decision inbox, ⛔ not this PR.

    Scope = direction 1 only: correct the teaching. Replace the data-table + bind example with data-table's real inline data form (or with a type that genuinely reads bind — today only list and tree-view), and delete the useDataScope mechanism sentence, which describes a different component's behaviour.

    Fold #5337 (sub-issue) into this same PR — one Fixes line each. Three sites, one spelling; fixing them separately is how two spellings happen.

    Measured on origin/main bdf8cf76e, 2026-08-20 — the site list is bigger than the cards say

    file data-table blocks cards say
    skills/objectui/guides/schema-expressions.md :377 :377-384 ✔
    skills/objectui/guides/data-integration.md :185 :183-190 ✔
    skills/objectui/rules/protocol.md :100, :109, :130 :128-136 only

    protocol.md holds three data-table blocks, not one. Census all three before deciding what to rewrite; report which of them actually teach bind and which are already fine. A zero on the other two is only a reading if you counter-probe it — grep bind across the whole file and say what you found, rather than reporting "the other two were fine".

    ⛔ Hard pin — do not touch the columns key spelling

    The very lines you are editing (schema-expressions.md:377-384, data-integration.md:185-192) are also the subject of an open census fork on #5120, currently parked at needs-user-decision with the maintainer: those examples spell columns { name, label }, and whether that alias is authored surface or a docs defect is the maintainer's open question, to be decided together with #5350.

    So: fix the binding (that is this card), and leave every columns entry byte-identical to what is on main — whatever spelling it currently carries. The two defects are orthogonal (binding mechanism vs column key spelling) and each belongs to its own card. Writing either spelling here pre-empts a live maintainer decision. If the rewrite you choose genuinely cannot preserve the existing columns block verbatim, stop and report rather than picking a spelling.

    Governed surface

    skills/** is maintainer-merge-only. Open the PR, get it green, ⛔ do not enable auto-merge and do not merge it. Say so in the PR body so no passing seat does it for you.


    Generated by Claude Code

  3. os-support-ai commented on Aug 20, 2026

    @os-support-ai
    Collaborator
    {
      "issue": 5126,
      "status": "done",
      "branch": "claude/issue-5126-data-table-bind-teaching",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5371",
      "premise_still_valid": true,
      "summary": "Direction 1 only, as ordered. All three sites now demonstrate `bind` with `list` (which does call useDataScope) bound to a STRING array — records would render the right number of empty entries, the #4797 trap — and each site names the real readers and says plainly that `data-table` is not one of them. The false 'the table component calls useDataScope(\"customers\")' sentence is gone. schema-expressions.md and data-integration.md keep a `data-table` example in its real inline-`data` form; their `columns` entries are byte-identical to main (they do not appear in the diff at all, git matched them as context), so the #5120 spelling question is untouched. One `columns` line did go and I am flagging it rather than burying it: protocol.md:130's `\"columns\": [...]` placeholder left with the `data-table` node it belonged to — it carried no column-key spelling, and protocol.md is not one of the two files #5120's census fork names. Bounded in-place fix, same defect class, named in the PR body: data-integration.md:143 carried the same over-broad claim unqualified ('Components with `bind: \"customers\"` will then access ...'); one clause qualifies it. Two corrections to my own first draft, both caught by guards I then pinned: the reader list said `object-pivot-table`, which is the component FILE — the registered key is `object-pivot`; and the first repo-wide census script made the fence language tag optional, mis-paired fences and reported zero on origin/main too. Draft PR, no auto-merge, waiting for a maintainer per the governed-surface rule.",
      "tests": "All from the repo root (`pnpm exec vitest run PATH`), never `pnpm --filter PKG test`. Union re-derived and green on the FINAL commit `99d8721a3`. Build artifacts between edit and thing-under-test: NONE on every leg — the root vitest.config.mts aliases every workspace package to its src/, and the guides are read from disk at run time, so no rebuild is needed for any leg to be honest. || NEW PIN packages/components/src/__tests__/skill-guide-data-table-binding.test.tsx: 'Test Files 1 passed (1) / Tests 15 passed (15)', exit 0. It lifts the JSON blocks out of the REAL guide files at run time (doc-sameness), renders them through the real SchemaRenderer (behaviour), and counter-probes each file for a known-present `bind` key so the data-table zero is a reading. || MEASURED, the two numbers the card turns on: retired bind form -> 1 tbody row, `[\"No results foundTry adjusting your filters or search query.\"]`; taught data form -> 2 rows, `[\"Ada Lovelace\",\"ada@example.com\",\"Grace Hopper\",\"grace@example.com\"]`. || REVERSE VERIFICATION, both legs run, both stated, direction = turned red. Guides reverted to origin/main with the test unchanged: 'Tests 9 failed | 4 passed (13 at that revision)', exit 1. Restored: 15/15, exit 0. The 4 that survive the mutation are the 3 counter-probes (main teaches `bind` correctly too, so they MUST pass) plus the empty-state measurement, true on both refs by construction. || SECOND ABLATION on the reader-list guard: `object-pivot-table` put back into schema-expressions.md fails it with '`object-pivot-table` must be registered by exactly one plugin package: expected [] to have a length of 1'; restored, 15/15. || ADJACENT SUITES: vitest run scripts/__tests__/doc-version-claims.test.ts scripts/__tests__/check-skills-paths.test.ts packages/plugin-dashboard/src/__tests__/ObjectDataTable.columnIdentity.test.tsx -> 'Test Files 3 passed (3) / Tests 61 passed (61)', exit 0. || GATES, all exit 0: pnpm --filter @object-ui/components run type-check (script name echoed, not a zero-match run; caught and fixed a TS2882 package self-import on the way); eslint on the new test, 0 errors 0 warnings; check-skills-paths (94/95 resolve, 1 baselined); check-control-bytes (4758 files) plus a manual grep -naP sweep over the changed files, no control bytes; check-package-self-import; check-changeset-presence (empty-frontmatter exemption); check-changeset-fixed; check-changeset-no-major. Note objectui has no scripts/pm/dispatch-gates.mjs, so no path-derived gate set exists to re-derive here; the union above is the derived one.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #5372 (unassigned, label `finding`): the ONLY working route from a provider dataSource into a `data-table` is the `properties` envelope that protocol.md tells authors not to use. Measured through the real renderer with identical columns in all three legs — node-level `data: \"${data.customers}\"` renders the empty state (top-level keys are never expression-evaluated); `properties: { data: ... }` renders all 4 cells (evaluated AND hoisted onto the node); `props: { data: ... }` renders the empty state (evaluated but not hoisted, and the renderer reads schema.data). It is the inverse polarity of the seam #4799 corrected. No fix proposed — it is the decision input if the closed direction 2 is ever weighed again."
      ]
    }

    Census I was asked to measure myself, on origin/main bdf8cf76e — the card list was incomplete and my reading agrees with the correction, with one addition:

    file data-table blocks carried bind verdict
    skills/objectui/guides/schema-expressions.md :377 :377 corrected
    skills/objectui/guides/data-integration.md :185 :185 corrected
    skills/objectui/rules/protocol.md :100, :109, :130 :130 only :130 corrected; the other two are the "No Schema Property Invention" pair (a violation example spelling fields, and its columns counterpart), neither carries bind, both correct as they stand

    Counter-probed, not reported as bare zeros. Grepping each whole file on origin/main for the known-present terms: schema-expressions.md 13 bind lines / 3 useDataScope; protocol.md 5 / 2; data-integration.md 5 / 3. Widened past the three named files: across all 307 markdown and MDX files tracked under content/docs, skills, packages, apps, examples, exactly 3 fenced json blocks paired data-table with a bind key — these three — and 0 remain on the branch, while 8 json blocks still carry a bind key on both refs. The first version of that scan made the fence language tag optional, mis-paired fences, and returned zero on origin/main too; the counter-probe is the only reason that was caught.

    No disagreement with the cards. Two notes for the record: the reader set is wider than "only list and tree-view" once the plugin packages are counted (object-grid, object-kanban, object-chart, object-data-table, object-gallery, object-timeline, object-pivot all call useDataScope(schema.bind)), which is why the guides now name them; and object-pivot, not object-pivot-table, is the registered key.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions