docs(skills): page-builder.md names the channel that publishes expression roots (objectui#9672) - #9997
docs(skills): page-builder.md names the channel that publishes expression roots (objectui#9672)#9997os-tesla wants to merge 1 commit into
Conversation
…sion roots
Step 3 of "Wire renderer and registry cleanly" told a reader to provide
`dataSource` and contextual data through the renderer provider, and the
page's own examples then read `${data.userRole}` / `${data.metrics.*}`.
After objectui#9308 the renderer's evaluator binds no `data` root, so a
copied example fails silently: a `hidden` gate hides for everyone, and a
`text` content / `statistic` value prints its own source text.
The step now names one channel, PredicateScopeProvider from
@object-ui/react (every key of `scope` is a root), states the roots the
renderer adds itself (`record`, `page`), and what the provider's
`dataSource` still is. The four example reads use roots the prose says
the host published (`userRole`, `metrics`). Section 5 is untouched.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W5y9kRg1YtYaMQYExVLRc2
|
changeset-claim-re-read
|
Contract reviewServed-tier: In-seat review by the ① Derived judgments
② Semver levelNone owed — ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Contract reviewServed-tier: In-seat review by the
① Derived judgments
② Semver levelNone owed — ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #9672
Clause-②: yes
What changed
skills/objectui/guides/page-builder.mdonly — one guide, seven hunks, net +8 lines (331 → 339 against BASEedbcf1e7a).dataSourceand contextual data through renderer provider」. It now names ONE channel:PredicateScopeProviderfrom@object-ui/react— every key of thescopeyou hand it becomes an expression root (andbindreads the same bag). It also states which roots the renderer adds on its own (record,page), that nothing publishesdata, and whatSchemaRendererProvider'sdataSourcestill is: the adapter the object-bound blocks fetch through, not an expression root. The provider fence is pointed at, not copied —guides/auth-permissions.mdcarries it since PR docs(skills): auth-permissions stops teachingdataSourceas thedataexpression root (objectui#9379) #9669.${data.…}reads the page's own examples made (BASE :43, :47, :179, :193) now read roots the surrounding prose says the host published:${userRole !== 'admin'},${metrics.activeUsers},${metrics.growth}. Two short sentences carry the publication claim (section 3's lead-in and the 「Expression evaluation boundaries」 lead-in), the same shape as auth-permissions.md's 「a page whose host publisheduserRole」.Residual
${data.in this file after the change: 0.The measurement that decided the channel
packages/react/src/SchemaRenderer.tsx, the evaluator thathidden/content/ astatistic'svalueare evaluated on (thenew ExpressionEvaluator({ … })block insideevaluatedSchema):usePredicateScope()— thePredicateScopeProvidercontext (packages/react/src/hooks/useExpression.ts:PredicateScopeProvider/usePredicateScope, exported throughhooks/index.tsand the package index);current_user(alias of a publisheduser),record(fromRecordContextProvider, only when a row is bound) andpage(page variables);data. The block's own comment: 「datais NOT here, and the absence is the decision (objectui#9308, maintainer ruling 2026-09-13 option B)」.SchemaRendererContext.dataSourceis read byuseViewData(the object-bound blocks' adapter) and is no longer an expression root;useDataScope— whatbindreads — now walksusePredicateScope()too (same ruling, per its docblock). So under the old step-3 wiring a${data.metrics.activeUsers}has no root:hiddenfails soft (hidden for everyone), atextcontent/statisticvalueprints its own source text — the card's silent failure, reproduced by reading rather than asserted.useExpression/useCondition(the widget tier) merge the same published scope under the caller's local context, so the roots are the same on both tiers.Class count, re-derived (⛔ not copied forward)
git grep -c '\${data\.' -- 'skills/objectui/**/*.md'atedbcf1e7a: architecture.md 1 · data-integration.md 2 · page-builder.md 4 · schema-expressions.md 21 · testing.md 4 · rules/protocol.md 13 — six files, 45 reads. Only page-builder.md is touched here: data-integration.md / schema-expressions.md / rules/protocol.md are PR #9378's (objectui#9370); testing.md is objectui#9380's; auth-permissions.md was repaired by PR #9669 and reads 0.Line readings (the PM's budget: net ≤ +8 in the file)
edbcf1e7a)skills/objectui/guides/page-builder.mdskills/objectui/**/*.md, 16 filesPackage spelling:
find skills/objectui -name '*.md' -type fpiped throughcatandwc -l(agit ls-files 'skills/objectui/**/*.md'glob skips the two top-level files and reads 4,439 — not the figure used).Region fence — open PR #9592 (objectui#7945)
PR #9592's only hunk on this file is
@@ -105,18 +105,16 @@(section 5, theeventsbag →action:button). BASE :102–:122 — that hunk plus its leading context — is byte-identical at :109–:129 of this branch (diffempty). Nothing here touches section 5, so the two land in either order.The card's 「related」 item
The 「Provider composition pattern」 example that nests only
SchemaRendererProvideris NOT in page-builder.md (composition→ 0 hits in this file at BASE; controlSchemaRenderer→ 5). It lives inskills/objectui/guides/auth-permissions.mdunder the heading 「## Provider composition pattern」, an unmarkedtypescriptfence — a file outside this card's surface (PR #9994 / objectui#9671 holds it). Not touched here; handed to the seat in the dev report.Gates (exit captured before any pipe; the gate's own verdict line quoted)
pnpm exec turbo run build $(node scripts/check-skill-examples.mjs --build-filter) --concurrency=2→VERDICT command-exit 0(29/29 cached, shared worktree cache)node scripts/check-skill-examples.mjs --self-test→ exit 0, 「60 cases pass」pnpm check:skill-examples→ exit 0: 「Semantic phase: 15 of 15 ts fence(s) judged, 0 failed. JSON phase: 70 fence(s) parsed, 0 failed.」 — all ten marked page-builder.md fences readpassin--listpnpm check:skill-eval-tokens→ exit 0: 「Every must_contain token is taught by its own skill bundle.」 (no eval touched)pnpm check:skills-paths→ exit 0 (88/89 resolve, 1 baselined)pnpm check:new-line-citations→ exit 0 on the committed head: 「0 new citation(s)」pnpm check:control-bytes→ exit 0 (8061 files)node scripts/check-governed-queue-guard.mjs --test skills/objectui/guides/page-builder.md→ exit 3, 「GOVERNED — 1 of 1 path(s)」 — expected: Tier H, this PR stays draft until an authorized approvalnode scripts/check-changeset-presence.mjs→ exit 0, no changeset owed (skills/**is not published source)pnpm exec vitest run scripts/__tests__/check-skill-eval-tokens.test.ts→ exit 0, 36 passed (the only test namingpage-builder.md; it uses a fixture by that name)pnpm lintnot run locally: repo-wide and CI-owned; the diff is one.mdoutside every eslint population.Acceptance notes
PredicateScopeProvider, so a reader copying it gets no expression scope — incompleteness, not a false statement. 承接者: the seat, since PR docs(skills): gate the usePermissions example on can(), a boolean, and mark its fence (objectui#9671) #9994 holds that file.维护者速读(草稿)
改了什么:只改
skills/objectui/guides/page-builder.md一个文件,净 +8 行。第 4 节第 3 步原来教读者「通过 renderer provider 提供dataSource和上下文数据」,而这条通道在 objectui#9308 之后已不再给表达式发布data.*根。现在这一步只点名一条能用的通道:PredicateScopeProvider(@object-ui/react),交给它的scope的每个键都成为表达式的根;同时写明渲染器自己只补record与page、没有任何东西发布data、SchemaRendererProvider的dataSource是对象绑定块取数的适配器而不是表达式根。页面自己的四处示例从${data.userRole}/${data.metrics.activeUsers}改为读宿主已发布的userRole/metrics,并用一句话写明「宿主发布了这两个键」。为什么改:照旧文接线的读者,页面不报错但结果是错的:
hidden门对所有人都隐藏,text的content与statistic的value把${data.metrics.activeUsers}这串字符原样打到页面上。这是 objectui#9379(auth-permissions.md,PR #9669 已修)同一类问题的又一个成员;修法照抄那次的形状,不照抄字句。风险与代价(含回滚):纯文档改动,不动任何包源码、不发版、不欠 changeset;
check:skill-examples对本文件十个标记示例全部通过。与在途 PR #9592(改同文件第 5 节)区域不相交,先后合并都干净。回滚 = revert 这一个 commit。席位意见:(留空)
你要做的:
skills/**是受管面,本 PR 停在 draft;由os-zhuang/hotlong之一给一条 APPROVED review 后,认领席落地。Generated by Claude Code