Repository navigation
docs(plugin-view): teach the spec-shaped named list view (objectui#8255) - #10504
Conversation
Every `listViews` entry in the plugin-view README, plugin-view.mdx and schema-reference.md now parses under @objectstack/spec's ObjectListViewSchema: each named view carries `columns` (the one key the spec requires), and schema-reference's `my-deals` view spells its filter as a spec rule object instead of the ObjectQL tuple. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
The pin that held the three refused named-view forms as "still what the docs teach" now asserts their successor: every `listViews` entry in the plugin-view README, plugin-view.mdx and schema-reference.md, read off disk with the TypeScript parser, parses under the spec's ObjectListViewSchema. A positive control runs the same predicate over the retired forms (label-only, tuple filter) and requires both refused. The spec-side refusal assertions are unchanged. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
…guide
schema-reference's my-deals view now filters on the spec's own context
token {current_user_id} (CONTEXT_TOKENS in @objectstack/spec/data)
instead of an invented ${currentUser.id}, with one sentence saying the
host that renders the list resolves it and that the object-view node
path is tracked in objectui#10506. The CRUD guide's TaskSchema
listViews.active filter becomes a { field, operator, value } rule
object, which the spec's ObjectSchema.listViews accepts.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
The guide page joins NAMED_VIEW_DOCS, keeping the per-page non-vacuity bound, and the markdown-test-inputs ledger row for the pin now lists it as a read so a markdown-only change to the guide still runs the pin. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
…ified The pending 7779 entry said the spec refuses the named views the docs teach; the docs no longer teach them, so that sentence now says what the docs taught when the entry was written and that objectui#8255 has since rewritten them. Front matter unchanged. This change's own empty-frontmatter changeset now also names the CRUD guide and the context token. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Fixes #8255
Clause-②: no
The docs half of the objectui#7928 ruling (decision batch #70, option A). The renderer half, objectui#8254, landed as PR #9605 and honours a spec-shaped named view, including
columnsin either union arm andfilteras rule objects. This PR makes the four pages teach that shape: the three the card names, plus the CRUD guide folded in by the seat decision5827390159(patch round 1, head9c7f893d3).What changed
packages/plugin-view/README.mdandcontent/docs/plugins/plugin-view.mdx(the same three examples in each): every named view now carriescolumns, the one keyObjectListViewSchemarequires. The label-onlyallview in the ObjectView overview gainscolumns: ['name', 'email'](the same list as the snippet'stable.columns), and its inline comment now says each view needslabelandcolumns.cheap(Read/List) gainscolumns: ['name', 'price']andadmins(View tabs) gainscolumns: ['name', 'email'], matching their sibling views.content/docs/api/schema-reference.md, theObjectViewSchemaexample: both views gaincolumns(the example's owntable.columnslist), andmy-dealsspells its filter as a spec rule object,{ "field": "owner", "operator": "equals", "value": "{current_user_id}" }, instead of the ObjectQL tuple. The value is the spec'sCONTEXT_TOKENSspelling (patch round 1; it was an invented${currentUser.id}nothing resolves), and one sentence beside the example says the host that renders the list resolves the token, with theobject-viewnode path tracked in objectui#10506. The view is again writtenlabel-first. The old order only existed to keep a pinned line byte-identical, and that pin now reads this example differently (see below).content/docs/guide/building-crud-app.md(patch round 1):TaskSchema.listViews.active.filterbecomes the rule object{ field: 'status', operator: 'not_equals', value: 'Done' }instead of the tuple..changeset/object-view-unmirrored-keys-7779.md(patch round 1): the one sentence this PR falsified now reads in the past tense (the spec refused the named views the docs taught when the entry was written; objectui#8255 has since rewritten them). The front matter is byte-identical.scripts/markdown-test-inputs.mjs(patch round 1): the 7779 pin's ledger row gains the guide page inreads, because--auditrefuses an unadjudicated document the pin now resolves.Validation against the installed spec
Schema:
ObjectListViewSchemafrom@objectstack/spec/ui,@objectstack/spec@17.4.0, resolved frompackages/types(the^17.4.0range there,^17.0.0inplugin-view, same install). This scratch script was not committed. It finds every fenced block in the three pages that mentionslistViewsand parses it with the TypeScript parser (ajsonbody is wrapped in an initializer). For eachlistViewsproperty it turns the literal into a value and runs each entry throughObjectListViewSchema.safeParse.Before (base
39395455a), 12 entries in 7 blocks, 8 refused:After (this branch), all 12 accepted, controls refused:
Patch round 1, over four pages (the CRUD guide added). Base
39395455a:SUMMARY listViews blocks=8 entries accepted=5 refused=9 controls=pass(the extra refusal:content/docs/guide/building-crud-app.md:130 (ts) listViews.active -> filter.0: invalid_type). Head9c7f893d3:The card named three examples. Measured, seven blocks carried eight refused entries: the
cheapandadminsviews in both the README and the mdx were refused too (nocolumns), so all of them are rewritten.The pin that held the old forms, and its successor
packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.tspinned the refused forms off disk as "still what the docs teach". That was the input to the measurement keepinglistViewsledgered. Rewriting the docs turned it red, as designed. Before the successor was written it failed one test out of 233 (expected '# @object-ui/plugin-view…' to contain 'listViews: { all: { label: 'All User…').That test is replaced by its successor and is not weakened. The new test reads every named view the four pages author off disk (three, plus the CRUD guide from patch round 1), using the TypeScript parser, and requires each one to parse under
ObjectListViewSchema. It requires at least one entry per page, so a page cannot pass vacuously. It also runs a positive control through the same predicate: the retired label-only and tuple forms must come back refused, and the spec shape must not. The spec-side refusal assertions in the test before it are unchanged; only its title and comments moved to the past tense. The file header sentence that said the docs "teach" the refused forms is updated the same way. The pin reads all four pages, and itsscripts/markdown-test-inputs.mjsledger row names all four inreads(--audit: exit 0,75 declared entries, all present).This PR claims the pages validate. Per AGENTS.md #9, that claim now points at this pin as the instrument that re-derives it, not at the scratch output above.
Reverse verification (one-time, not committed)
Each leg ran through
ablation-replace.mjs: the anchor had to hit, the blob had to change on disk, and the restore was proven by blob == HEAD plus an emptygit diff HEAD.Leg A: drop
columnsfrom the README'scheapview. Predicted red, naming that entry. Observed exit 1:+ "packages/plugin-view/README.md:458 listViews.cheap". Restored, blobe7f0e491f2b4== HEAD.Leg B: put the tuple filter back in
schema-reference.md. Predicted red namingmy-deals, with the objectui#7923 pin still green. Observed exit 1:+ "content/docs/api/schema-reference.md:853 listViews.my-deals",Test Files 1 failed | 1 passed (2). Restored, blob67508396a7c5== HEAD.Leg C: set
columns: 'name'on the README overview view, to provecheck:doc-snippetscompiles that block. Observed exit 1:packages/plugin-view/README.md:154:43 TS2322: Type 'string' is not assignable to type 'string[]'. Restored.Leg D (patch round 1): put the tuple back in the CRUD guide. Observed exit 1:
+ "content/docs/guide/building-crud-app.md:89 listViews.active",Tests 1 failed | 228 passed (229). Restored: blobf390aef0ef41== HEAD,git diff HEADempty.Gates, at HEAD
9c7f893d3(patch round 1 re-ran every gate below)pnpm check:doc-snippets(after the gate's own--build-filterclosure,Tasks: 35 successful, 35 total)Semantic phase: 673 of 673 block(s) judged, 0 failed.pnpm check:doc-examplesEvery covered @example compiles, or fails exactly as its ledger row declares.No ledger row keys on these examples (its three plugin-view rows are JSDoc blocks in the ObjectView source)pnpm check:doc-fencespnpm check:doc-typesEvery documented component type is registered.pnpm docs:check-linksLinks are valid across 17 scan roots.node scripts/check-doc-example-ids.mjs·pnpm check:readme-exports·node scripts/check-shell-escape-residue.mjspnpm check:control-bytespnpm check:new-line-citations0 new citation(s)node scripts/check-changeset-presence.mjspackages/types/src/, answered with the empty-frontmatter.changeset/8255-docs-spec-shaped-list-view.md. The docs alone owed nonenode scripts/check-changeset-no-major.mjs·node scripts/check-pending-changeset-literals.mjs·node scripts/markdown-test-inputs.mjs --auditscripts/__tests__/(thecheck-doc-*suites,markdown-test-inputs,check-pending-changeset-literals)Test Files 11 passed (11),Tests 634 passed (634)@object-ui/types, whole package:pnpm exec vitest run packages/types/Test Files 232 passed (232),Tests 5156 passed (5156)pnpm --filter @object-ui/types type-check(includestsconfig.test.json;--listFilesshows the edited pin in the program, 1 hit)node scripts/check-governed-queue-guard.mjs --teston the eight pathsNOT GOVERNEDpnpm check:changeset-claims(the 7779 entry no longer flagged) ·node scripts/check-changeset-overwrite.mjs(report-only; 7779 front matter unchanged,@object-ui/types: minor) · the 7779 + 7923 pins and theguideCrudAppRendersreaders in plugin-detail and plugin-form (Tests 249 passed (249)) · 18scripts/__tests__suites naming the edited gates (Tests 991 passed (991))NOT MEASURED: the docs-site build (
Build Docs), because CI owns it. The mdx edit is inside a code fence.Premise check
default: truehalf of the card's premise is already gone. PR docs(api): spell the object-view example's default list view at the node level #7991 (objectui#7923) removed the entry-level flag and added the node-leveldefaultListView, so it is not in this diff. The rest of the premise held.Acceptance notes
.changeset/object-view-unmirrored-keys-7779.mdis falsified by this PR. It says the spec refuses "the named views this package's own README andcontent/docs/api/schema-reference.mdteach" (check:changeset-claims, report-only, flags it). That file is outside this claim's file surface, so it is left untouched here. It publishes verbatim at the next release, and the open release PR chore: release packages #5400 carries it. ⇒ Corrected in patch round 1 (seat decision5827390159, option A): the one sentence now reads in the past tense, and the front matter is byte-identical.listViewsledger docblock inpackages/types/src/zod/objectql.zod.tsand the matchingUnmirroredDeclaredentry comment inpackages/types/src/__tests__/zod-mirror-parity.test.ts. The owner is objectui#7928's mirror flip, which rewrites both. The header ofschema-reference-named-list-view-keys-7923.test.tssays the filter line is "held verbatim" by the 7779 pin and that the running dialect is unmeasured; no carrier has been named for it. Its assertions stay green.content/docs/guide/building-crud-app.mdalso teaches a named view the spec refuses:TaskSchema.listViews.activeuses the tuple[['status', '!=', 'Done']], refused by the spec'sObjectSchema.listViewsatactive.filter.0, while the rule-object spelling parses. It was not one of this card's three pages. ⇒ Folded in by patch round 1 (seat decision5827390159): the rule-object spelling now, and the page joins the pin.my-dealskeeps its value${currentUser.id}, because only the dialect was in scope. Nothing resolves that value on anobject-viewnode.SchemaRendererdoes not evaluatelistViews(the spec'sexpressionBindableTextKeysFor('object-view')is empty), and plugin-view, plugin-grid and plugin-list have zeroresolveFilterPlaceholders/current_user_id/useFilterScopereads. For comparison, app-shell'sObjectView.tsxhas 3. The spec's context token is{current_user_id}. ⇒ Patch round 1 (seat decision5827390159, option B): the example now uses{current_user_id}, with one sentence naming the host that resolves it; theobject-viewnode path's gap is filed as objectui#10506.Generated by Claude Code