Repository navigation
docs(spec): the app page record binding's describe and TSDoc say what the console does - #30663
Conversation
… the console does The record key's describe() and the PageRecordBindingSchema TSDoc said the binding was planned in the renderer. The console reads it once per page open, the first row under sort under the caller's identity, and every component's visibleWhen sees that row as record. The text now names the three states a predicate sees. No key, shape, default or export changes. Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <[email protected]>
…ribe Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <[email protected]>
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 59e105a1751507576b1f14f42eb6606f13b38f39 && git checkout 59e105a1751507576b1f14f42eb6606f13b38f39
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ab44ec94b0362bafdf5f610b1d121655cd39a5fa 4afb99547e411b9793d78f83a4f4e6a47c25facb && git checkout -B drift-repro ab44ec94b0362bafdf5f610b1d121655cd39a5fa && git merge --no-ff 4afb99547e411b9793d78f83a4f4e6a47c25facb
node scripts/docs-audit/affected-docs.mjs --json ab44ec94b0362bafdf5f610b1d121655cd39a5fa
|
…ge-record-describe
Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <[email protected]>
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract-review-claim: session_01L6bhgTqqeHSwZYJmApbDCa · head 03429fc · 2026-11-05T22:12Z Full review at Generated by Claude Code |
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract reviewServed-tier: Inputs: card #30614 (body, triage 6666559971, claim 6669354257 and its amendment 6670237155, dev reports 6670194967 and 6670864581); PR #30663's body, file list and net diff against the merge-base Check-runs on the head, read at 2026-11-05T22:23Z: 69 of 69 completed, 60 ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings on the
No must-fix: every new sentence is true of the tree it describes, the set an author needs is present for the page Implemented-by: VERDICT: PASS Generated by Claude Code |
…ge-record-describe
…hen withholds Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <[email protected]>
…ge-record-describe
Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <[email protected]>
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract reviewServed-tier: Delta of record 6671102362 (PASS at Check-runs on the head, read at 2026-11-05T23:38Z: 69 of 69 completed, 60 ① Derived judgments
② Semver levelUnchanged and still right: ③ Boundary flags
④ Design judgment
Findings, none must-fix:
No must-fix: every round-2 sentence is true of the tree it describes and pinned there, the three should-fixes of 6671102362 are adopted as written, the parse-half sentences stay true, both merges are clean, and the Pages guide row matches the describe. Implemented-by: VERDICT: PASS Generated by Claude Code |
…ge-record-describe
…e mounted page row Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <[email protected]>
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract reviewServed-tier: Delta of records 6671102362 (PASS at Check-runs on the head, read at 2026-11-06T00:17Z after a first poll at 00:13Z found one still in progress: 69 of 69 completed, 60 ① Derived judgments
② Semver levelUnchanged and still right: ③ Boundary flags
④ Design judgment
Findings: none. No must-fix and no should-fix: the round-3 paragraph is true of the tree, names a symbol that exists, uses the tense the rest of the text uses, leaves "unbound" exactly where the tree binds nothing, and both body claims hold at the head. Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa 维护者速读
席位意见:契约复审三轮都 PASS。第一轮提了三处措辞:被拒的读只算 403;其他失败不画页面主体;走 席位核对 — ACCEPT · domain:spec#3 · head
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
Requested by Sales · project thread
Fixes #30614
Clause-②: no
Metadata-protocol: none
维护者速读
page.zod.ts中 app 页面record绑定的 describe 与PageRecordBindingSchemaTSDoc,以及组件visibleWhen的 describe 与 TSDoc,改写为控制台的真实行为,并重新生成参考页。record不绑定",而控制台早已读取它;照文案写元数据的作者和 AI 会放弃一个能用的绑定。packages/spec/src/ui/page.zod.ts(四处文案:PageRecordBindingSchemaTSDoc、recorddescribe、组件visibleWhenTSDoc 含其「Measured on the renderer」段、visibleWhendescribe)、content/docs/ui/pages.mdx(手写指南record行)、packages/spec/liveness/page.json(两条说明)。git grep -n "Planned in the renderer\|faulting predicate renders\|configEvaluationScope" -- packages/spec/src/ui/page.zod.ts content/docs ':!content/docs/releases'预期零命中(在 4afb995 实测退出码 1、无输出)。What changes
packages/spec/src/ui/page.zod.ts, thePageRecordBindingSchemaTSDoc: the "Planned in the renderer" paragraph is replaced by what the console does. The binding is read once per page open (the first row undersort, under the caller's identity); every component'svisibleWhensees that row asrecord; a record block that binds its own row still provides that row to its own subtree; and the three states a predicate sees (pending: the body is not drawn; no row, or a read the server refuses as forbidden (403):recordis null; any other failure: the body is not drawn). A page drawn throughinterfaceConfig.sourcereads no binding (round 2).recordkey's.describe(): the same reading, in one string. The parse half is unchanged and still stated:type: 'app'only (checkPageRecordBindingPlacement), a strict one-row shape with nolimit.visibleWhenTSDoc and.describe()(round 2, review escalation): "a faultingvisibleWhenrenders the component ... a gate that never gates" (TSDoc), "a faulting predicate renders the component, so such a gate never gates" and, forhasCapabilityon a host with no capability list, "a faulting predicate renders the component" (describe) now say the console withholds the component.data.total > 0anddata.total == 0both hide it. The advice that the page's row isrecordis kept.visibleWhenTSDoc's "Measured on the renderer" paragraph (round 3, delta review 6672431263). It namedconfigEvaluationScope, which does not exist underui/, and saidrecordis added "only when the page has a row — on an app page, once the renderer mounts the page'srecordbinding". It now namesbuildNodeEvaluationScopeand saysrecordis the page's row: the record a record page opens, or the row an app page'srecordbinding reads,nullwhen that read finds no row or is refused as forbidden.content/docs/references/ui/page.mdx: regenerated bygen:docs, never hand-edited.content/docs/ui/pages.mdx:63, the hand-writtenrecordrow of the Pages guide: "Planned in the renderer: until the console mounts it,recordstays unbound on anapppage" is replaced by the describe's reading, in the same words, kept as one table cell (round 1). A grep ofcontent/docsoutsidereleases/for "stays unbound" and "Planned in the renderer" now finds no hit.packages/spec/liveness/page.json, theprops.regionsnote (round 3): the[120] PageComponent.visibleWhenread point namedSchemaRenderer.tsx#configEvaluationScopewithrecord"only when the page has a row". It now namesui/packages/react/src/SchemaRenderer.tsx#buildNodeEvaluationScope(noting the old name at objectui @1fb1ced36243) and states the samerecordreading as the TSDoc.packages/spec/liveness/page.json, theprops.recordnote: its last sentence said this describe and TSDoc were stale. This PR makes that false, so it now says they state the same reading..changeset/30614-page-record-binding-describe.md:@objectstack/specpatch, which also names the Pages guide row.Every sentence was checked against the readers on
origin/mainb8929f486:ui/packages/app-shell/src/views/PageView.tsx(appPageRecordBinding,AppPageRecordGate,AppPageRecordReadwith$top: 1and$orderbyfromsort),ui/packages/app-shell/src/providers/ExpressionProvider.tsx#PageRecordScope,ui/packages/react/src/SchemaRenderer.tsx#buildNodeEvaluationScope, and the pinui/packages/app-shell/src/views/__tests__/PageView.appPageRecord-12931.test.tsx.Tests
No behaviour changes, so there is no new test and no ablation. The
@objectstack/specpage suites pass, spec typecheck passes, andcheck:generatedreports all 14 artifacts up to date.Acceptance notes
recordunbound: a predicate reading it faults, and a faultingvisibleWhenrenders the component". The describe said "No row, norecord: the predicate faults and the component renders". Onmain,AppPageRecordReadbindsrecordasnullfor both cases (pinned by the 0-row and 403 cases of the pin test). Separately,SchemaRenderer.tsx#visibilityFaultOutcomenow fails a declaredvisibleWhenclosed on a fault, so "renders" is no longer the verdict. The new text does not describe the fault verdict of a field read on a nullrecord, because no test pins it.packages/spec/liveness/page.json, theprops.recordnote: its last sentence ("The schema's own describe() and TSDoc still say 'Planned in the renderer' — stale prose left for a spec change") was made false by this PR. It now reads "The schema's own describe() and TSDoc state this same reading." It ships (livenessis in the package'sfiles), the claim's file surface was amended to hold it (6670237155), andcheck:livenessis green.content/docs/ui/pages.mdx:63 carried the same stale sentence and is fixed in round 1, under the amended claim (6670237155). The Pages guide row was already silent on the no-row verdict, so only the "Planned in the renderer" sentence was false there. It gains the three states the describe states, and no claim the describe does not make.PERMISSION_DENIED/FORBIDDENclassifyforbidden(ui/packages/react/src/utils/error-message.ts). A 401, a 400 or rejected read, and api-disabled land in the failed-read state.ElementDataSourceGate.tsx). The TSDoc now agrees with the describe: any other failure draws no page body.apppage that also setsinterfaceConfig.sourceis drawn asInterfaceListPageoutsideAppPageRecord(PageView.tsx), so it reads no binding. One clause in both texts, and no refinement.visibilityFaultOutcome(SchemaRenderer.tsx) answers a declaredvisibleWhenthat faults withfalse, pinned bySchemaRenderer.nodeVisibilityFailClosed-13299.test.tsxandSchemaRenderer.visibleWhenRecordBinding.test.tsx("WITHHOLDS the block").packages/spec/src/**(non-test) and the hand-writtencontent/docs/**for "faulting predicate renders", "faultingvisibleWhenrenders" and "never gates": only thepage.zod.tssites carried the false claim. The other hits (automation/schemaless-node-config.zod.tsdecisioncondition,ui/action.zod.tspressed,data/object.zod.tsdisabledWhenfail-soft,kernel/public-auth-features.ts, two migration entries) carry no visibility fault-renders claim and are untouched.content/docs/ui/pages.mdx:63 now matches the round-2 describe word for word on the two points, with "no row, or a read the server refuses as forbidden (403), bindsrecordas null" and "A page drawn throughinterfaceConfig.sourcereads no binding". It is still one table cell and adds no other claim.ui/packages/app-shell/src/providers/ExpressionProvider.tsxPageRecordScopedocblock still states the fail-soft verdict (noui/change).packages/spec/src/ui/page.zod.tskeeps "re-read when the bound object is written":AppPageRecordReadkeys its read onuseDataInvalidation(object), so it is still true beside "once per page open".Verification
Local gates, round 3 (head 4afb995, after merging origin/main at 606df50)
turbo run build --concurrency=2: lock VERDICT command-exit 0, 119/119 tasks.gen:docs && check:generated && vitest runover the page suites&& typecheck(spec): lock VERDICT command-exit 0. "All 14 generated artifacts are up to date" (no regenerated diff: the edited paragraph is TSDoc only). Test Files 10 passed (10), Tests 572 passed (572).check:test-typecheck: OK.eslint --no-inline-config packages/spec/src/ui/page.zod.ts: exit 0.dispatch-gates --commands --repo objectstack-ai/objectstack: 97 commands, all exit 0 on the first pass (check:livenessamong them).--ran: "97 derived, 97 run, 0 NOT-MEASURED, 0 UNRUN".check-changeset-no-major --base origin/main: "This diff introduces nomajorbump".Local gates, round 2b (head 0aeb81b, after merging origin/main at 8f4aaf7)
turbo run build --concurrency=2: lock VERDICT command-exit 0, 119/119 tasks.pnpm --filter @objectstack/spec check:generated: exit 0, "All 14 generated artifacts are up to date".dispatch-gates --commands --repo objectstack-ai/objectstack: 97 commands, all exit 0 on the first pass (check:doc-authoring,check:doc-anchors,check:doc-frontmatter,check:docs-single-h1andcheck:docs-redirectsamong them).--ran: "97 derived, 97 run, 0 NOT-MEASURED, 0 UNRUN".check-changeset-no-major --base origin/main: "This diff introduces nomajorbump".Local gates, round 2 (head f7299af, after merging origin/main at 4533101)
turbo run build --concurrency=2: lock VERDICT command-exit 0, 119/119 tasks.gen:docs && check:generated && vitest runover the page suites&& typecheck(spec): lock VERDICT command-exit 0. "All 14 generated artifacts are up to date". Test Files 10 passed (10), Tests 572 passed (572).check:test-typecheck: OK.eslint --no-inline-config packages/spec/src/ui/page.zod.ts: exit 0.dispatch-gates --commands --repo objectstack-ai/objectstack: 97 commands, all exit 0 on the first pass.--ran: "97 derived, 97 run, 0 NOT-MEASURED, 0 UNRUN".check-changeset-no-major --base origin/main: "This diff introduces nomajorbump".Local gates, round 1 (head 03429fc, after merging origin/main)
turbo run build --concurrency=2: lock VERDICT command-exit 0, 119/119 tasks.pnpm --filter @objectstack/spec check:generated: exit 0, "All 14 generated artifacts are up to date".dispatch-gates --commands --repo objectstack-ai/objectstack: 97 commands, all exit 0 on the first pass,check:doc-authoring,check:doc-anchors,check:doc-frontmatterandcheck:docs-single-h1among them.--ran: "97 derived, 97 run, 0 NOT-MEASURED, 0 UNRUN".check-changeset-no-major --base origin/main: "This diff introduces nomajorbump".Local gates, round 0 (head 2529918)
All read at head
2529918f4, exit codes captured before any pipe.pnpm --filter @objectstack/spec build: lock VERDICT command-exit 0.pnpm --filter @objectstack/spec gen:docs && pnpm --filter @objectstack/spec check:generated: exit 0. "All 14 generated artifacts are up to date". The firstcheck:generatedrun namedcontent/docs/references/**stale. That page is regenerated in the second commit.vitest runoversrc/ui/page*.test.ts(9 files) andsrc/ui/object-refinement-check-exports.test.ts: Test Files 10 passed (10), Tests 572 passed (572).pnpm --filter @objectstack/spec typecheck: exit 0.eslint --no-inline-config packages/spec/src/ui/page.zod.ts: exit 0.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 97 commands, all exit 0. Six first exited 3 (PREREQUISITE NOT MET, unbuilt workspace packages). They were re-run afterturbo run buildand exited 0.--ranreconciliation: "97 derived, 97 run, 0 NOT-MEASURED, 0 UNRUN".check-changeset-no-major --base origin/main: "This diff introduces nomajorbump".check:dev-prereqsexit 0,check:skill-frame-freshnessexit 0.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa