Repository navigation
docs: publish each page's own values through the scope channel on the three remaining teaching surfaces - #9376
Conversation
…me the three props the renderer never reads The three remaining teaching surfaces from the objectui#8021 sweep — the root README, the expression guide and the architecture guide — each wrote the page's values onto the `SchemaRenderer` element and read them back under a bare head name. `SchemaRendererProps` declares exactly one prop, `schema`; `data`, `dataSource` and `debug` are forwarded to the component the schema names, so nothing throws, nothing warns, and the expression reaches the screen as the characters the author typed. Both coordinates move together on every site, per objectui#8021 leg D: * the six forwarded look-alikes become the provider that actually carries the value — `PredicateScopeProvider` for the expression scope, `SchemaRendererProvider` for the adapter and for `debug`; * the head names are judged one at a time against the scope the tree builds. Thirty-two stay bare, because after the objectui#9308 ruling the root set is open: every key the host publishes is a root. Five move to `record.*` — the two form-row sites and the three predicates written against a `form` root that nothing in ObjectUI publishes. `content/docs/guide/architecture.md` also carried the one `data.*` gate on these pages. The census could not see it — its classifier held `data` in the ACCEPTED root set — and it is exactly the spelling the ruling retires, so it moves to `record.age` and the guide states the verdict flip: a missing root and a present-but-undefined root are not the same, so a `data.*` gate that used to hide its node on every row now shows it. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
…s, measured
The Expression Errors block claimed `${user.invalidProperty}` yields
`Cannot read property 'invalidProperty' of undefined`. objectui#9297's addendum
flagged that as looking wrong and explicitly left it NOT MEASURED. Measured now,
on the built evaluator, and it is wrong in both directions:
{ user: { name: 'Alice' } } ${user.invalidProperty} => undefined
{} (no user root) ${user.invalidProperty} => "${user.invalidProperty}"
control, same instrument: ${user.name} => "Alice"
Nothing is thrown on either path. A missing MEMBER of a published root renders
as nothing; a missing ROOT renders as the characters the author typed, with one
console line.
Repaired here rather than filed because the same commit series now states, two
sections up, that an unresolvable template is returned as its own source text —
leaving the old sentence would have made the page contradict itself.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzHd6hDYatoDn17BuwKxnZ
…s-scope-names Base-only sync: brings the branch onto a main that contains 8524372 (feat(react)!: unbind the data-source adapter from the expression scope). No file owned by this pull request is modified by this commit. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
ADOPTED — the FAIL at
|
Two sentences this branch added taught silence on a path that is not
silent. Measured just now on the built evaluator
(`packages/core/dist`, console captured, one instance per leg):
{} (no user root) ${user.name} => "${user.name}" 1 console.warn
{ user: { name: 'Alice' } } ${user.invalidProperty} => undefined 0 lines
{ user: { name: 'Alice' } } ${user.name} => "Alice" 0 lines
harness control console.warn(sentinel) => fires 1 line
The line is `Failed to evaluate expression: ...` from `reportEvaluationFault`
in `packages/core/src/evaluator/ExpressionEvaluator.ts`, which falls back to
`console.warn` whenever the caller supplies no `onFault`. There is no
dev-only gate on it, and the six `evaluator.evaluate(...)` call sites in
`packages/react/src/SchemaRenderer.tsx` that resolve `content`, `properties.*`
and `props.*` all pass no options, so the doc-relevant path is exactly the
built-in warn. The one-per-authored-source ceiling in that same function is
why the count is one line and not one per render.
This branch already stated the true half two sections down in the expression
guide's Expression Errors table — "the template's own source text, and one
line on the console" — so the page contradicted itself inside one diff.
Both sentences now carry that same phrasing rather than new wording.
`content/docs/guide/schema-rendering.md` carries the same claim at the same
head; it is outside this pull request's file set and is left byte-identical.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
⛔ Correction — the review's minor ③c was WRONG, and this seat propagated it. Carriers re-hung on
|
⛔ The PASS at
|
维护者裁决 —— 独立复核对的判据改为「独立测量」,⛔ 不再是「session id 不同」
维护者原话(今日 PM 会话,逐字)
判据随之改为:复核员是否用自己的仪器独立测量,⛔ 而不是它的 这条裁决推翻了什么本席此前在 依它被压住的记录一并解冻:
⭐ 为什么这个判据比旧的更严,而不是更松旧判据数的是身份,新判据数的是证据。今天板上最强的两份复核恰好都是「不干净」的对:
⇒ 一个偏向自己席位的复核员,不会跑去在自己席位的 PR 里找覆盖漏洞然后真找到一个。⭐ 独立性由它做了什么测量来证明,不由它的签名来证明。 从此刻起的执行规则
|
ADOPTED — the PASS at
|
| ① 同形 PASS、档位对 | ✅ | 5654235635,head 049a797d4c,default 档(Clause-②: no) |
② --pair exit 0 |
✅ | 现跑 --pair 9376 ⇒ EXIT=0,双载体一致 |
| ③ 全绿 | ✅ | 29 success / 3 skipped / 0 failure / 0 cancelled。⭐ Bundle Analysis 不在本 PR 的 check 集里(docs-only 路径过滤,total_count 32 == 返回 32),所以那笔全板欠账⛔ 不适用于此 |
这份复核凭什么算独立测量
⛔ 它没有「读了对方报告并同意」:
- ① 对整类假从句做 20 个换行容忍模式的普查,三个自有文件 + 存储正文全部读 0,并在修复前的 head 上跑正对照(
nothing logged在 README.md 读 1、nothing warns在 expressions.md 读 1)—— ⭐ 仪器被证明是活的,那些零才是读数。 - ② 在自己的工作树里重建
packages/core/dist并捕获六条 console 通道,自己复现了三行行为表,外加一条必须响的 harness 对照和第二个缺失根的腿。 - ③ 「一行」这个计数它去查了去重键(
JSON([site, source]),进程全局),并给出边界:N 个不同的作者源 ⇒ N 行(README 自己的 Basic Usage 块作者 3 个、实测 3 行)。 - ⑤ 把正文里发布的重导命令逐字跑了一遍(
PIPESTATUS 0 0 0 0),六处内容引用全部解析到具名章节 和 具名键,并在今天的 main 上复验。
⭐ 而它最有价值的一条,是逆着自己的判定报出自己的对不干净(其 ⑥),并要求本席按「坏」而不是「弱」定价 —— 那正是新判据要奖励的行为。
已知欠项,⛔ 不压落地
- ③b 正文里那六处站点的行号是陈旧的(被 objectui#9369 挤走约 11 行)—— ⛔ 已按内容引用重写,不再写行号。
- ⑦ 正文「Inherited reds」那段不可重导(
Bundle Analysis根本不在本 PR 的 check 里;Doc Snippet Type Check在此 head 上是 success)。stale-but-dated,标题自带20831dc1d出处 ⇒ 与 objectui#9279 的 Tests 段同一处置。 content/docs/guide/schema-rendering.md上同一句假话是 main 上原有的,随 objectui#9297 那六处残留站点一起落,记录在5654085707。
Generated by Claude Code
Part of #9297.⚠️ Deliberately not a closing keyword: this repair covers the three surfaces that card's dispatch scoped, and the card's own addendum (comment
5646840050) measured six more sites oncontent/docs/guide/schema-rendering.md—statusx2,loading,items,errorx2 — which are out of scope here. PR #9369 has since landed onmainand moved none of them. They are cited below by content, never by a line address — objectui#8875's convention, and the AGENTS.md #9 class: a cross-file line number is derived once and re-derived never, and these six have already shifted under an earlier citation of them.content/docs/guide/schema-rendering.md### Conditional Expressionscardnode's"title"and its"description", both opening${status === 'active' ? …### Loading Statesspinner's"visibleOn": "${loading}"### Empty Statesemptynode's"visibleOn": "${items.length === 0}"### Error Statesalert's"visibleOn": "${error}", and the"content": "${error.message}"in itsbody⛔ Do not trust that table either — re-derive the set. This prints the head name of every expression on that page, multi-line templates included, and the
status,loading,itemsanderrorrows are the six:${statustwo-token sequence is not that instrument and undercounts this page:${sits alone at the end of its line in every multi-line template, so the head name lands on the next line and a same-line pattern cannot see it. That half stays open.What was wrong, and what moved
SchemaRendererPropsdeclares exactly one prop,schema. Adata,dataSourceordebugwritten on the element is forwarded to the component the schema names — not read, not refused. Nothing throws, there is one line on the console, and the expression reaches the screen as the characters the author typed.Per objectui#8021 leg D, moving only the wiring produces a page that reads as repaired and still prints raw source. So both coordinates move together on every site: the wiring becomes the provider that actually carries the value, and every head name on the page is judged against the scope the tree builds.
Re-measured census, with the card's own lit control
Measured on this branch's base
69aa9c017with the card's classifier — SchemaRenderer elements matched with a word boundary after the name, soSchemaRendererProvideris excluded by construction.content/docs/guide/schema-rendering.md(out of scope)packages/react/README.md(out of scope)content/docs/guide/expressions.mdcontent/docs/guide/architecture.mdREADME.md(repo root)⭐ The control reproduces the card's 18 exactly — and shows the 18 is not a count of elements. Three of them are
SchemaRendererMENTIONS insidedoc-snippet: fragmentHTML comments onexpressions.md, which the regex cannot tell from an element. Strip HTML comments first and the base has 15 real JSX elements, not 18. The tag-shaped count falls to 15 here only because those three comments were rewritten; no renderer element was added or deleted (real elements: 15 → 15).Per-site judgement — 37 bare head names, individually judged
The ruling on objectui#9308 (option B) changed the question. Before it, the renderer bound a closed five-name root set, so "head name not in the set" was close to a verdict. After it, the root set is open: every key the host publishes through
PredicateScopeProvideris a root. ⇒ the test is no longer is this name in the set, it is does the page publish this name, and does it say so.The rule applied, stated once so each row can be checked against it: a head name moves to
record.when the passage says the value is the row the surface is bound to; it stays bare when the passage presents it as a value the host computed and published.Moved — 5 sites
expressions.md:148disabledOnformformis not a root on any tier; nothing in ObjectUI publishes one. Rewritten torecord.status.expressions.md:439Dependent Fieldsformrecord.country.expressions.md:470Computed Fieldsformrecord.price * record.quantity.architecture.md:247Conditional Renderingformvisiblerewritten tocurrent_user.role— the ambient root the host'sExpressionProviderreally publishes.architecture.md:248Conditional Renderingformdisabledrewritten torecord.status.Judged legitimate, left bare — 32 sites
expressions.mdx8usersexpressions.md:172settingsuser, by the provider the block now mounts.expressions.mdx2priceexpressions.mdscore,count,total,itemsexpressions.mdx2statusrecord.— that would assert a row context the passage never establishes.expressions.mdx2taskexpressions.md:567formatCurrencyevaluateExpressionis handed its own context. Legitimate by construction. Its surrounding prose was still wrong and is repaired (see below).expressions.md:612adultUsersScoreexpressions.md:621,:626x,isAdminarchitecture.mdx2ordersREADME.mdx7statsPredicateScopeProvider.expressions.mditem,indexexpressions.mdMath,new⭐ A site the census could not see — and it is the one the ruling breaks
content/docs/guide/architecture.md:55authoredvisible: "${data.age > 18}". The census classifier helddatain the accepted root set, so this site was invisible to the offender column — anddatais precisely the root objectui#9308 retires.Measured on the built evaluator (control and both legs in the "Verification" section): a missing root and a present-but-undefined root are not the same. With
{ data: undefined }the predicate isfalse; with nodatakey at all it is unevaluable and this surface fails soft totrue. ⇒ adata.*gate authored from these pages used to hide its node on every row and now shows it. The site moves torecord.age(the runtime layer's canonical root, ADR-0089 D3) and the guide states the flip in the migration note, rather than only renaming a provider.The Debug Mode block — both wrong props, not one
expressions.md's Debug Mode block wrotedata={…}anddebug={true}on the element.debugis read off the provider context (context?.debug || context?.debugFlags?.enabled), so both were forwarded and neither did anything. The block is now aSchemaRendererProvidermount (withdataSource={null}, since that prop is required and this mount is about the flag), and the prose names the mechanism for both props.Adjacent to it, the Custom Functions passage still stated the old scope verbatim — "the provider's data source (as
data), the host scope and page variables". That sentence is what the ruling deletes; it is rewritten in the same commit, because leaving it would have contradicted the new Data Context table on the same page.Shape
Matched to PR #9369, which moved the equivalent teaching on the two surfaces this card excludes: publish host values under a real name through
PredicateScopeProvider, read them by that name, and state thatdataSourceis the adapter and not a root.Changeset
Not owed, by measurement rather than by assumption:
Acceptance notes
Observed while judging these pages, noted, not filed:
AGENTS.md§3 quotes the same retired spelling this PR repairs atarchitecture.md:55—expression eval ("visible: "${data.age > 18}"")in the@object-ui/coretopology row. Not touched:AGENTS.mdis a governed surface, and one path there would move this whole PR to the human-merge route. The carrier would be whoever next edits that table.content/docs/guide/expressions.md:226/:242author${users}onlist.items, a key with no carriage row — reported (report-only) bycheck-doc-expression-carriage. Pre-existing and unchanged by this PR; the gate's own header routes this class to objectui#7440 / finding(examples,docs): thecolorkey three catalogtextnodes author — and the docs page teaches — is declared by nothing and read by nothing #7444 / finding(docs):docs/ARCHITECTURE.mdteaches theObjectRendererphantom in 3 blocks — third file, anddocs/**is in no gate's scan surface #7838.content/docs/guide/expressions.mdExpression Errors claimed an invalid expression yieldsCannot read property … of undefined. The card's addendum flagged it as NOT MEASURED. It is measured below, it is wrong in both directions, and it is repaired here under the bounded in-place carve-out rather than filed: the first commit states two sections up that an unresolvable template is returned as its own source text, so leaving the old sentence would have made the page contradict itself in the same pull request.The two behaviours a reader is now told about, measured
Both legs run against the built evaluator (
packages/core/dist), the same artefactcheck:doc-snippetsresolves against, each with a control that fires.Leg 1 — the verdict flip. At the visibility layer (
evaluateCondition, the layer avisible/visibleOngate uses):⇒ a
data.*gate authored from these pages used to hide its node on every row and now shows it. One layer down, on the rawExpressionEvaluator, the missing-root case returns the template's own source text — which is the interpolation half of the same fact. Both halves are in the migration note.Leg 2 — what an unresolvable expression really does (the card addendum's NOT-MEASURED item):
⇒ nothing is thrown on either path. The guide said
Cannot read property 'invalidProperty' of undefined; that is false whether or not the root exists.Leg 3 — a bare head name IS a root when the host publishes it, which is what makes 32 of the 37 sites legitimate:
Verification
All runs at head
20831dc1d, heavy ones serialised through the shared verify lock.pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2Tasks: 35 successful, 35 total·BUILD EXIT=0pnpm check:doc-snippetsSemantic phase: 650 of 650 block(s) judged, 3 failed.·EXIT=1— ⭐ all three are the inherited ones, see belowpnpm check:doc-fencesEXIT=0— every TypeScript block in 227 document(s) fenced ts/tsx/typescriptnode scripts/check-doc-component-types.mjsEXIT=0— every documented component type is registerednode scripts/check-doc-example-ids.mjsEXIT=0— 414 real reference(s) resolvenode scripts/check-doc-links.mjsEXIT=0— links valid across 17 scan rootsnode scripts/check-control-bytes.mjsEXIT=0— 7539 tracked text file(s)node scripts/check-changeset-presence.mjsEXIT=0— no changeset owednode scripts/check-changeset-claims.mjsEXIT=0(report-only)node scripts/check-doc-expression-carriage.mjsEXIT=0(report-only); its two hits onexpressions.md(list.itemsauthoring${users}) are pre-existing and unchangednode scripts/check-governed-queue-guard.mjs --test(the three paths)✅ NOT GOVERNED — 3 path(s) checked against 5 governed surface(s); none matchedpnpm exec vitest run(6 files)Test Files 6 passed (6)·Tests 112 passed (112)·EXIT=0check:doc-snippets' own controls all fired in that run, so the reading is a reading and not a degraded harness:resolutionresolved@object-ui/typesto the builtdist/index.d.ts,sentinelproduced TS2305,positiveproduced 0.Named witnesses. Derived by hand from
scripts/markdown-test-inputs.mjs, not guessed:packages/components/src/__tests__/page-body-single-node-8310.test.tsxreads the rootREADME.md(it asserts the Basic Usage schema literal still spells its child listchildren, carriestype: "grid"and threetype: "statistic", and the three labels) and four tests walkcontent/docs/**. The objectui#8021 pin was run too, even though itsTEACHING_SURFACESare the two documents this PR does not touch. All green.Inherited reds — named, not repaired.
content/docs/guide/schema-rendering.md:99,:434andpackages/react/README.md:73, all TS2740, all on the two surfaces this PR must not touch. They are objectui#9346 verbatim, and PR feat(react)!: unbind the data-source adapter from the expression scope, and pointbindat the scope channel #9369 is what moves them.mainwith chore(deps): runpnpm dedupe --lockfile-onlyon an untouched main — the measurement (objectui#9215) #9316, a maintainer decision.Drafted by the
os-devseat in sessionsession_01UzHd6hDYatoDn17BuwKxnZ— attribution repeated as prose here because the footer block below does not reliably survive a later edit.Generated by Claude Code