Repository navigation
fix(spec): the page liveness ledger grades the app page record binding live, citing its console readers - #30611
Conversation
…read points The app page record binding is read by the console's PageView (appPageRecordBinding -> AppPageRecord -> PageRecordScope); each child key is cited at the line that reads it. Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check
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): |
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa 维护者速读
席位意见:本 PR 不碰契约四面(无 schema、无收窄、 席位核对 — ACCEPT · domain:spec#3 · head
|
Requested by Sales · project thread
Fixes #30094
Clause-②: no
Metadata-protocol: none
维护者速读
packages/spec/liveness/page.json里 app 页面record绑定及其全部子键(object/view/filter 及 field/operator/value、sort 及 field/order)从planned改判live,每行引用控制台里真正读取它的代码;同步重生成state-counts/page.md(live 35→42,planned 9→2),并加一条@objectstack/specpatch changeset。record」,但ui/里的 PageView 已经按这个绑定读出首行并作为record交给每个组件的visibleWhen;过期的planned会让作者和 AI 以为这个键不起作用。ui/、无运行时行为变化;回滚即 revert 本 PR。packages/spec/liveness/page.json的record块(容器行的 evidence 与 note);packages/spec/liveness/state-counts/page.md;.changeset/30094-page-record-liveness-regrade.md。pnpm --filter @objectstack/spec check:liveness,预期末行✓ … every path#symbol anchor names a symbol its file contains …且state-counts/ is current,退出码 0。What changes
Each
props.record.*row of thepageledger is regraded from the renderer in this checkout, following the README regrade recipe: apath#symbolcitation at the reader,verifiedAt: 2026-11-05,evidenceScope: in-repo, and aproducerwhere the read depends on a second input (the page's adapter). No row staysplanned: every key has a reader.recordPageView.tsx#appPageRecordBinding(anapppage only, a binding that names its object) → the AppPageRecord elementPageView.tsx#PageViewmounts around the page body →PageView.tsx#AppPageRecordRead(first row,$top: 1) →ExpressionProvider.tsx#PageRecordScope(publishes it asrecord) →SchemaRenderer.tsx#buildNodeEvaluationScope(spread into every component'svisibleWhen)record.objectPageView.tsx#AppPageRecordGatelands it onobjectName(element-data-source.ts#composeElementDataSource);PageView.tsx#AppPageRecordReadcallsdataSource.find(object, params)record.viewuseElementDataSource.ts#useElementDataSourcereadsconfig.view, lists the saved views and resolves the name (an unresolved name draws the gate's error panel, never a wider read);element-data-source.ts#composeElementDataSourceAND-combines the view filter and takes the view sort when the binding has nonerecord.filterElementDataSourceGate.tsx#useElementDataSourceSchema(the page mapping'sfilter: truelowers it withtoFilterNodeSafely);PageView.tsx#AppPageRecordReadresolves placeholder tokens and sends it as$filterrecord.filter.fieldfilter-converter.ts#viewFilterRuleToNode(left operand of the lowered comparison)record.filter.operatorfilter-converter.ts#viewFilterRuleToNode(normalised bynormalizeFilterOperator)record.filter.valuefilter-converter.ts#viewFilterRuleToNode(right operand)record.sortPageView.tsx#AppPageRecordReadsends it asparams.$orderbybeside$top: 1;element-data-source.ts#composeElementDataSource(binding sort overrides the view's)record.sort.fielddata-objectstack/src/index.ts#serializeOrderBy(field/-fieldon the wiresort)record.sort.orderdata-objectstack/src/index.ts#serializeOrderBy(desc, case-insensitive, selects-field)All
ui/paths are rooted atui/packages/:app-shell/src/views/PageView.tsx,app-shell/src/providers/ExpressionProvider.tsx,react/src/SchemaRenderer.tsx,react/src/hooks/useElementDataSource.ts,react/src/element-data-source/ElementDataSourceGate.tsx,core/src/data-scope/element-data-source.ts,core/src/utils/filter-converter.ts,data-objectstack/src/index.ts.The predicate scope the old note said was missing. The old note measured objectui
main@79cb8c03eb, whererecordcame only fromRecordContext, which a record block provides to its own body. The page host now mountsPageRecordScope, which adds the page row asrecordto the ambient predicate scope;buildNodeEvaluationScopespreads that scope first, so every component predicate on the page reads it, and a record block that binds its own row still overridesrecordfor its own subtree.Changeset.
packages/spec/package.jsonfiles[]listsliveness, soliveness/page.jsonships in the npm tarball:@objectstack/specpatch, with both declaration lines.Why
A stale
plannedrow tells authors and agents that the key does nothing. The ledger is what the gate, the enforce-or-remove channel and the AI authoring surfaces read as the capability catalogue, and this row was written before the console's reader landed.Tests
No code changed, so no test was added. The reader is already pinned by
ui/packages/app-shell/src/views/__tests__/PageView.appPageRecord-12931.test.tsx(tier and count predicates, one read per page open with the org token resolved in$filter, no binding and a non-app page read nothing, 0 rows, 403 read as no row, failure fails closed). That test coversobjectand thefilterrule keys.viewandsortare cited at their readers only.Acceptance notes
packages/spec/src/ui/page.zod.tsstill says "Planned in the renderer: until the console mounts it,recordstays unbound on an app page" in therecordkey's.describe()and in thePageRecordBindingSchemaTSDoc. The same file'svisibleWhendescribe already states the binding is read. The ruling for this card is no schema change, so this is a follow-up for the spec owner (a.describe()edit regeneratescheck:docsartifacts). The ledger row wins over a describe marker, so the gate's verdict is unaffected.pageNotes cell ("live, plus the one dead tombstone below") is now exactly true for therecordsubtree and was not edited. The 2 rows stillplannedinpageare outsiderecord.--commandsfamilies derived on the committed head, exit codes captured to disk,--ranreconciled. Readings are in Verification.Verification
All readings on head
7a3032f3b, the final commit; exit codes captured before any pipe.check:liveness — exit 0
pnpm --filter @objectstack/spec check:livenessbefore regenerating the counts: exit 1, the only failure being the stalepageshard (35 | 0 | 0 | 1 | 9became42 | 0 | 0 | 1 | 2).gen:liveness-countsrewrote 1 shard (page.md). Re-run: exit 0, with everypath#symbolanchor resolving, every cited file naming its key, andstate-counts/ is current.Liveness vitest — 12/12 files, 359/359 tests
bash scripts/pm/os-verify-lock.sh -c 'pnpm --filter @objectstack/spec gen:migration-registry && pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness'printedTest Files 12 passed (12),Tests 359 passed (359)andVERDICT command-exit 0.Derived gate families — 57 derived, 57 run, 0 NOT-MEASURED (derived zero)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 57 commands from the change set (3 paths, 105 changed lines). Every one exited 0, and--ranwithcommand :: exit Nrecords printed57 derived, 57 run, 0 NOT-MEASURED, 0 UNRUN(a DERIVED zero: all 57 carry an exit code, none of them 3).Three needed a second run.
check:generated: in the first sweep thecheck:test-typechecklane's tsc died with no diagnostics, because the sweep ran withoutNODE_OPTIONS. Run alone with--max-old-space-size=4096, that gate held (52 files / 240 errors / 131 pinned signatures, unchanged), andcheck:generatedre-ran with all 14 artifacts up to date.check:dual-build-cjs-loadsandcheck:lean-entry-closurefirst exited 3 (PREREQUISITE NOT MET). Afterturbo run build(120/120 tasks) both exited 0.Local-only families:
check:dev-prereqsexit 0,check:skill-frame-freshnessexit 0.Human Minimum
packages/specholds no runtime logic. (No schema touched.)pnpm lintpasses. (No lintable source changed; CI runs it.)main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed (state-counts/page.md;check:generated14/14).content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa