docs(skills): auth-permissions stops teaching dataSource as the data expression root (objectui#9379) - #9669
Merged
Conversation
…ta` expression root (objectui#9379) The 2026-09-13 maintainer ruling on objectui#9308 (option B) stopped `SchemaRenderer` publishing the injected `DataSource` adapter as the expression root `data`. This guide still taught both halves: flags derived "in the dataSource object", a scope table sourcing `data` from "the `dataSource` passed to `SchemaRendererProvider`", and a trap paragraph whose recommended spelling is the one that now fails. The document is what is wrong here, not the runtime: the guide is moved onto the channel that does publish roots, `PredicateScopeProvider`, in the same shape PR #9369 used for `content/docs/guide/schema-rendering.md` and `packages/react/README.md`. - permission flags are published as an ambient scope and read by the names they were published under; - the scope table gains a `record` row (ADR-0089 D3 makes `record` the runtime-layer row root) and states that `data` is a root only when the host publishes one; - the trap paragraph is re-measured on the built evaluator: a name nothing published makes a predicate fail soft to `true` (the button is hidden for every user), while a text key hands back its own source characters. One bounded repair inside the same paragraph: the flag example derived its booleans from `check(...)`, which answers a `{ allowed, … }` object. An object is truthy, so `${!flag}` was permanently `false` and the gate showed the button to everyone. The example now publishes `can(...)`, which answers a boolean. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015h79niBMyoB1xcaQje3uiz
…`dist` path (objectui#9379) `Skill Guide Path Check` went red on the first push of this branch while `node scripts/check-skills-paths.mjs` was green locally, and the gap is the gate's own premise: its workflow needs "no install and no build — a checkout plus one `node` call", and it resolves every `packages/…` code span with `existsSync`. The new measurement paragraph cited `packages/core/dist`, which exists only in a tree someone has built — so the local run resolved it and the CI checkout could not. The citation now names the package instead of the build output. The gate's own count moves 89 -> 88 stated paths, which is the one token this commit removes. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015h79niBMyoB1xcaQje3uiz
This was referenced Sep 17, 2026
os-zhuang
approved these changes
Sep 17, 2026
os-zhuang
marked this pull request as ready for review
September 17, 2026 11:12
This was referenced Sep 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #9379
⛔ Governed surface — this PR stays a DRAFT.
scripts/check-governed-queue-guard.mjs --test skills/objectui/guides/auth-permissions.mdexits 3 and prints: "One governed path governs the WHOLE pull request … Park it as a DRAFT and leave the merge to the maintainer", namingGOVERNED_APPROVERS: os-zhuang, hotlong. No ready-flip, no queue, no auto-merge from this seat.What is repaired
The 2026-09-13 maintainer ruling on objectui#9308 (option B) stopped
SchemaRendererpublishing the injectedDataSourceadapter as the expression rootdata.skills/objectui/guides/auth-permissions.mdstill taught both halves of the retired wiring. The document is what was wrong — the runtime is right — so the guide is moved onto the channel that does publish roots,PredicateScopeProvider, in the same shape PR #9369 used forcontent/docs/guide/schema-rendering.mdandpackages/react/README.md.recordrow (ADR-0089 D3 makesrecordthe runtime-layer row root) and now states thatdatais a root only when the host publishes one;The premise, checked rather than relayed
packages/react/src/SchemaRenderer.tsxcarries the decision in its own words: "datais NOT here, and the absence is the decision (objectui#9308, maintainer ruling 2026-09-13 option B)". Nothing in this PR asks fordataSourceto become a real root — that would widen a published surface. Prose only; no package source is touched.Re-measured on the built evaluator, not remembered
packages/core/dist(built from this branch's base,cf601fff6), over the guide's own gate${!canDeleteContacts}and itsdata.-rooted predecessor:evaluateConditionevaluateExpression${!data.canDeleteContacts}{}— no root at alltrue${!data.canDeleteContacts}${!data.canDeleteContacts}{ data: {} }— adapter-shapedtruetrue${!data.canDeleteContacts}{ data: { canDeleteContacts: true } }falsefalse${!canDeleteContacts}{ canDeleteContacts: true }— published as a rootfalsefalse${!canDeleteContacts}{}true${!canDeleteContacts}Two consequences the old paragraph could not state: a bare name does resolve when the host publishes it as a root (so the old "reachable only under the
data.root" sentence is now false in its own right), and the predicate layer fails soft totruewhile the interpolation layer prints the characters you typed. Both are in the new text.One bounded repair in the same paragraph
The flag example derived its booleans from
permissions.check(...), which answers a{ allowed, … }object. An object is truthy, so${!canDeleteContacts}was permanentlyfalseand the gate showed the button to every user — the mirror image of the trap the page warns about. The example now publishespermissions.can(...), which answers a boolean, and the guide says why. Without this the repaired example would be untrue on its own terms.The class, re-derived (⛔ triage's "fourth" is not relayed)
Instrument, run on this branch's base
cf601fff6: every trackedskills/**/*.md,content/docs/**/*.md,packages/*/README.mdandREADME.md; every line namingdataSource, judged against a ±4-line window for a teaching token (${data, adata.root,bind,useDataScope,scope) and for a correction token (PredicateScopeProvider, "not an expression root", objectui#9308, "the ADAPTER"). Raw hits were then adjudicated by hand, because the raw signal does not distinguish the class from the unrelatedPageComponentSchema.dataSourceelement-data-source key.Members of the class (5):
skills/objectui/guides/data-integration.mdskills/objectui/guides/schema-expressions.mdskills/objectui/rules/protocol.mdskills/objectui/guides/auth-permissions.mdskills/objectui/guides/testing.md⭐ A sixth candidate, reported and not folded in:
skills/objectui/guides/page-builder.md— its integration sequence says "ProvidedataSourceand contextual data through renderer provider" and every schema example on the page then reads${data.metrics.activeUsers}/${data.userRole}. It names no other channel, so a reader wires the retired one. On a governed surface every extra file widens what a human has to approve, so it is left for its own card.Control, same instrument, same run:
content/docs/guide/architecture.mdandcontent/docs/guide/expressions.mdwere surfaced by the identicaldataSource-plus-teaching-window query and both teach the correct root ("SchemaRendererProvider'sdataSourceis not an expression root"), so the instrument discriminates and the count above is a reading rather than an empty query. Adjudicated not in the class, also by the same run:content/docs/guide/{ci-cd-pipeline,data-source,user-state-persistence}.md,content/docs/rfcs/0001-clipboard-paste.md,packages/{plugin-detail,plugin-list,react}/README.md— every one of those names the adapter's own methods or the per-elementdataSourcespec key, neither of which is this class.Gates — each verdict is the gate's own line
node scripts/check-skill-examples.mjsMarked: 15 ts fence(s) (floor 13), 70 json fence(s) (floor 70);Semantic phase: 15 of 15 ts fence(s) judged, 0 failed. The onetsxfence this PR adds is inside that 15.node scripts/check-skills-paths.mjs89/90 stated path(s) resolve across 20 guide file(s); 1 baselinednode scripts/check-skill-eval-tokens.mjsnode scripts/check-changeset-presence.mjsnode scripts/check-new-cross-file-line-citations.mjs0 new citation(s), enforcement report-onlypnpm check:control-bytesscanned 7788 tracked text file(s); plus a directgrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over the changed file, exit 1 (no match)pnpm exec vitest run packages/components/src/__tests__/skill-guide-provider-envelope.test.tsx scripts/__tests__/check-skill-eval-tokens.test.ts scripts/__tests__/check-skill-examples.test.ts scripts/__tests__/check-skills-paths.test.tsTest Files 4 passed (4),Tests 201 passed (201)The four test files are the ones
node scripts/markdown-test-inputs.mjs --listnames as readers ofskills/objectui/**and.claude/skills/**. ESLint is not owed by this diff:eslint.config.jsdeclares no markdown surface, andpnpm lintis CI's repo-wide run either way. Build:turbo run build --concurrency=2 $(node scripts/check-skill-examples.mjs --build-filter)—29 successful, 29 total— so the fences above were judged against builtdist/*.d.ts.Governed-surface size readings
skills/objectui/guides/auth-permissions.mdskills/**/*.md)One file, one section. The added lines are the measured verdict table, the
recordrow, and onetsxfence that the examples gate now type-checks; a second scope fence was drafted and dropped as duplicate teaching.Acceptance notes
noted, not filed: skills/objectui/guides/auth-permissions.md's provider-composition example still nests onlySchemaRendererProvider, with noPredicateScopeProviderbeside it. It is not false — the adapter belongs there — but a reader copying it gets no scope. Carrier: whoever takes thepage-builder.mdcard above, which needs the same nesting shown once.维护者速读(草稿)
改了什么 —— 只改一份已发布技能指南
skills/objectui/guides/auth-permissions.md的「表达式可见性」与「表达式作用域」两节。把权限标志的发布通道从已退休的SchemaRendererProvider dataSource改成PredicateScopeProvider,作用域表补上record行,并按实测重写那段陷阱说明。⛔ 不动任何运行时代码。为什么改 —— 2026-09-13 您对 objectui#9308 的裁决(选项 B)已经让渲染器不再把注入的适配器发布为表达式根
data;这份指南两半都还在教。它按人读文档的速度持续制造错写法,并且它 推荐 的那个写法今天同样失败,失败方式还和它自己警告的那个不同。风险与代价(含回滚) —— 纯文档,风险面是「教得对不对」,不是运行时。三道技能门禁(examples / paths / eval-tokens)各自的判定行都在上表,均为 exit 0;changeset 门禁自己判定无需 changeset。回滚 = revert 这一个 commit,无迁移、无发版影响。⚠️ 顺带修掉同段里一处独立错误:示例用
check(...)(返回对象,恒真)当布尔标志,改成can(...);不改它,新示例自己就是假的。席位意见 ——
你要做的 —— 这是受管面:PR 保持 draft,合并权在您。需要
os-zhuang/hotlong其一的 APPROVED review,或由您直接人工合并(人工合并本身即评审记录)。另外请裁决上面那个第六个候选文件page-builder.md是否单开一卡 —— 本 PR 刻意没有把它折进来。Generated by Claude Code