Repository navigation
fix(core,plugin-view,types): the density fold tests an own key; the flat-property warning and NamedListView's docblock stop naming retired channels (objectui#10868) - #10883
Conversation
`normalizeListViewSchema` tested `legacyDensity in DENSITY_MODE_TO_ROW_HEIGHT`, and `in` walks the prototype chain: `densityMode: 'toString'` folded into `rowHeight` as `Object.prototype.toString` and the key was dropped. The fold now uses the own-key test `rowHeightToDensityMode` already uses in the read direction, so an inherited key is an unrecognized density, like `'cozy'`. Pinned beside the existing density cases: five inherited keys stay unfolded (and a canonical view comes back by reference), the `'cozy'` control is unchanged, and `'compact'` still folds. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
… KIND block; NamedListView's docblock names no channel it does not type plugin-view: `generateViewSchema`'s dev-mode warning told authors to "Move them under options.KIND". Since objectui#7928 this component reads no `options` bag and a named view refuses `options` by name, so the text sent an author to a place that is ignored or refused. It now names the view's own top-level KIND block, the one `viewOptions[viewType]` reads. The text sits behind the development-only branch, which the package build defines away. types: `NamedListView`'s docblock said "Used in ObjectViewSchema.listViews". That member is the protocol's `ObjectListViewSchema` by reference since objectui#7928. The docblock now says the type is exported and types no member of the contract, and points at the pins that hold that. The type is unchanged. Changeset: patch for @object-ui/core (the fold) and @object-ui/types (the docblock). Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
|
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
|
Contract reviewServed-tier: Diff read three-dot against objectui ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
…bject views, detail-view, email, password) and repair the shorthand Omit erasure (objectui#9256) (objectstack-ai#10897) Part of objectstack-ai#9256 Clause-②: yes **Clause-② `yes`, as the claim declared:** twelve published arms stop accepting an authored `children`, and two published TypeScript faces stop erasing the members they inherit. Both narrow an accept set; a contract review is owed before landing. The E3 residual that the maintainer's ruling on objectui#8284 (comment `5861449497`, Q2 A) moved onto this card: keys with a published arm whose renderer reads **neither** content channel. It also carries the ruling's execution parameter 3, the `InputShorthandSchema` / `UiCalendarSchema` TypeScript `Omit` erasure. objectui#9256 stays open for the rest of family D. ## What changed - **Narrowed (12 keys):** `object-grid`, `object-form`, `object-kanban`, `object-map`, `object-tree`, `object-view`, `object-gantt`, `object-calendar`, `object-chart`, `detail-view`, `email`, `password`. - TypeScript face: `body?: never` and `children?: never`, each with a docblock naming what the node renders instead. - zod mirror: `body` and `children` are two `retirementTombstone` members fed ONE string from the new `neitherContentChannelGuidance` builder in `zod/tombstone.zod.ts`. Both stay MEMBERS, so `zod-mirror-parity`'s key sets stay equal. - `body` was already refused on these arms (by `BaseSchema`, objectui#6771), except on the `email` / `password` TypeScript face, which the `Omit` erased. It is restated because `BaseSchema`'s refusal names `children` as the remedy, and `children` is dead here too. - **`Omit` erasure repaired:** `InputShorthandSchema` and `UiCalendarSchema` now inherit through `OmitDeclared` (`form.ts`, not exported). It is a key-remapping mapped type: it drops exactly the named keys and keeps every other named member and the index signature. - `ui:calendar` gains no refusal of its own. Its face now re-exposes what `CalendarSchema` declares, so the published TypeScript face refuses `body`, `children` and a `mode` outside the declared enum, which the erased face accepted. Its mirror (a `.extend()` of that one) already refused them. - I measured the `ui:calendar` renderer anyway (`renderers/form/calendar.tsx`, typed `CalendarSchema`). It reads `defaultValue`, `mode` and `value`, and no channel. - **Held (3 keys): `br`, `hr`, `img`.** See "Held, and the question it leaves" below. ## Per-key measurement, taken on `origin/main` `0c50f1863` before any edit **Instrument.** The TypeScript compiler API, ⛔ not grep. It builds one program per workspace package from that package's own `tsconfig.json`: 40 programs over 1573 source files, on a BUILT tree (turbo build 42/42 first), with `@object-ui/types` resolving to `packages/types/dist`. It files every `.body` / `.children` read (property access, string element access, object destructuring) under the declared type of its receiver. - 547 channel reads were filed. - **Lit controls fire:** `ButtonSchema` 1, `DivSchema` 1, `CardSchema` 1, `ContainerSchema` 1 (each `children`). - **Receiver-reachability control:** the same program sees every narrowed declaration as a receiver of the keys its renderer reads. The zeros below are readings, not blindness. | key | registration(s) claiming it | registration hop → reader, and the type it reads the node as | `body` / `children` reads under that type | receiver reads (reachability) | arm, TS face: before → after | arm, zod face: before → after | disposition | |---|---|---|---|---|---|---|---| | `object-grid` | `plugin-grid:object-grid` (+ console `registerLazy` of the same plugin) | `ObjectGridRenderer` (`any`) → `ObjectGrid` · `ObjectGridSchema` | 0 / 0 | 158 reads, 38 keys | body refused (BaseSchema), children accepted → both refused | same → both refused by name | narrowed | | `object-form` | `plugin-form:object-form` | `ObjectFormRenderer` (`any`) → `ObjectForm` · `ObjectFormSchema` | 0 / 0 | 200 / 44 | same | same | narrowed | | `object-kanban` | `plugin-kanban:object-kanban` (+ lazy) | `ObjectKanbanRenderer` (`any`) → `ObjectKanban` · `ObjectKanbanSchema` | 0 / 0 | 67 / 13 | same | same | narrowed | | `object-map` | `plugin-map:object-map` (+ lazy) | `ObjectMapRenderer` (`any`) → `ObjectMap` · `ObjectMapSchema` | 0 / 0 | 30 / 16 | same | same | narrowed | | `object-tree` | `plugin-tree:object-tree` (+ lazy) | `ObjectTreeRenderer` (`any`) → `ObjectTree` · `ObjectTreeSchema` | 0 / 0 | 13 / 8 | same | same | narrowed | | `object-view` | `plugin-view:object-view` (and the `view` alias) | `ObjectViewRenderer` (`any`) → `ObjectView` · `ObjectViewSchema` | 0 / 0 | 112 / 19 | same | same | narrowed | | `object-gantt` | `plugin-gantt:object-gantt` (+ lazy) | `ObjectGanttRenderer` (`any`) → `ObjectGantt` · `ObjectGanttSchema` | 0 / 0 | 61 / 48 | same | same | narrowed | | `object-calendar` | `plugin-calendar:object-calendar` (+ lazy) | `ObjectCalendarRenderer` (`any`) → `ObjectCalendar` · `ObjectCalendarSchema` | 0 / 0 | 40 / 12 | same | same | narrowed | | `object-chart` | `plugin-charts:object-chart` (+ lazy) | `ObjectChartBlock` (`any`) → `ObjectChart` · `ObjectChartSchema` | 0 / 0 | 123 / 15 | same | same | narrowed | | `detail-view` | `plugin-detail:detail-view` | `DetailViewRenderer` (`any`) → `DetailView` · `DetailViewSchema` | 0 / 0 | 195 / 31 | same | same | narrowed | | `email` | `ui:email` (`field:email` stands down) | `any` wrapper spreads the node into `InputRenderer` · `InputSchema` | 0 / 0 | 23 / 17 | BOTH accepted (erased `Omit`) → both refused | body refused, children accepted → both refused by name | narrowed | | `password` | `ui:password` (`field:password` stands down) | same as `email` | 0 / 0 | 23 / 17 | same as `email` | same as `email` | narrowed | | `br` | `ui:br` | html-elements factory (`any`), void tag: passes `undefined` as the child | reads neither (the one `schema?.children` read is behind the void-tag guard) | n/a (`any`) | body refused, children accepted (family arm) → unchanged | same → unchanged | **held** | | `hr` | `ui:hr` | same | same | n/a | same | same | **held** | | `img` | `ui:img` | same | same | n/a | same | same | **held** | The residual count stays 15: no key reads `children` today. 12 are narrowed and 3 are held. **`any`-typed receivers, attributed rather than assumed.** - Every hop above is `any`-typed. Each hop body was read: none contains a channel read. - The any-typed reads in the eleven hosting files and packages were attributed one by one: - React `children` destructured off internal components' own props (`SchemaRenderer` passes no node child as a React child); - `document.body` and `err.body`; - `TreeNode.children` on the record hierarchy `ObjectTree` builds; - `FeedItem.body`; - `record:alert`'s own `props.body`, which is another registration. - The html factory's `schema?.children` read sits behind `isVoid ? undefined : …`. **Delegation hosts, checked for pass-through.** Every `SchemaRenderer` call in the ten object/detail packages was traced. The node it renders is built one of three ways: - key by key — `ObjectForm` / `ModalForm` / `DrawerForm` / `TabbedForm` / `SplitForm` / `WizardForm` all build their `form` node that way, and the `form` renderer DOES draw `children`, which is why this was checked; - from a sub-key — `DetailView`'s `header` / `footer` / tab `content`, `ObjectChart`'s drill-down table; - or from a generated `object-*` node — `ObjectView` assembles `object-kanban`, `object-calendar`, `object-gallery`, `object-timeline`, `object-gantt`, `object-map`, `object-tree` and `object-chart` from named keys, and every one of those reads neither channel (for gallery and timeline: `packages/plugin-list` and `packages/plugin-timeline` hold no node-channel read). No host spreads its own node into a node that reads `children`. **Generic traversers** (`validateChildren` in core, `sdui-parser` `validateTree`, the metadata-admin preview canvases, the vscode validator) walk children to validate or preview. They render nothing and are node-agnostic, as for every row family D already holds. **objectui#9910 cross-check.** None of the 12 narrowed registrations declares a `children` slot input: a grep over their registration files finds 0 hits, and the lit control is `html-elements.tsx` / `div.tsx`, which do. **Producers.** `pnpm census:body-dialect --keys` over the 15, plus `ui:calendar` and `input`, with `div` / `card` / `page` / `button` / `p` / `h1` as lit controls in the same pass: 8981 files, 2744 candidate nodes. - **0** nodes author `children` on any of the 15. - 1 node authors `body` on `ui:calendar`: it was the family-D TRIPWIRE test line (test bucket), moved by this change. - The controls read `div` 170 / `card` 183 / `page` 47 `children`. - Producers derived: none. Nothing was migrated. ## The `Omit` repair — measured on the BUILT d.ts A probe program under `packages/components` resolved `@object-ui/types` to `packages/types/dist/index.d.ts` (`--traceResolution`). It carried 15 `@ts-expect-error` pins (the 10 object/detail `children`, `email` `children`, `password` `body`, `email` `label: 42`, and the `ui:calendar` `children` and `mode: 'default'`), a lit control (`const n: number = 'x'`), and 12 channel-free controls. - **On this branch:** exit 0 — every directive used, every control compiles, the lit control fires. - **On the base dist:** exit 2 with 15 × TS2578, and the lit control is still used. - The emitted `dist/form.d.ts` declares `OmitDeclared` locally and both heritage clauses use it. ## Red on base, then green — one-shot, the restore proven by state The predictions were written to a file BEFORE the mutation. The mutation was `git checkout 0c50f18 -- THE-SEVEN-DECLARATION-FILES`, with every test file at HEAD. It was proven by 7/7 blob hashes equal to BASE plus anchor counts (`neitherContentChannel` 0, `OmitDeclared` 0). The run sat under `trap … EXIT INT TERM` with absolute paths. | reader | mutated (BASE arms) | restored (HEAD `14fd13c51`) | |---|---|---| | vitest, the new pin file | **RED** exit 1 — 73 failed / 90 passed; exactly the predicted 12 × 5 `children` families + 12 `body`-message rows + 1 nested row | **GREEN** 163 / 163 | | `tsc -p packages/types/tsconfig.test.json` | **RED** exit 2 — 18 × TS2578 and 3 × TS2322 (the `Eq` pins) in the new file, plus 3 in `zod-mirror-parity` naming the two re-collapsed pairs and the stale `KnownDrift` row; 0 elsewhere | **GREEN** exit 0 | | built-d.ts probe (types rebuilt; dist markers 0 → 29 / 6) | **RED** exit 2, 15 × TS2578 | **GREEN** exit 0 | The restore was proven by 7/7 blob hashes equal to HEAD, `git diff HEAD` empty and `git status` clean, both after the restore and at the end.⚠️ **The `body` rows on the ten object/detail arms are GREEN on base, by design:** `BaseSchema` already refused `body` there. Only their MESSAGE changes, and the message rows are the ones that turn red. `?: never` is erased before vitest runs, so the TypeScript half is read by `tsc` alone. The vitest run cannot see it. ## Serial constraints - **Mapped at branch time (`0c50f1863`).** PRs objectui#10714, objectstack-ai#10883 and objectstack-ai#10884 were open then; all three have since merged, and PR objectui#10875 was the base. - `layout.ts` (TabItem) and `layout.zod.ts` (TabItemSchema): untouched, because `br` / `hr` / `img` are held and neither file is edited. - `content-channel-family-d-9256.test.ts`: the only edits are forced ones, clear of PR objectui#10714's hunks, which sit in the ListItem and Tabs sections: - The file's own `ui:calendar` TRIPWIRE said "when the collapse is repaired this line goes RED … turn it back into a `@ts-expect-error` pair". The repair fired it. - The pair moved to the new file. That file lost the tripwire line, its `uiCalendarBody` array entry (32 → 31) and the now-unused `UiCalendarSchema` type import. - No pin was added there. - `objectql.ts`: the insertion after `ObjectViewSchema`'s last member is clear of PR objectui#10883's `NamedListView` docblock edit. - `object-view-unmirrored-keys-7779.test.ts` (PR objectui#10884): untouched. - **Open PRs the branch-time map missed** (re-mapped by contract review `5863631182`): - PR objectui#10890 rewrote the same two `KnownDrift` header figures in `zod-mirror-parity.test.ts` and landed first (`c30c8dd4c`). This branch merged `main` at that commit (merge commit `31bb63bcb`, no rebase, no force-push) and recounted the figures from the merged table; see "Merge round" under Gates. - PRs objectui#10888, objectstack-ai#10889 and objectstack-ai#10892 are textually disjoint, and all three have since merged. `git merge-tree` of the merge head against `main` at `6a7f24e92`, which carries all of them, reports no conflict. - ⛔ `zod/index.zod.ts` and the `packages/cli` ratchet (objectui#10872) are untouched. ## Collateral that the repair and narrowing made true or false — each measured, none widened - **`zod-mirror-parity.test.ts`:** - The two `Omit` COLLAPSE rows (32 + 26 keys) leave `MirroredUndeclared`. Its figures move from 4 / 60 to 2 / 2, and the class note records the emptying. - Restoring the named members NARROWED those faces: a collapsed face accepted every key at `any`. So this is not the "declare the keys" remedy that ledger refuses. - The repaired shorthand face now carries `InputSchema`'s `onChange` runtime slot. It enters `KnownDrift` as inherited drift: one entry, one key. After the merge with PR objectui#10890 (which took `ai.zod.ts#AIFormAssistSchema` out, one entry and two keys), the table holds 49 entries / 88 keys, and both header sites say so. - The union-arm non-vacuity leg had no multi-arm entry left in this ledger. It now takes the same reader's arm-walking on `KnownDrift` and re-arms here when a multi-arm entry lands. - **`object-view-spec-parity.test.ts`:** `body` / `children` are redeclared envelope keys on `object-view` now. They are triaged into `SANCTIONED_LOCAL` as refusal-only surface, like `viewTabBar`, and the declared-surface figure moves 24 → 26. - **`CalendarSchema`'s texts on both faces said the TypeScript `Omit` "collapses … and carries no member".** That became false; they are corrected. - **Two comments** that spelled the old plain-`Omit` heritage (`index.ts`, `form-barrel-mirror-9406.test.ts`) are corrected. - **`scripts/check-handler-key-read-sites.mjs`** caught my first spelling. It was a computed spread (`...helper(…)`) that the gate cannot resolve, so it stopped judging all eleven arms and its `detail-view` `onTabChange` waiver read stale. The fix, the second commit, declares both members explicitly. Now 49 / 49 reads are judged and 0 are left unjudged. ## Held, and the question it leaves `br` / `hr` / `img` read neither channel, but their only published arm is `HtmlElementSchema`: ONE object over 38 tags, whose renderer draws `children` for the other 35 (`p`, `h1`, …). Refusing the key on three tags means splitting that family arm, or refining it per tag. Both change a published contract's shape. - The option the ruling adopted (option A in measurement `5859897857`) reads: "leaving the three void tags to the tier because their arm is the shared HtmlElementSchema family whose per-tag split was ruled out (objectui#9067)". - The parser tier already names them: the registration declares no `children` slot on a void tag, so `validateTree` reports `not-a-container`. - A HELD control in the new pin file records the shared-arm fact, so the hold is visible. That the brief listed them among the keys to narrow is recorded as a conflict in the report, ⛔ not resolved here by guessing. ## Gates (at HEAD `14fd13c51`, exit codes captured by redirect-then-capture; heavy runs through the shared verify lock) | gate | result | |---|---| | `@object-ui/types` build (tsc + vite + dist completeness) | exit 0 — 132 emitted files verified | | `@object-ui/types` `type-check` (`tsc --noEmit` + examples + `tsconfig.test.json`) | exit 0 | | `pnpm exec vitest run packages/types/` (parity, node-slot, arm, mirror, family-D and the new pins) | 259 files / 5670 tests, exit 0 | | `pnpm exec vitest run scripts/` | 177 passed + 2 skipped of 179 files / 5317 tests, exit 0 | | consumer type-check — every package naming a narrowed type (28 packages: the ten object plugins, app-shell, components, core, fields, cli, react, runner, console, schema-catalog, vscode-extension …) | exit 0, 28 × `type-check: Done` | | `pnpm --filter @object-ui/types lint` | 0 errors; 0 findings on any added line (eslint JSON over the 13 touched files) | | `check:control-bytes` · `check:new-line-citations` (0 new) · `changeset:check` · `check-changeset-presence` · `check:changeset-claims` · `check:pending-changeset-literals` | exit 0 each | | `check:doc-types` · `check:doc-snippets` · `check:doc-examples` · `check:skill-examples` · `check:doc-fences` · `check:doc-example-ids` (against the built types) | exit 0 each | | `check:handler-key-reads` · `check:component-surface-parity` · `check:prompt-keys` · `check:registry-bare-names` · `check:spec-symbols` · `check:readme-exports` · `pnpm check` (CLI self-check) | exit 0 each | | governed guard `--test` over the 14 paths | NOT GOVERNED | NOT MEASURED: - `check:sdui-registration-pins` exits 2 without a console build. The diff touches no registration and no `sideEffects` array. Left to CI. - The 4-way `pnpm test` shards beyond `packages/types` and `scripts/`, plus `test:dist` and E2E: left to CI. ### Merge round — head `31bb63bcb` (merges `main` at `c30c8dd4c`) The one conflict was the two `KnownDrift` header figures in `zod-mirror-parity.test.ts`. It was resolved by RECOUNTING the merged table with the test's own AST reader, not by picking a side: | tree | `KnownDrift` | |---|---| | base `0c50f1863` | 49 entries / 89 keys | | PR objectui#10890 removes `ai.zod.ts#AIFormAssistSchema` | −1 entry / −2 keys (48 / 87 on `c30c8dd4c`) | | this branch adds `form.zod.ts#InputShorthandSchema` | +1 entry / +1 key (50 / 90 on `14fd13c51`) | | merged `31bb63bcb` | **49 entries / 88 keys** | The population bullet and the KNOWN_DRIFT restatement both read 49 / 88, and the bullet keeps both histories in landing order. The other ledgers read the same as before: `MirroredUndeclared` 2 / 2, `UnmirroredDeclared` 12 / 84, `RuntimeOnlyDeclared` 3 / 7, `WiderThanDeclared` 6 / 7. The merge head differs from `main` by exactly this PR's 14 files. | gate at `31bb63bcb` | result | |---|---| | `zod-mirror-parity` + `content-channel-e3-residual-9256` | 2 files / 200 tests, exit 0 | | `@object-ui/types` build · `type-check` (incl. `tsconfig.test.json`) | exit 0 · exit 0 | | `pnpm exec vitest run packages/types/` (incl. PR objectui#10890's `ai-zod-arms-10859` / `ai-node-faces-agree-10874` and the family-D file PR objectui#10714 edited) | 261 files / 5696 tests, exit 0 | | `pnpm exec vitest run scripts/` | 177 passed + 2 skipped of 179 files / 5322 tests, exit 0 | | `check:control-bytes` · `check:new-line-citations` · `changeset:check` · `check-changeset-presence` · `check:changeset-claims` · `check:pending-changeset-literals` · `check:handler-key-reads` | exit 0 each | ## Acceptance notes — out of scope, not fixed here - **`input` reads neither channel as well.** `InputSchema`: 0 channel reads, 17 keys read; the registration declares no `children` slot. - It is this card's remaining family-D name, and it was not in this claim. - Its old hold-out ground ("a TS `Omit` carries nothing") is gone with this repair: a tombstone on `InputSchema` now propagates on both faces. - Carrier: the next objectui#9256 slice. - **`PartialSchema`'s docblock in `index.ts`** says every generic re-spelling of its `Omit` collapses for the same `keyof T` reason. `OmitDeclared` is a generic spelling that does not: this PR measures it on two faces. - Carrier: the next objectui#9256 slice, which touches the same `Omit` subject. objectui#6397, that alias's card, is closed. - Noted, not filed. - **The family-D test header** still records `InputSchema` as "family E, frozen" and `DetailViewSchema` as unattributable. Both readings are superseded by this change. - Carrier: the next objectui#9256 slice. - Noted, not edited: PR objectui#10714 held that file while this PR was written. It has since merged, so the next slice edits the header freely. --- _Generated by [Claude Code](https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #10868
Clause-②: no
Three hygiene leftovers from the objectui#7924 and objectui#7928 retirements, as the card's Fix section lists them. Claim
5861960491, seatdomain:ui#1. The implementing dev ran under sessionsession_01DuWo5bdP9SdVebamn99GGk(the dispatching seat's id).What changed
@object-ui/core: the density fold tests an own key.normalizeListViewSchemasetfoldRowHeightwithlegacyDensity in DENSITY_MODE_TO_ROW_HEIGHT. It now usesObject.prototype.hasOwnProperty.call(DENSITY_MODE_TO_ROW_HEIGHT, legacyDensity). That is the idiomrowHeightToDensityModeandLIST_VIEW_KINDSalready use in the same file. It was the onlyinoperator in that file's code.@object-ui/plugin-view: the dev-mode flat-property warning ingenerateViewSchema. It said "Move them under options.KIND". It now says "Move them under its top-level KIND block ({ KIND: { ... } })", which is the blockviewOptions[viewType]reads. A comment above it says why.#region.#regionchanged. objectui#10758 works there.@object-ui/types:NamedListView's docblock. It said "Used in ObjectViewSchema.listViews for named views".object-view-unmirrored-keys-7779.test.ts:_ListViewsIsNoLongerTheLocalRecordand_ListViewsIsTheSpecRecord..changeset/10868-list-view-leftovers.md:patchfor@object-ui/coreand@object-ui/types.@object-ui/plugin-viewis not listed, because the warning does not ship (measured below).Measurements
The fold, on the built package. These readings come from
@object-ui/core'sdist, as resolved fromplugin-view, withnormalizeListViewSchema({ densityMode: X }):de1b879a6'toString','constructor','hasOwnProperty','valueOf'rowHeightis a function, key droppedrowHeightundefined, key kept'__proto__'rowHeightisObject.prototype, key droppedrowHeightundefined, key kept'cozy'(control)'compact'/'spacious''compact'/'tall', key droppedThe pin is red on base and green on head. The new cases sit in
normalize-list-view.test.tsunderdensityMode → rowHeight.viewType: 'grid'the input comes back by reference.'cozy'stays unfolded and'compact'still folds.Tests 5 failed | 87 passed (92). The 5 failures are the inherited keys (expected [Function toString] to be undefined), and the control stayed green.Tests 92 passed (92).Where the fold is still reachable. This answers the card's reachability question.
ListView, on its own schema;ObjectView, on the hostviewsentry (therowHeightrelay, inside the HOST-COMPOSITION fence);ObjectView, on the stored view definition.densityModeby name:unrecognized_keysatlistViews.v1, for'compact'too. The controlrowHeight: 'compact'is accepted.@objectstack/spec17.4.0'sdisthas 0densityModehits. The controlrowHeighthas 4 hits indist/index.js.list-viewnode's zod schema still declaresdensityModeas a three-value legacy enum. It accepts'compact'and refuses'toString'withinvalid_value.list-viewnode, a hostviewsentry or a stored view body.'toString'reaches it only on a path that does not validate.The warning's remedy, run once. I used a temporary probe (not committed). It renders the real
ObjectViewwith a hostviewskanban entry and NODE_ENV stubbed todevelopment.groupField: 'stage'gives lanestatus. The warning now reads "The view uses flat properties ["groupField"]. Move them under its top-level kanban block ({ kanban: { ... } }) …".kanban: { groupField: 'stage' }gives lanestageand no warning.options: { kanban: { groupField: 'stage' } }gives lanestatusand no warning. The old text sent the author to a place nothing reads.The warning does not ship. plugin-view's
vite.config.tsdefinesprocess.env.NODE_ENVas"production", and the build removes the development branch.turbo run build,Spec ComplianceandMove them underhave 0 hits indist/index.jsanddist/index.umd.cjs. The controlObjectView data fetch errorhits both files.filesisdist, README, CHANGELOG and LICENSE.check-changeset-presenceis satisfied by the one changeset: "4 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)".The docblock ships. In
types/dist/objectql.d.ts, the old sentence has 0 hits and the new pin name has 1.Verification, all at head
96c9f9953Heavy runs went through
os-verify-lock.sh, and each exit was captured with the output redirected first.turbo run build --filter=@object-ui/plugin-view...gave 16 of 16 tasks successful, VERDICT command-exit 0.type-check(tsc --noEmitplustsconfig.test.json) exited 0 for each of@object-ui/types,@object-ui/coreand@object-ui/plugin-view. I captured each exit on its own, and the script name echoed. core's test program lists the pin file (--listFiles).vitest run packages/core/ packages/types/ packages/plugin-view/: 491 files, 9613 tests passed, VERDICT command-exit 0.packages/plugin-list/plus the 13 app-shell and react test files that namedensityMode,normalizeListViewSchemaorrowHeight. 117 files, 1310 tests passed.vitest run scripts/__tests__/(the whole directory): 177 files passed and 2 skipped (179), 5317 tests passed.check-changeset-presence,-no-major,-fixed,-overwrite("1 changeset(s) added, 0 modified"),-claims, andcheck:pending-changeset-literals;check:control-bytes,check:new-line-citations("0 new citation(s)") andcheck:spec-symbols;check:test-path-rootsand the threecheck:vi-mock-*;check:handler-key-reads,check:i18n-keys,check:icon-record-names,check:unreferenced-sources,check:element-data-source-declaration,check:doc-types,check:prompt-keys,check:action-forward-parity,check:metadata-write-doorsandcheck:registry-bare-names;check-lint-coverage,check-type-check-coverage,check:self-importandcheck:phantom-deps;check-governed-queue-guard --teston the 5 paths: NOT GOVERNED.check:readme-exports. Prerequisite not met: 20 packages are unbuilt, and its population floor refused the run. No README is touched.check:sdui-registration-pins. It needs a console build.--no-inline-config --format jsonon the 4 touched TS/TSX files: 0 errors and 94 warnings, the same per-file counts as base (60 and 34).eslint.config.jshas 0projectService/parserOptions(the controllanguageOptionshas 1), so linting is not type-aware.eslint-rules/rule reads the disk, so no untouched file's verdict can move.Acceptance notes
groupByon kanban anddateFieldon calendar.kanban: { groupBy: 'stage' }gives lanestatusand no warning, while the controlgroupByFieldgivesstage.calendar: { dateField: 'due' }gives a node withoutstartDateFieldand no warning, while the controlstartDateFieldgivesdue..changeset/10002-map-style-remedy-text.mddescribes how the map warning's remedy was made executable. Carrier: none.options.kanban.conditionalFormattingas the nested home. It appears in thegenerateViewSchemakanban-branch comment ("nestedoptions.kanban.conditionalFormattingwins") and in the header ofObjectView.kanbanConditionalFormatting.test.tsx. Since objectui#7928 the nested home is the top-levelkanbanblock. These are comments only, so I left them untouched. The file is shared with objectui#10758's claim, so the in-place exemption does not apply. Carrier: none.legacyViewOptions. It describesoptions.KINDas retired and folded atViewPreview, which is correct, so it is unchanged.Generated by Claude Code