Skip to content

docs(skills): page-builder.md names the channel that publishes expression roots (objectui#9672) - #9997

Draft
os-tesla wants to merge 1 commit into
mainfrom
claude/issue-9672-page-builder-published-scope
Draft

os-tesla wants to merge 1 commit into
mainfrom
claude/issue-9672-page-builder-published-scope

Conversation

@os-tesla

Copy link
Copy Markdown
Collaborator

Fixes #9672

Clause-②: yes

What changed

skills/objectui/guides/page-builder.md only — one guide, seven hunks, net +8 lines (331 → 339 against BASE edbcf1e7a).

  1. Section 4 「Wire renderer and registry cleanly」 step 3 no longer says 「Provide dataSource and contextual data through renderer provider」. It now names ONE channel: PredicateScopeProvider from @object-ui/react — every key of the scope you hand it becomes an expression root (and bind reads the same bag). It also states which roots the renderer adds on its own (record, page), that nothing publishes data, and what SchemaRendererProvider's dataSource still is: the adapter the object-bound blocks fetch through, not an expression root. The provider fence is pointed at, not copied — guides/auth-permissions.md carries it since PR docs(skills): auth-permissions stops teaching dataSource as the data expression root (objectui#9379) #9669.
  2. The four ${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 published userRole」.

Residual ${data. in this file after the change: 0.

The measurement that decided the channel

packages/react/src/SchemaRenderer.tsx, the evaluator that hidden / content / a statistic's value are evaluated on (the new ExpressionEvaluator({ … }) block inside evaluatedSchema):

  • spreads usePredicateScope() — the PredicateScopeProvider context (packages/react/src/hooks/useExpression.ts: PredicateScopeProvider / usePredicateScope, exported through hooks/index.ts and the package index);
  • adds current_user (alias of a published user), record (from RecordContextProvider, only when a row is bound) and page (page variables);
  • binds NO data. The block's own comment: 「data is NOT here, and the absence is the decision (objectui#9308, maintainer ruling 2026-09-13 option B)」.

SchemaRendererContext.dataSource is read by useViewData (the object-bound blocks' adapter) and is no longer an expression root; useDataScope — what bind reads — now walks usePredicateScope() too (same ruling, per its docblock). So under the old step-3 wiring a ${data.metrics.activeUsers} has no root: hidden fails soft (hidden for everyone), a text content / statistic value prints 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' at edbcf1e7a: 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)

reading before (edbcf1e7a) after
skills/objectui/guides/page-builder.md 331 339 (+8, at the cap)
package skills/objectui/**/*.md, 16 files 4,640 4,648

Package spelling: find skills/objectui -name '*.md' -type f piped through cat and wc -l (a git 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, the events bag → action:button). BASE :102–:122 — that hunk plus its leading context — is byte-identical at :109–:129 of this branch (diff empty). 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 SchemaRendererProvider is NOT in page-builder.md (composition → 0 hits in this file at BASE; control SchemaRenderer → 5). It lives in skills/objectui/guides/auth-permissions.md under the heading 「## Provider composition pattern」, an unmarked typescript fence — 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)

  • build closure under the shared lock — pnpm exec turbo run build $(node scripts/check-skill-examples.mjs --build-filter) --concurrency=2VERDICT 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 read pass in --list
  • pnpm 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 approval
  • node 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 naming page-builder.md; it uses a fixture by that name)

pnpm lint not run locally: repo-wide and CI-owned; the diff is one .md outside every eslint population.

Acceptance notes

维护者速读(草稿)

改了什么:只改 skills/objectui/guides/page-builder.md 一个文件,净 +8 行。第 4 节第 3 步原来教读者「通过 renderer provider 提供 dataSource 和上下文数据」,而这条通道在 objectui#9308 之后已不再给表达式发布 data.* 根。现在这一步只点名一条能用的通道:PredicateScopeProvider(@object-ui/react),交给它的 scope 的每个键都成为表达式的根;同时写明渲染器自己只补 recordpage、没有任何东西发布 dataSchemaRendererProviderdataSource 是对象绑定块取数的适配器而不是表达式根。页面自己的四处示例从 ${data.userRole} / ${data.metrics.activeUsers} 改为读宿主已发布的 userRole / metrics,并用一句话写明「宿主发布了这两个键」。

为什么改:照旧文接线的读者,页面不报错但结果是错的:hidden 门对所有人都隐藏,textcontentstatisticvalue${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

…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
@github-actions

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/6475-gantt-block-face-declared.md

  • names skills/objectui/guides/page-builder.mdskills/objectui/guides/page-builder.md — edited by this change

    Maintainer ruling, objectui#6475 (2026-08-27), Option A — enforce as-is, immediately, no warning window (the startup-stage no-gradualism rule, objectstack#12668: transitions do not get phased windows without named external-user evidence, and none exists here). A census of every gantt block reachable through ObjectGanttSchema in this repository — the examples/schema-catalog fixtures, content/docs/plugins/plugin-gantt.mdx, and the published skills/objectui/guides/page-builder.md guide — found zero blocks missing the trio.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with ff0c38473 (merge-base with origin/main): 1 file(s) changed outside .changeset/, read against 1204 pending declaration(s) that publish a body (1763 pending in total). · run

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 045d02959e0aa4b7f2cb4d0c3ca4f4ea62f9a2ee

In-seat review by the domain:skills seat at the contract-review tier (served tier read at seating, objectstack#7623 marker 5738863635) — the lane's record; Clause-②: yes declared on the card claim (5739526152) and in the PR body, needs:contract-review on both carriers (--pair 9997 read C1 half-hung until the seat hung the PR side in this act, then 0). Verified against GitHub (GET /pulls/9997/files: one file, skills/objectui/guides/page-builder.md, +15 / −7) and the fetched branch (origin/claude/issue-9672-page-builder-published-scope at 045d029, base edbcf1e; origin/main has since moved one commit to ff0c384 without touching this guide), ⛔ not against the report: one commit, trailer pair model-free; seven hunks, all in section 3's lead-in and example (:33–:49), section 4 step 3 (:101–:108) and the 「Expression evaluation boundaries」 lead-in and its two examples (:173–:204). Tier H (skills/**): this record is piece ① of the terminal; the PR stays draft for an authorized approval.

① Derived judgments

  • The public-surface claim the guide now makes: expression roots on a page are the keys of the scope handed to PredicateScopeProvider (@object-ui/react); the renderer adds record (bound row) and page (page variables) itself; nothing publishes data; SchemaRendererProvider's dataSource is the adapter object-bound blocks fetch through, not a root. Read on origin/main: packages/react/src/SchemaRenderer.tsx :866 const predicateScope = usePredicateScope(), :938 「⛔ data is NOT here, and the absence is the decision (objectui#9308 …)」, :968–:974 new ExpressionEvaluator({ ...predicateScope, current_user: …user, …{ record: boundRecord }, page: pageVariables }); packages/react/src/hooks/useExpression.ts :36 PredicateScopeProvider, :50 usePredicateScope, read at :175 / :205 / :284 by the widget-tier hooks; context/SchemaRendererContext.tsx :114 reads the same scope (the bind bag — the 9308 changeset: 「predicate scope (usePredicateScope()) instead of walking the injected adapter」). Every sentence the step now states is a reading of that code; no contract widens or narrows — the guide teaches the channel that exists and stops teaching the one that resolves to undefined. Correct per the triage's 判据 (a) and objectui#9308.
  • The four example reads (${userRole !== 'admin'}, ${metrics.activeUsers} ×2, ${metrics.growth}) are true under the prose that now precedes them (「a page whose host published userRole and metrics」 in section 3; 「both examples below read metrics, a root the host published」 before the boundaries examples) — the auth-permissions.md shape (PR docs(skills): auth-permissions stops teaching dataSource as the data expression root (objectui#9379) #9669). Residual ${data. in the file: 0 (seat's grep on the branch; 4 on origin/main). The class is counted again in the PR body at edbcf1e (six files, 45 reads) and only this file is touched — the others are PR docs(skills): move the three published guides off the retired dataSource expression root #9378's and objectui#9380's.
  • The card's 「Provider composition pattern」 item is measured absent from this guide (composition 0 / control SchemaRenderer 5) and located in auth-permissions.md — outside this card's surface; no paragraph invented. Correct.
  • Region fence held: PR docs(skills,AGENTS): teach action:button + actionType, retire the events bag #9592's hunk (@@ -105,18 +105,16 @@, section 5) — base :102–:122 is byte-identical to the branch's :109–:129 (seat's own diff); the two land in either order.
  • Value density, read from the loading agent's seat: the wiring step a page author copies now names the one channel that works and the two roots the renderer adds, and the four examples on the page evaluate instead of printing their own source. Net +8 lines in the guide (331 → 339, exactly the claim's cap), package 4,640 → 4,648.

② Semver level

None owed — skills/** publishes no package; scripts/check-changeset-presence.mjs exit 0 on the branch diff.

③ Boundary flags

  • Deviations (5) read: net +8 at the cap, not under it (accepted — the step needed the channel, the two renderer roots, the absence of data and what dataSource still is); model-free trailer pair (the rule); PR body one byte shorter on store (platform); the first report post aborted by the dev's own pre-write assertion, no write spent (accepted); pnpm lint NOT MEASURED with reason (CI's Lint is success on the head).
  • open_questions: none. out_of_scope_findings (1): the auth-permissions.md 「Provider composition pattern」 fence nests no PredicateScopeProvider — incompleteness, not a false statement; the file is PR docs(skills): gate the usePermissions example on can(), a boolean, and mark its fence (objectui#9671) #9994's (objectui#9671) and that PR is at its terminal awaiting approval, so this rides no PR now; the seat carries it as a note for the next auth-permissions.md take (not one of the three classes; not filed).
  • CI on the head at this record's writing: 24 success, 3 skipped (Test (coverage), its shard matrix, dependabot — conditional on this PR), 5 in progress (Test (shard 1–4/4), Doc Snippet Type Check). Landing waits on the authorized approval in any case and re-reads every check first.

Implemented-by: claude/issue-9672-page-builder-published-scope
Reviewed-by: session_01W5y9kRg1YtYaMQYExVLRc2

VERDICT: PASS


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 045d02959e7bb07f9da9ca36799a34ff53f91dd1

In-seat review by the domain:skills seat at the contract-review tier (served tier read at seating, objectstack#7623 marker 5738863635) — the lane's record; Clause-②: yes declared on the card claim (5739526152) and in the PR body, needs:contract-review on both carriers (--pair 9997 read C1 half-hung until the seat hung the PR side in this act, then 0). Verified against GitHub (GET /pulls/9997/files: one file, skills/objectui/guides/page-builder.md, +15 / −7) and the fetched branch (origin/claude/issue-9672-page-builder-published-scope at 045d029, base edbcf1e; origin/main has since moved one commit to ff0c384 without touching this guide), ⛔ not against the report: one commit, trailer pair model-free; seven hunks, all in section 3's lead-in and example (:33–:49), section 4 step 3 (:101–:108) and the 「Expression evaluation boundaries」 lead-in and its two examples (:173–:204). Tier H (skills/**): this record is piece ① of the terminal; the PR stays draft for an authorized approval.

⚠️ Correction: the record 5739640762 above is VOID — its Head-sha: line carried a mistyped tail (the seat typed the 40-character sha instead of pasting git rev-parse's output). This record is otherwise identical and names the real head, read from git rev-parse 045d02959 on the fetched branch and GET /pulls/9997 head.sha.

① Derived judgments

  • The public-surface claim the guide now makes: expression roots on a page are the keys of the scope handed to PredicateScopeProvider (@object-ui/react); the renderer adds record (bound row) and page (page variables) itself; nothing publishes data; SchemaRendererProvider's dataSource is the adapter object-bound blocks fetch through, not a root. Read on origin/main: packages/react/src/SchemaRenderer.tsx :866 const predicateScope = usePredicateScope(), :938 「⛔ data is NOT here, and the absence is the decision (objectui#9308 …)」, :968–:974 new ExpressionEvaluator({ ...predicateScope, current_user: …user, …{ record: boundRecord }, page: pageVariables }); packages/react/src/hooks/useExpression.ts :36 PredicateScopeProvider, :50 usePredicateScope, read at :175 / :205 / :284 by the widget-tier hooks; context/SchemaRendererContext.tsx :114 reads the same scope (the bind bag — the 9308 changeset: 「predicate scope (usePredicateScope()) instead of walking the injected adapter」). Every sentence the step now states is a reading of that code; no contract widens or narrows — the guide teaches the channel that exists and stops teaching the one that resolves to undefined. Correct per the triage's 判据 (a) and objectui#9308.
  • The four example reads (${userRole !== 'admin'}, ${metrics.activeUsers} ×2, ${metrics.growth}) are true under the prose that now precedes them (「a page whose host published userRole and metrics」 in section 3; 「both examples below read metrics, a root the host published」 before the boundaries examples) — the auth-permissions.md shape (PR docs(skills): auth-permissions stops teaching dataSource as the data expression root (objectui#9379) #9669). Residual ${data. in the file: 0 (seat's grep on the branch; 4 on origin/main). The class is counted again in the PR body at edbcf1e (six files, 45 reads) and only this file is touched — the others are PR docs(skills): move the three published guides off the retired dataSource expression root #9378's and objectui#9380's.
  • The card's 「Provider composition pattern」 item is measured absent from this guide (composition 0 / control SchemaRenderer 5) and located in auth-permissions.md — outside this card's surface; no paragraph invented. Correct.
  • Region fence held: PR docs(skills,AGENTS): teach action:button + actionType, retire the events bag #9592's hunk (@@ -105,18 +105,16 @@, section 5) — base :102–:122 is byte-identical to the branch's :109–:129 (seat's own diff); the two land in either order.
  • Value density, read from the loading agent's seat: the wiring step a page author copies now names the one channel that works and the two roots the renderer adds, and the four examples on the page evaluate instead of printing their own source. Net +8 lines in the guide (331 → 339, exactly the claim's cap), package 4,640 → 4,648.

② Semver level

None owed — skills/** publishes no package; scripts/check-changeset-presence.mjs exit 0 on the branch diff.

③ Boundary flags

  • Deviations (5) read: net +8 at the cap, not under it (accepted — the step needed the channel, the two renderer roots, the absence of data and what dataSource still is); model-free trailer pair (the rule); PR body one byte shorter on store (platform); the first report post aborted by the dev's own pre-write assertion, no write spent (accepted); pnpm lint NOT MEASURED with reason (CI's Lint is success on the head).
  • open_questions: none. out_of_scope_findings (1): the auth-permissions.md 「Provider composition pattern」 fence nests no PredicateScopeProvider — incompleteness, not a false statement; the file is PR docs(skills): gate the usePermissions example on can(), a boolean, and mark its fence (objectui#9671) #9994's (objectui#9671) and that PR is at its terminal awaiting approval, so this rides no PR now; the seat carries it as a note for the next auth-permissions.md take (not one of the three classes; not filed).
  • CI on the head at this record's writing: 24 success, 3 skipped (Test (coverage), its shard matrix, dependabot — conditional on this PR), 5 in progress (Test (shard 1–4/4), Doc Snippet Type Check). Landing waits on the authorized approval in any case and re-reads every check first.

Implemented-by: claude/issue-9672-page-builder-published-scope
Reviewed-by: session_01W5y9kRg1YtYaMQYExVLRc2

VERDICT: PASS


Generated by Claude Code

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

Projects

None yet

2 participants