Repository navigation
feat(spec,types,plugin-list,app-shell)!: retire the list view's options bag; stored bags fold onto the top-level blocks, and the renderers read the blocks alone - #27206
Conversation
…onto the top-level blocks The flattened list overlay's options member is a retiredKey tombstone naming the move to the top-level KIND block. The ADR-0087 D2 conversion list-view-options-bag-folded replays on stored rows (top-level wins per key, chart whole); the D3 entry ui-list-view-options-bag-folded carries what it cannot decide. Pins move in spec, rest, metadata-protocol and lint. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
… readers; the mirror takes the spec tombstone ListViewSchema.options takes the list overlay's retiredKey tombstone by reference, and ListView, the object page relay, the interface page, ViewPreview, the list-view inspector and plugin-view read and write the per-kind blocks at the top level only. The server folds a stored bag before the row is served. Tests that mounted a bag move to the top-level block; the ones that pinned the bag now pin that it is refused or reaches nothing. A source census in ListView.readersRetired-6152 pins that no plugin-list source reads schema.options. react-blocks.md regenerates without the prop. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
…t from held to retired The member was held under objectui#7928's Q2 (i) while the bag was a live protocol spelling. With the bag retired and the fold on the server, it is a ?: never tombstone naming the top-level blocks, and the listViews docblock names the server fold instead of ViewPreview. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
📓 Docs Drift CheckThis PR changes 1 package(s): 15 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 — 165 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 1a130d0c0faa075b3532a43b5c149d6dcff68de0 && git checkout 1a130d0c0faa075b3532a43b5c149d6dcff68de0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ebfadb02c3a06153ff05af1cb620dfdc29bb6157 8a4ad1fba714e18cc91c305587abbe9936bf1142 && git checkout -B drift-repro ebfadb02c3a06153ff05af1cb620dfdc29bb6157 && git merge --no-ff 8a4ad1fba714e18cc91c305587abbe9936bf1142
node scripts/docs-audit/affected-docs.mjs --json ebfadb02c3a06153ff05af1cb620dfdc29bb6157
|
…ons input The list-view registration publishes no options input since the bag retired, so the console registry manifest drops that row. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
…ry that follows it The major-18 merge pin wants a conversion added after its rule defined directly above the next entry's definition (listViewSortStringClauseToArray); the bag kinds constant moves with it. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
os migrate meta prints the reason verbatim, and author-shown guidance carries no tracker number. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
Contract reviewServed-tier: Inputs read: card #25923 body and all 24 comments, in particular the claim 6456306486, the amendments 6456384663, 6456494843 and 6460225523, the rulings 6412606977 and 6409923362, the premise checks 6430806588, the landings 6416705898 / 6437594464 / 6448239783 / 6462217108, and every os-dev-report (6412566640, 6432621418, 6445173979, 6458717005 — no os-dev-report for PR #27206 is on the card as of 10:42Z); PR #27026 (merged 06:18:03Z as d8a9cc5), its body, its six comments including both contract-review records (6458913292 FAIL r1, 6459158552 PASS r2) and the seat's ACCEPT 6461454849, its 44-file list, and its changeset on the branch; PR #27206 as it stands (head ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: FAIL |
… object page Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
Contract reviewRound 2, on the round-1 FAIL (6467465885). Round 1's judgments D2–D9 and ② stand for every file the four new commits do not touch (the net diff against Served-tier: ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
维护者速读 (席位终稿)
席位意见:接受。契约复核第一轮 FAIL(6467465885),三处 CI 红灯都是机械问题:SDUI 清单没重新生成、转换的位置不对、迁移说明里写了编号。第二轮 PASS(6468417300),三处都已修好,说明文字也已核实为真。#25923 剩下的事: 席位核对 · ACCEPT (Tier H, awaiting an authorized approval) ·
|
…-eqo5sw # Conflicts: # packages/spec/src/shared/retired-key-removal-version.pin.test.ts # scripts/sdui-manifest.record.json # ui/packages/plugin-list/src/ListView.tsx
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
…ons input retired main's #27179 generates content/docs/ui/components/ from sdui.manifest.json; the merged manifest no longer publishes list-view's options input. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT
Requested by Yibo Wang · project thread
Part of #25923
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: skills/objectstack-ui/references/react-blocks.md regenerated by
pnpm gen:react-blocks; thelist-viewtable drops itsoptionsprop row. No otherskills/**file teaches the bag: skills/objectstack-ui/rules/list-views.md and skills/objectui/guides/page-builder.md already write the top-level blocks only.ADR-0087: registered list-view-options-bag-folded, ui-list-view-options-bag-folded
维护者速读
options配置包退役。规范的视图写入口按名拒收options并提示改写为顶层kanban/calendar等配置块;已存储的配置包由 ADR-0087 D2 转换在下发前折叠到顶层配置块;objectui 的类型镜像直接引用规范的墓碑,ListView、对象页中继、界面页、Studio 预览和检查器都只读写顶层配置块。options的 PUT 请求、页面list-view节点或ListView宿主会被拒收或不再生效;已存储的行由服务端折叠,渲染不变。回滚即还原本 PR;D2 转换只在读取时折叠,不改写存储数据。packages/spec/src/ui/view.zod.ts(墓碑)、packages/spec/src/conversions/registry.ts(list-view-options-bag-folded)、ui/packages/app-shell/src/views/objectViewListRenderer.tsx(顶层中继)、ui/packages/plugin-list/src/ListView.tsx。cd ui && pnpm exec vitest run packages/types/src/__tests__/list-view-options-bag-6152.test.ts packages/plugin-list/src/__tests__/ListView.readersRetired-6152.test.tsx packages/app-shell/src/views/ObjectView.storedRowParity-10380.test.tsx,预期全绿:配置包在每个入口被拒收并给出规范原文,源码普查没有schema.options读取,存储的配置包折叠后两页渲染一致。What changes
@objectstack/spec: the flattened list overlay'soptionsis aretiredKey()tombstone that refuses a bag by name with the move-each-options.KIND-to-KINDprescription. The D2 conversionlist-view-options-bag-foldedfolds a stored or source bag onto the top-level blocks before a row is served (top-level wins per key; forchart, whose block replaced the bag whole, the top-level block wins whole). It leavesoptions.grid, a non-object block and a bag on a form view in place with a TODO. The D3 entryui-list-view-options-bag-foldednames what the fold cannot decide (a folded block can still miss a required key). The pagelist-viewcomponent row shares the tombstone, andreact-blocks.tsdrops theoptionsprop row.@object-ui/types:ListViewSchema.optionsis the spec's tombstone by reference, so the mirror, the tolerant and strict faces andsafeValidateSchemarefuse a bag atoptionswith the spec's text, unreworded.NamedListView.optionsis a?: nevertombstone naming the top-level blocks, moved from held to retired in theobject-view-unmirrored-keys-7779census (22 tombstones, was 21). The dataset-chart filter refusal reads thechartblock alone. A page node's flatoptionsis refused with the bag text rather than pointed atproperties.options.@object-ui/plugin-list:ListViewreads every kind from its top-level block alone (render branches, capability gate, projection and expand collectors, fetch effect dependencies). Thelist-viewregistration publishes nooptionsinput.@object-ui/app-shell: the object page relays each per-kind block at the top level of the list schema, each held by value throughisSameOptionsValueso an equal rebuild keeps its identity, and forwards no stored bag (storedLegacyOptionsremoved). The interface page sends onemapblock (its derivation with the authored keys laid over) and no bag.ViewPreviewand the list-view inspector fold nothing; the server does.@object-ui/plugin-view: the host list schema carries the active view's blocks at the top level instead of underoptions.@object-ui/plugin-map: two development warnings name themapblock.@object-ui/console,@objectstack/rest,@objectstack/metadata-protocol,@objectstack/lint: test pins only.Tests
list-view-options-bag-6152pins the mirror IS the spec tombstone, and every door refuses five bag shapes atoptionswith the spec's text, beside a CONTROL that the same blocks written top-level parse. The named alias refusals the bag carried are pinned at the top-level block.ListView.readersRetired-6152gains a SOURCE census (TypeScript AST over every non-test plugin-list file) that finds noschema.optionsread, with a firing control onschema.kanbanand a probe of each retired shape. The same scanner finds 39 reads inListView.tsxonorigin/main. The object page relay census (ObjectView.relayRungCensus-7559) declaresoptionsunread and every block relayed; the interface page census (InterfaceListPage.relayCensus-11572) writesmapand notoptions.list-view-options-bag-foldedon stored rows; in ui,ObjectView.storedRowParity-10380andViewPreview.foldedOnRead-25923render rows folded withapplyConversionsToStoredItemand pin that an unfolded bag renders nothing.Census
TypeScript AST + JSON + YAML walk of every object literal: views carrying a top-level
optionsbag with a kind key.origin/main4b8f8cd (19,856 files)objectViewListRenderer.tsxpackages/spec/src/conversions/registry.ts(the fold's own doc and fixtures)Not reachable, so not counted as zero: hotcrm metadata, tenant
sys_metadatarows, cloud.Acceptance notes
chartfolds whole: the top-levelchartblock replaced the bag outright before this change, so a bag beside a block is dropped, not merged.titleField. The object page floorstitleField: 'name'inkanbanViewOptions(pinned bykanbanLane-8193); the interface page sends none. This is pre-existing andObjectView.storedRowParity-10380pins it as observed.18.view-item-options-bag-refused.tsand18.view-overlay-options-bag-judged.tsare left unedited. They describe the earlier view-item refusal and the earlier judged overlay; this PR adds18.ui-list-view-options-bag-folded.tsbeside them.ListView.tsx,ListView.test.tsxandobjectViewListRenderer.tsx; both are in this head's main merge, which was clean, and plugin-list, types, spec and metadata-protocol were rerun after it. feat(spec)!: the action blocks spell the destructive variantdanger, the word ActionSchema.variant uses #26966 (open) adds its own conversion toregistry.ts; this PR's fold is registered at order 78, so the one that lands second takes the next free order.dispatch-gatescounts 5,341 changed lines over 88 files (+2,704 / -2,637), over the 3,000-line human-merge threshold. Most of it is test fixtures moving from the bag to the block.patch): console, rest, metadata-protocol, lint.FormField's[key: string]: anyindex signature (ui/packages/types/src/form.ts), which ruling 6412606977 deferred because it breaks componentsform.tsx, plugin-form and plugin-grid; and theimmutablefollow-up from 6448239783: plugin-form'snormalizeSectionField(sectionFields.ts:417) copiesimmutable, but no form renderer reads it, so an edit-mode form leaves an immutable field editable. Work item 3 is complete with refactor(plugin-calendar,plugin-gantt)!: retire the flat fallback read; the calendar and gantt renderers read the block only #27026 and this PR.Verification
Head
3f56e4cfe(mainb322b5da6merged in). Every run below was under os-verify-lock.ui tests
--maxWorkers=3(a singlevitest runhit the container's memory limit at 1h49m and was killed, so it measured nothing): app-shellTest Files 1826 passed | 1 skipped·Tests 16795 passed | 9 skipped; components, plugin-list, plugin-view, plugin-map, types, core, react, plugin-grid, plugin-detailTest Files 2041 passed | 2 skipped·Tests 28433 passed | 69 skipped; the other packages, apps, scripts, eslint-rules and examplesTest Files 1843 passed | 4 skipped·Tests 25842 passed | 291 skipped. Each batch exit 0.b322b5da6(fix(plugin-list): show list view sharing type and lock owner as read-only text, drop the dead Share button #27013 touchedListView.tsxandListView.test.tsx): plugin-list + typesTest Files 560 passed (560)·Tests 12306 passed, exit 0.spec and server packages
pnpm --filter @objectstack/spec testafter the last merge:Test Files 741 passed (741)·Tests 22244 passed | 1 todo, exit 0.typecheck: exit 0.pnpm --filter @objectstack/spec check:generatedafter the spec closure build: all 14 generated artifacts up to date, exit 0.@objectstack/metadata-protocolafter the last merge and its closure build:Test Files 277 passed | 4 skipped·Tests 21752 passed | 26 skipped, exit 0. (Run before the closure build, one test from feat(spec, formula, plugin-email, lint): a mail template formats an amount in the record's own currency with currency:@path #26937,runtime-authoring-gate.email-template-writes, failed on a stale@objectstack/lintdist; it passes once that dist is built.)@objectstack/restTest Files 332 passed·Tests 6552 passed | 326 skipped;@objectstack/lintTest Files 170 passed·Tests 7516 passed. Both exit 0.type-check and lint
type-checkfor types, plugin-list, plugin-view, plugin-map, app-shell and console: exit 0, after building the app-shell and console dependency closures (stale dists from main's console list Display menu: 「打开记录」 (drawer | split) as a per-user preference; an object or view declaringpageshows the declaration instead; the name cell's hover ↗ opens the record as a full page #26681 had red them first). plugin-list type-check rerun after the last merge: exit 0.lintfor the same six packages: 0 errors.changeset checks
check-changeset-no-major.mjs --base origin/mainwith this body as the event: exit 0; it readsClause-②: no (narrowing)andMetadata-protocol: narrowedagainst theminorgrade on@objectstack/spec.check-adr-0087-registration(registerslist-view-options-bag-folded,ui-list-view-options-bag-folded),check-empty-changeset,check:changeset-fixed,check:nul-bytes: exit 0.dispatch gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 100 commands, each run with its exit code recorded.--ran: 100 derived, 99 run, 1 NOT-MEASURED, 0 UNRUN. All 99 measured exit 0.pnpm check:dual-build-cjs-loadsexit 3 (its prerequisite is a fullpnpm build). CI runs it.node scripts/check-platform-checklist.mjs --changed-from origin/main: OK, exit 0.dogfood battery
3f56e4cfe(after theb322b5da6merge and the round-1 fixes): closurepnpm --filter '@objectstack/dogfood^...' buildexit 0, thenpnpm --filter @objectstack/dogfood test:Test Files 348 passed | 3 skipped (351)·Tests 2804 passed | 20 skipped (2824), exit 0.07d18e692merge:Test Files 348 passed | 3 skipped (351)·Tests 2803 passed | 20 skipped (2823), exit 0.review round 1 (contract review 6467465885 on ef9b178)
sdui.manifest.jsonstill listed thelist-viewoptionsinput.node scripts/gen-sdui-manifest-node.mjsdrops that row (5 lines, the same diff CI printed) and re-recordsscripts/sdui-manifest.record.json;node scripts/check-sdui-manifest.mjsexit 0.scripts/conversions-major18-merge.test.tsrule 2 wants a conversion added after the rule defined directly above the next entry's definition. Reproduced locally (3 failed of 12, naminglistViewOptionsBagFoldedandlistViewSortStringClauseToArray). The fold and itsLIST_VIEW_OPTIONS_BAG_KINDSconstant now sit directly abovelistViewSortStringClauseToArray: 12 passed. Spec repo projectTest Files 81 passed·Tests 1324 passed; spec local conversions, migrations and uiTest Files 167 passed·Tests 6308 passed.reasoncitedobjectui#10380and#25923. Reproduced locally with the old text and a spec build:migrate-meta-engine-guidance.test.tsfails with "ui-list-view-options-bag-folded: the printed guidance cites a tracker id: expected '[finding] Two PASSING@objectstack/runtimetests printAcquire connection errorand ~150 ERROR-levelsql-driver DATABASE_ERRORlines into the shared Test Core log — they were adopted verbatim as a p1 flake signature #10380' to be undefined". Rephrased without ids: 3 passed. Full@objectstack/clitestTest Files 521 passed | 1 skipped·Tests 6484 passed | 9 skipped, exit 0;check:generatedexit 0.titleField: 'name'floor, for one), so a folded row can draw differently where its bag left such a key unset; 0 reachable rows, pinned byObjectView.storedRowParity-10380.Generated by Claude Code