Repository navigation
docs(spec): the page element's api data source is described as rendered, and visibleWhen names where data is mounted - #24460
Conversation
…; visibleWhen names where data is mounted ElementApiDataSourceSchema drops its planned marker and says what the console renders at its pin. PageComponentSchema.visibleWhen's describe and TSDoc, and the page:tabs item TSDoc face, name the api data source as the one data carrier. The binding's refusal and unknown-key messages no longer name a page element. The expression-scope data-root pin is re-trued to the shipped fact, and the page liveness note records the binding as live. Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
…data source Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
…ema's own message Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
📓 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:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 143 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 bbf5ea9185698eb385d8f6d6856cf087cd511b78 && git checkout bbf5ea9185698eb385d8f6d6856cf087cd511b78
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 31ce45c071bbcb6e92a730ce19ebf30dcfa361cb f0ce6bc1e3f2ba0333eaa5709bb5c0c1ca263286 && git checkout -B drift-repro 31ce45c071bbcb6e92a730ce19ebf30dcfa361cb && git merge --no-ff f0ce6bc1e3f2ba0333eaa5709bb5c0c1ca263286
node scripts/docs-audit/affected-docs.mjs --json 31ce45c071bbcb6e92a730ce19ebf30dcfa361cb
|
…a source's data root, as its TSDoc does Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
…nsole renders the api binding Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Inputs read: card #24300 body and all 8 comments (triage ① Derived judgmentsAccept set: unchanged. RIGHT. The diff to Published prose,
Rider The pin,
Generated docs: RIGHT at the PR's base, INCOMPLETE against Sibling checkout: no pin risk. The Console Pin Gate ( Fence and hold-offs: honoured. ② Semver level
Clause-②: One nit, not a verdict item: the changeset's bullets name the ③ Boundary flagsBoth dev reports carry
Implemented-by: VERDICT: PASS Generated by Claude Code |
…i-binding-rendered
…s-regen hand-off) Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
…source by reference Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
… api data source changeset Claude-Session: https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu Co-authored-by: Claude <noreply@anthropic.com>
|
Regen-provenance: 6260617692 ·
Generated by Claude Code |
席位核对ACCEPT ·
Generated by Claude Code |
Fixes #24300
Clause-②: no
The page element's
apidata source (ElementApiDataSourceSchema) is rendered by the console at its pin, and@objectstack/specnow says so. Before this change, its describe opened with[PLANNED — not yet rendered], andPageComponentSchema.visibleWhensaid that no renderer reads the binding. Both told an author, and an AI author first, not to use a binding the console renders. The change is describe and TSDoc text only: no accept set moves, and every refusal keeps its issuecodeandpath.What the console renders, measured at the pin
The pin is
.objectui-sha0707b4ae37onmain. It carries objectuic4dd7078ed:git merge-base --is-ancestor c4dd7078ed 0707b4ae37exits 0 in../objectui, an exit 0 that proves itself. Every read below isgit show 0707b4ae37:PATH, not objectuimain.packages/react/src/SchemaRenderer.tsxcallsuseElementApiDataSource(schema)for every node (:1157). Once the read isready, the node's evaluation scope is{ ...ambientScope, data: apiData }(:1231), and this scope evaluates its expression holes and itsvisibleWhen(:1982). The same value goes to the subtree throughPredicateScopeProvider(:1161,:2524). While the read isloadingthe node draws a loading panel, and when the binding isrefusedor hits anerrorit draws an error panel. Both are drawn before visibility, sovisibleWhenis decided only once the value is in (:1285,:2165).packages/react/src/element-data-source/useElementApiDataSource.tsparses the binding withElementApiDataSourceSchemafirst (refusedcarries the schema's own message, and nothing is read). It then sends oneGETthroughSchemaRendererContext.apiFetch, the console's signed-in fetch, and selectspath.SchemaRenderer:packages/components/src/renderers/layout/page.tsxpasses the region's components toPageBlockGrid(page-block-grid.tsx:56), andtoRenderableSchemais identity for an object.hero,stat,usage-bar,checklistandtile-gridblocks are registered inpackages/app-shell/src/console/blocks/productBlocks.tsx(:360–:408).buildExpressionScope(packages/app-shell/src/providers/ExpressionProvider.tsx:181) returnscurrent_user,user,ctx.user,os.userandfeatures, andconfigEvaluationScope(SchemaRenderer.tsx:668) addsrecord(only when there is a row) andpage. No root is claimed that is not mounted.page:tabsitem evaluator (packages/components/src/renderers/layout/containers.tsx:645) writesdata: recordDataafter spreading the ambient scope. So on that surfacedatastays the row, even inside an element anapidata source binds.scripts/build-console.shbuilds@object-ui/console"at the SHA pinned in .objectui-sha", andscripts/sdui-manifest.record.jsonrecordsobjectuiSha0707b4ae37…. So no "which console" caveat is needed.What changed
packages/spec/src/ui/page.zod.tsElementApiDataSourceSchema: its describe drops the marker and says what the console renders. Its docblock section "Planned, not yet rendered" becomes "Rendered by the console, on a page element", with the read points cited by theobjectui:realm marker.PageComponentSchema.visibleWhen, describe and TSDoc: the renderer mounts nodataroot on an element that noapidata source binds, where adata.*read still faults and the gate never gates. On an element one binds,datais the bound value, there and on every element nested inside it. The TSDoc's measured-scope sentence names that one added root. The section heading is now "data— only where anapidata source binds it".PageComponentSchema.dataSourceTSDoc: "(planned in the renderer …)" now reads "rendered by the console".6259026494: the binding's refusal, unknown-key surface and sibling describe sentences no longer name a page element. For example, "read.urlof anapidata source must be …", the surface "thisapidata source", and thewrite,body,methodandpathmessages. The same change also made door-neutral theobjectguidance, which told an author to "keepobject": the navigation entry that PR feat(spec): a navigation entry may declare one API data source, which its visible reads as data #24427 adds admits no object binding, so that advice is now scoped to "where thedataSourcealso takes the object binding (a page element's does)". Each refusal keeps its issuecodeandpath. The objectui test that reads the refusal text asserts onlysame-origin(useElementApiDataSource-12197.test.tsx:141), and the new wording keeps it.packages/spec/src/ui/component.zod.ts: only thepage:tabsitemvisibleWhenTSDoc face that the pin reads. It now says that the component-node evaluator mounts nodataroot, except on an element anapidata source binds, and that on this surfacedatastays the row. Patch round 2 (claim amendment6259996449): the same key's.describe()parenthetical now agrees with it: "(the component-node evaluator mounts nodataroot save on an element anapidata source binds, wheredatais that binding's value)".packages/spec/src/ui/expression-scope-data-root.pin.test.ts: re-trued, not deleted. Rule (2) now admits adatasentence only if it says "NOdata", tiesdatatoprovider: 'api', or is aboutpage:tabs. A sentence that mountsdatawithout the binding is still refused. The "two texts agree" block becomes "three texts agree": the binding's describe and bothvisibleWhenfaces carry no planned reading (six matchers), and bothvisibleWhenfaces name the binding as the onedatacarrier. Two DARK controls are added: one shows that an overclaiming sentence fails rule (2), and one shows that the three replaced planned texts are caught by the planned matcher. The pin has 16 cases (13 before).packages/spec/liveness/page.json: the_notesentence "PLANNED RECORD (spec(ui): a page element dataSource can name an API endpoint (provider: 'api'), so a product page composes from a control-plane summary in metadata instead of a product-specific React widget (maintainer ruling 2026-10-12) #23016 …)" becomes a "LIVE RECORD", measured at the pin, with theobjectui:read points. Only the_notechanges; theregionsrow that PR feat(spec)!: retire a page action row's own patch — a row's operation: 'update' runs the declared action its name names (#24394) #24442 edits is untouched.content/docs/references/ui/page.mdxandcontent/docs/references/ui/component.mdx: regenerated bygen:docs.content/docs/references/ui/app.mdx: regenerated in patch round 3, because PR feat(spec): a navigation entry may declare one API data source, which its visible reads as data #24427's navigation entry embedsElementApiDataSourceSchemaby reference (18 embeddings × theprovider,readandpathrows).content/docs/ui/pages.mdx(hand-written; claim amendment6260050788, declared todomain:devxon [PM seat] domain:devx · seat 2 — 🟢 os-sales · session_016PVjjuVPte5XEJvaQx1E4t · serial (maintainer) #20163): the "Not rendered yet" bullet of "The API binding's rules" now says the console renders the binding and names the blocks that read it. No other edit to the page..changeset/24300-api-binding-rendered.md:@objectstack/specpatch. Patch round 3 added one bullet for thepage:tabsitemvisibleWhendescribe parenthetical.Not touched, by the claim's fence:
packages/spec/src/ui/app.zod.ts(its navigationdataSourcestays planned), the other[PLANNED]markers incomponent.zod.ts, and the binding's accept set.view.zod.ts:170and theview-data-api-provider-retiredmigration texts call this binding "the governed door" read with the signed-in fetch. They never call it planned, so they stay as they are (dispatch hypothesis H3, refuted for them).Verification (at head
8951d79063, unless a line names another sha)Patch round 3, head
f0ce6bc1e3:origin/mainff4840756d(carrying PR feat(spec): a navigation entry may declare one API data source, which its visible reads as data #24427 and PR feat(spec)!: retire a page action row's own patch — a row's operation: 'update' runs the declared action its name names (#24394) #24442) was merged withbash scripts/pm/os-regen-merge.sh, with no rebase or force-push.component.mdxandapp.mdxwere regenerated withcheck:generated --fix. The hop proof compares the+/-lines ofgit diff -U0 9112bcd887 0ea4d853a2andgit diff -U0 ff4840756d f0ce6bc1e3, both outsidecontent/docs/referencesand.changeset. It is empty, so the hop moves only generated pages and the changeset. Atf0ce6bc1e3,vitest run src/ui/gaveTest Files 132 passed (132),Tests 5200 passed (5200), andcheck:generatedandcheck:docsexited 0.Reverse verification at
1dad7bbe4b(the pin file is byte-identical at the final head), one shot, expected direction red.page.zod.tswas restored to the merge base9112bcd887(hash-objectmatched the base blob448b9617…; the marker count was 1), and the re-trued pin ran against it:Tests 4 failed | 12 passed (16). The four failing cases were the docblock's binding sentence, the describe's binding sentence, the binding's "renders" sentence and the no-planned-reading sweep. The file was then restored withgit checkout HEAD --:hash-objectmatched the HEAD blob646f9a43…, andgit diff HEADwas empty. The observed direction was red.pnpm --filter @objectstack/spec testat1dad7bbe4b:Test Files 697 passed (697),Tests 21271 passed | 1 todo. The final commit8951d79063changes one TSDoc paragraph. At that head, every test that readspage.zod.tssource was re-run: 6 files / 362 tests passed, andscripts/file-description.test.tsplusscripts/schema-index.test.tsgave 2 files / 130 tests passed.pnpm --filter @objectstack/spec typecheck: exit 0 (tsc --noEmit,check:scripts-typecheck,check:test-typecheckOK).pnpm --filter @objectstack/spec check:generated: the only stale artifact wascontent/docs/references/**, regenerated withgen:docs.check:authorable-surface,check:api-surface,check:livenessandcheck:strictness-ledgerwere all green.node scripts/pm/dispatch-gates.mjs --commandsat8951d79063derived 111 commands, and all were run locally. Reconciliation result:--ran: "111 derived famil(ies) accounted for — 111 run, 0 NOT-MEASURED". 110 exited 0. Six had first refused withPREREQUISITE NOT METand passed oncelint,formula,client-reactandobjectqlwere built. One exited 1,pnpm check:platform-checklist, and that red predates this branch:docs/qa/platform-checklist/areas/access-security.jsoncitespackages/core/src/security/resolve-authz-context.ts#legacyGrantAnchorRetired, which is absent there on the merge base9112bcd887and onorigin/main7e1ce9d945. The symbol now lives inpackages/plugins/plugin-auth, sinceb2e78701f7. This diff touches no file underpackages/coreordocs/qa.main'sec951e29e4(docs(qa): re-point the platform-owner-email item's legacy-grant anchor at grantAnchorsPlatformStanding #24463) re-pointed that anchor, and the check readsOK — 16 areas, 327 itemsatf0ce6bc1e3.Verdict lines:
check:docs"227 generated files in sync";check:api-surface"public API surface + factory signatures unchanged";check:doc-authoring"19075 customer-facing string(s) … clean";check:issue-citations"every citation this change adds resolves";check:nul-bytes"no raw ASCII control bytes";check:empty-changesetandcheck:adr-0087-registrationgreen.Local-only
pnpm check:dev-prereqs: "@objectstack/spec … built from the sources on disk".Acceptance notes
TheDone in patch round 2: the seat widened the claim's surface (page:tabsitemvisibleWhendescribe was left for the seat.6259996449), and the describe now agrees with its TSDoc face.carrier: none· The committed SDUI manifest (sdui.manifest.json,objectuiSha0707b4ae37, 107 components) lists none of the five product blocks the pin registers (hero,stat,usage-bar,checklist,tile-grid). The JSX page gate validates components against that manifest. This is a read-only inference: noos validaterun measured it, so it is noted, not filed.carrier: none· The docblock's "## The ruling" section still justifiesmethod: 'GET'through@object-ui/core'sApiDataSource, which the shipped reader does not use (its ownGETis cited in the new section). The sentence stays true about that adapter. It sits outside the fence and is left as it was.mainwas merged in once, atff4840756d(patch round 3). PR feat(spec): a navigation entry may declare one API data source, which its visible reads as data #24427 reusesElementApiDataSourceSchemaon the navigation entry, so this branch's describe change also movescontent/docs/references/ui/app.mdx, which the queue'scheck:docswould otherwise find stale.Generated by Claude Code