Repository navigation
docs(skills): testing.md Pattern 5 publishes userRole through the scope channel the renderer reads (objectui#9380) - #10941
Conversation
…cope channel the renderer reads (objectui#9380)
The Pattern 5 fence built a plain bag, handed it to `SchemaRendererProvider`'s
`dataSource`, and gated `hidden: '${userRole !== "admin"}'` on a bare
`userRole` root. Nothing publishes that root: `dataSource` is the CRUD adapter
and, since objectui#9308, no expression root at all. The predicate faults
(`userRole is not defined`), `evaluateCondition` fails soft to `true`, the node
is hidden, and `getByText('Secret')` throws for a reader who copies the example.
The fence now publishes the same keys through `PredicateScopeProvider` — the
channel every sibling guide already teaches — so `${userRole !== "admin"}` is a
real gate. The admin leg is unchanged; a viewer leg is added so the test named
"hides component when hidden expression is true" exercises the hidden branch
once. Two prose lines above the fence name the channel and the fail-soft trap.
Measured on the current renderer (vitest `dom` project, aliased `packages/react/src`)
with the `text` renderer registered: the fence as written failed the admin
assertion (`Unable to find an element with the text: Secret`, body `<div />`);
the corrected fence passes both tests. Scratch tests deleted; no permanent test
added because no existing test pins this guide's examples.
Line readings: `testing.md` 364 -> 369 (+5); `skills/**/SKILL.md` + this guide
501 -> 506 (+5), inside the +6 budget.
Claude-Session: https://claude.ai/code/session_01EBx9rvB7dufCz4at53x35U
Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: ① Derived judgmentsDiff: one file, Prose claim 1 — "Expression roots are the keys of the Prose claim 2 — " Prose claim 3 — "a Fence — imports: Does an agent copying the fence get a passing test? With the Citations: the new prose and the PR body cite by symbol and quoted string, no line addresses; Gate verdicts — the check-runs on this head, read at 2026-09-28T09:14Z: 39 check-runs, 36 ② Semver levelNone — nothing publishes. ③ Boundary flagsDev deviations (six) — each answered:
Out-of-scope findings — answered or escalated:
Governed-surface note: Implemented-by: VERDICT: PASS Generated by Claude Code |
…enders (objectui#9380, patch round 1) Copied verbatim, the corrected fence still threw for a reader whose setup registers nothing: `Unknown component type: text` on both tests. The fence now carries the one side-effect import that registers the renderers, spelled the way page-builder.md spells its plugin imports. Nothing else in the fence moves. Measured on the current renderer (vitest `dom` project, light setup that registers nothing): the fence byte-identical to the published one passes both tests; the same file minus this import fails both with `Unknown component type:` — the control. Scratch files deleted before commit. Line readings: `testing.md` 364 -> 370 (+6); `skills/**/SKILL.md` + this guide 501 -> 507 (+6), exactly the PR budget. Claude-Session: https://claude.ai/code/session_01EBx9rvB7dufCz4at53x35U Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: ① Derived judgmentsDiff: one file, Delta since the earlier record's head Which renderer answers Prose claim 1 — "Expression roots are the keys of the Prose claim 2 — " Prose claim 3 — "a Fence — imports: Does an agent copying the fence VERBATIM get two passing tests? YES on this tree. The fence now carries every import it needs: Citations: the new prose cites by symbol and quoted string, no line addresses; the relative link Gate verdicts — the check-runs on this head, read at 2026-09-28T09:32Z after the last one completed at 09:31:50Z: 39 check-runs, 36 ② Semver levelNone — nothing publishes. ③ Boundary flagsRound-2 deviations (two) — answered:
Round-1 deviations (six) — re-answered on this head: (1) the
Out-of-scope findings — answered or escalated:
Governed-surface note: Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读(终稿)席位 改了什么:只改对外发布的技能指南 为什么改:技能包是 AI 照着写代码的材料,一个照抄即失败的示例等于产品缺陷。dev 在当前渲染器上实测:原示例照抄两个测试都失败,新示例照抄两个都通过;去掉注册那一行则失败(对照)。 风险与代价(含回滚):只改一段示例文本,不碰任何包代码、不发版( 席位意见:建议批准。席位核对了 你要做的:在本 PR 上点 Approve( Generated by Claude Code |
Fixes #9380
Clause-②: no — a published guide's example is corrected to the scope the renderer already publishes; no accept set or public contract surface moves
What changed
skills/objectui/guides/testing.md, «Pattern 5: Component rendering with SchemaRenderer» — one fence and two prose lines above it.users,userRole) toSchemaRendererProvider'sdataSourceand gatedhidden: '${userRole !== "admin"}'on a bareuserRoleroot. Nothing publishes that root:dataSourcecarries the CRUD adapter and, since objectui#9308 landed (852437297b), the renderer binds no expression root from it at all. The predicate faults (userRole is not defined),evaluateConditionfails soft totrue, the node is hidden, andgetByText('Secret')throws for a reader who copies the example.PredicateScopeProvider— the channelauth-permissions.md,schema-expressions.md,data-integration.md,page-builder.mdandrules/protocol.mdalready teach — so${userRole !== "admin"}is a real gate. Thehiddenexpression is unchanged: a bareuserRoleis the right spelling once the host publishes it under that name.// admin should see it). A viewer leg is added withrerender, so the test named "hides component when hidden expression is true" exercises its hidden branch once. Not an inversion: the admin leg still asserts the node is on screen.guides/auth-permissions.md.Measured, not inferred
Scratch vitest files under
packages/components/src/__tests__/— root config,domproject (happy-dom),@object-ui/reactaliased topackages/react/src, so the path exercised is the CURRENTSchemaRendererevaluation memo (configEvaluationScope: theusePredicateScope()spread pluscurrent_user/record/page) driving@object-ui/core'sExpressionEvaluator.evaluateConditionfrom source. The realtextrenderer was registered at module scope (import '../renderers'), which is the reader's own setup per the guide's "Common testing mistakes" section and not this card. All three scratch files were deleted before the commit; nothing permanent was added because no existing test pins this guide's examples (node scripts/markdown-test-inputs.mjs --listnames only tree-wide gates as readers oftesting.md).RED — the fence as written,
textregistered (verbatim):The DOM dump under that error is an empty body holding one empty
div— the node is hidden, not unknown.renders component from schemapassed in the same file, so the only variable left is the root.GREEN — the corrected fence (byte-identical to the published fence except the
describename and the renderer registration import;diffprinted exactly those two hunks). Verbatim except the verbose reporter's angle-bracket separator, spelled›here because GitHub's body sanitizer eats tag-shaped fragments:Copied verbatim with only the imports the fence itself carries (no renderer registered), both tests fail on
Unknown component type: text— the registration point the guide's own "Common testing mistakes" section already states; unchanged here.Line readings (published skill, net budget +6)
skills/objectui/guides/testing.md, whole fileskills/**/SKILL.md(one —skills/objectui/SKILL.md, 137 lines) plus the guide touchedNo re-wrap bought a line: the fence is +2 (the
itblock that gained a leg), the prose is +2, plus one blank line.objectui#9308 — does it change the correct spelling?
The card's «Suggested shape» offered two routes and objectui#9308 (option B, landed as
852437297b, card state completed) removes one of them:data: dataSourceis gone from the evaluator scope, so spelling the gate${data.userRole}against the injected bag would be exactly as wrong as the bare root is today —schema-expressions.mdnow warns that re-publishingdataonly restores an always-false verdict. The route that stands is publishing the name throughPredicateScopeProvider, which is what this PR does; the bare spelling inside the expression stays because that is what a scope-published key looks like.Gates (run locally at
d1fda66e1a)pnpm check:skills-paths→ exit 0 —88/89 stated path(s) resolve across 20 guide file(s); 1 baselinedpnpm check:skill-eval-tokens→ exit 0 —Every must_contain token is taught by its own skill bundle.pnpm check:control-bytes→ exit 0 —scanned 9180 tracked text file(s)pnpm check:new-line-citations→ exit 0 —0 new citation(s)(re-run after the commit)node scripts/check-changeset-presence.mjs→ exit 0 —No source or published contract of a released package changed in this range, so no changeset is owed.(skills/**sits in no package'sfiles[]; no changeset and noskip-changesetlabel to write)node scripts/check-governed-queue-guard.mjs --test skills/objectui/guides/testing.md→ exit 3 —GOVERNED — 1 of 1 path(s)(expected: Tier H, draft only)skills/objectui/**—check-skill-examples,check-skills-paths,check-skill-eval-tokens,doc-version-claims,layered-read-declared-path-4016,check-shell-escape-residue,check-installed-spec-pin-claims,dollar-dialect-alias-census,markdown-test-inputs,skill-guide-provider-envelope→Test Files 10 passed (10),Tests 365 passed (365)pnpm check:skill-examples→ NOT MEASURED locally: exit 2PRECONDITION NOT MET, nodist/in this worktree and the scoped build the gate names spans 30 packages (--dry=text), beyond the foreground budget. Declared to CI:skill-examples.ymlruns on every PR with no path filter. This diff adds no marker and touches no marked fence, so the marked population and its floors are unchanged.check:doc-snippets/check:doc-examples/check:doc-fences— not owed: theirDOCS_ROOTiscontent/docs, andcheck-doc-snippet-types.mjsstates thatskills/objectui/**is claimed by no gate there.Acceptance notes
dataSource, which objectui#7912'sDataSourcetyping rejects for a reader runningtsc(the same TS2740 shape objectui#9346 measured on the docs pages). The corrected fence passes nothing toSchemaRendererProvider, so that latent error leaves with it.维护者速读(草稿)
改了什么 — 发布技能包
skills/objectui/guides/testing.md的「Pattern 5」示例:把示例里当作表达式变量来源的SchemaRendererProvider的dataSource换成PredicateScopeProvider的scope,hidden表达式本身不变;补一条「非管理员看不到」的断言;围栏上方加两行说明。净增 5 行,预算 +6。为什么改 — 读者照抄原示例,第二个测试的断言直接抛错:
userRole没有被任何通道发布为表达式变量,hidden表达式求值失败后按安全默认判为「隐藏」,getByText('Secret')找不到节点。objectui#9308 之后所有姊妹指南都已改成本 PR 的写法,只有这一处漏了。已按当前渲染器实测:改前红、改后绿。风险与代价(含回滚) — 只动一份 markdown,不改代码、不发版、不欠 changeset。风险在文字层面:示例若再次与渲染器脱节会再次误导读者,本次以实测为据。回滚 = revert 这一个 commit。
席位意见 —
你要做的 — 作为
GOVERNED_APPROVERS之一在本 PR 留下一条 APPROVED review;之后由认领席翻 ready 并入队。Session:
https://claude.ai/code/session_01EBx9rvB7dufCz4at53x35UGenerated by Claude Code