Skip to content

Commit e967cbd

Browse files
feat(spec): declare the console's round-trip keys on the stored view wire (#20456) (#20474)
Fixes #20456 Clause-②: yes (narrowing) Stage (ii) of ruling 甲 on #20051 (`5856781584`), the **spec end** of this `Seam:` card: every key objectui's console writes onto a stored `view` row and reads back is now declared, with its meaning, on the wire member that judges that row, so a parse of the row keeps it. The census below is the measurement the declarations follow. ⛔ Nothing about what is persisted changes: `saveMetaItem` still stores the request body, and the three GUARD pins are green and untouched (evidence under Verification). The objectui end ("objectui aligns its reads to the declared spellings") is the seat's follow-up card, filed at ACCEPT with `Blocked-by:` this PR; its items are listed at the end. ## Census: what the console writes onto a stored `view` row and reads back Measured against objectui at the `.objectui-sha` pin `dd3f7e1be3561d63267d7162f3fc0ac52e72834d`, fetched into an isolated clone. Spec side read on this branch, merged with `origin/main` `e956924e`. **Method, two legs.** 1. **Reader leg (syntax walk).** A TypeScript compiler-API walk (syntax only) of the console's stored-view read seams: `data-objectstack/src/index.ts` (`listViews`, `listViewOverrides`, `getView`, `updateView`, `updateViewConfig`, `createView`, `mergeViewPatch`, `narrowPersonalizationOverlay`, `isPersonalizationOverlayRow`, `viewItemObjectName`, `unwrapViewDraft` and the three key constants), `app-shell/src/utils/viewIdentity.ts`, `app-shell/src/views/ObjectView.tsx` (the view-row functions, the saved-view load, the tab builder and sort, the switcher handlers), `plugin-view/src/ViewTabBar.tsx`, `plugin-view/src/config/view-config-utils.ts` (filter / sort row read-back), `app-shell/src/providers/MetadataProvider.tsx`, `InterfaceListPage.tsx`, `apps/console` `FormPage.tsx` and `PublicFormsPage.tsx`, `ResourceEditPage.tsx`, and the export-options readers. It collects every non-call property read, string-keyed element access, destructured key, `in` test and key-list literal: **154 distinct keys**. The spec's own view vocabulary (**280 keys**, walked off the Zod defs of the four `ViewMetadataSchema` members) was subtracted, leaving 105, each classified by hand (most are props, locals and client objects). 2. **Writer leg (parse diff).** Each console write body, built from its writer site, run through `ViewMetadataSchema` and diffed, parse output against input: what the parse drops, rewrites or adds. **Controls.** LIT: `isPinned`, a known key, is found at 11 sites; an injected fixture key `zzLitControlKey` is found at its 1 site. DARK: a fabricated key `pinnedAtEpoch` is found at 0 sites. Zero readings in the table are readings, not a dead scan. ### Round-trip keys: declared by this PR, or declared before it Parse columns are before and after this PR. `viewItem` is a ViewItem record row (`{ name, object, viewKind, config }`); `listOverlay` is a flattened list row. | key | written by (objectui at the pin) | read back at | parse before | parse after | meaning | |:--|:--|:--|:--|:--|:--| | `isPinned` | pin toggle `ObjectView.tsx:2120` via `updateView` merge `index.ts:2993`; config save carries it `ObjectView.tsx:1102`, `:1161` | `ObjectView.tsx:910`, `:3398`; `ViewTabBar.tsx:330` (pinned group) | kept on `viewItem`, **dropped on `listOverlay`** | kept on both | pinned in the view switcher; the row has no per-user scope | | `sortOrder` | drag-reorder `ObjectView.tsx:966` (`reorderViewPatches`); config save `:1102` | `ObjectView.tsx:913`, `:1925`-`:1934` (tab order) | kept on `viewItem`, **dropped on `listOverlay`** | kept on both | position among the object's saved views, 0-based over saved views only; `order` stays the authored default | | `visibility` | no control sets it; config save carries a stored value `ObjectView.tsx:1102`; a saved view's toolbar save writes the whole tab `:1085` | `ObjectView.tsx:912`, `:3399`; `ViewTabBar.tsx:336` (group order), `:385` (private divider), `:442` (lock icon) | **dropped on both** | kept on both | switcher grouping only (`private` / `team` / `organization` / `public`), **not** access control | | `_isOverride` | `updateViewConfig` `index.ts:5340`, on the row it writes for a toolbar change to a code-defined view | `isPersonalizationOverlayRow` `index.ts:2778`, used by `listViews` `:5448` and `narrowPersonalizationOverlay` `:2895` | **dropped on `listOverlay`** | kept | marks the row as that view's settings overlay, not a saved view of its own | | `isDefault` | set-default `ObjectView.tsx:946` (`setDefaultViewPatches`) | `ObjectView.tsx:911`, `:3397`; `MetadataProvider.tsx:420`; `index.ts:5470` | kept (declared; no meaning on the overlay) | kept, meaning added | the object's default view in the switcher | | `columnState` | toolbar `ObjectView.tsx:2803`, `:3112`; config save `:1102` | `ObjectView.tsx:2786`; `index.ts:2832` (overlay-owned keys) | kept (declared by #9933) | kept | column order and widths; the "per-user" wording was corrected | These six are the new export **`VIEW_CONSOLE_ROUND_TRIP_KEYS`** (`@objectstack/spec/ui`), each mapped to the members its rows use. That record is the spec symbol stage (iii)'s ADR-0005 appendix (c) note can cite. ### Found by the census and mapped to an existing declared spelling (no new key) | key | where | declared spelling | why no new declaration | |:--|:--|:--|:--| | `objectName` (also `object_name`) | stamped on rows read `ObjectView.tsx:1802`; written back by a saved view's toolbar save `:1085`; read `index.ts:2698`, `ResourceEditPage.tsx:933` | `object` (declared, required on both overlays) | every reader already falls back to `object`; a second spelling of one field is what this contract refuses | | top-level `id` / `_id` | written by the same tab spread; read only by `viewRowId` `viewIdentity.ts:95`, after `name` | `name` | the write path stamps `name` on every row, so `id` is never consulted for a stored row | | `filter[].id` / `sort[].id` | builder rows `view-config-utils.ts:145`, `:159`, `:319` | `VIEW_CONSOLE_ROW_DECORATIONS`, removed before the parse by `stripViewConsoleDecorations` | read back as `item.id \|\| crypto.randomUUID()` (`:159`, `:319`): a row without one gets a fresh id, so a parsed row loses nothing the console shows | | `exportOptions` as a bare array | a stored legacy value, read `ObjectView.tsx:2839` | the object form `{ formats, … }`, which the parse already lifts the array to | the export menu reads `exportOptions.formats` (`ObjectGrid.tsx:3888`); only `ListView.tsx:1783` folds the array itself | ### Found, and not stored-row round-trip keys - `_draft` (`index.ts:5455`): a read decoration. The read path stamps it, `saveMetaItem` strips it before anything else (`stripReadDecorations`), and it is never stored. - **Read, never written by the console:** `showSearch` / `showFilters` / `showSort` (`ObjectView.tsx:907`-`:909`, `:3139`-`:3141`), `allowExport` (`:2838`-`:2839`), `created_at` (`:1936`, the saved-view sort tie-break), `updatedAt` / `updated_at`, `viewType` and an `item.spec` envelope (`PublicFormsPage.tsx:142`, `:150`, `:163`; `FormPage.tsx:1462`). None is declared on any view member. A stored row carries one only if an author wrote it through the save door, where the parse strips it and the save stores it. Stage (iv) would drop them from such rows, so they belong in stage (iv)'s production census, and the objectui card decides their reads (declared spellings exist for three: `userActions.search` / `.sort` / `.filter`). ### Production `sys_metadata` **NOT MEASURED.** This container holds no connection to any deployed environment: no `OS_DATABASE_URL`, `TURSO_*` or `PG*` variable is set (an environment grep answers empty), and nothing here reaches a customer store. The count of stored views carrying undeclared top-level keys, which stage (iv) needs, has to be taken by a seat with production access. The census above names what to count: rows carrying `objectName`, a top-level `id`, a legacy `exportOptions` array, any of the read-only keys listed just above, and any `visibility` outside the four groups or `_isOverride` other than `true` (now refused on re-save). ## What changes in `packages/spec` - `viewSwitcherRowStateFields()` declares `isPinned`, `sortOrder` and `visibility` once, each with `.describe()` meaning, spread into the ViewItem wire member (`viewItemWireFields()`) and the flattened list overlay. The form overlay gets none of them: the switcher lists list-family views only, and no console write puts them on a form row. - `listOverlayRoundTripFields()` adds `_isOverride: true` on the flattened list overlay. The overlay's existing `isDefault` gains its meaning. - `VIEW_CONSOLE_ROUND_TRIP_KEYS` is exported (api-surface / export-origins regenerated with the tools). - The authoring door (`ViewItemSchema`) names `visibility` in its refusal guidance, and says it is not access control. - `columnState`'s declared meanings no longer call it per-user state: a stored view row is environment metadata (ADR-0017 as amended). ## Verification All at `2530b598` (this branch merged with `origin/main` `e956924e`) unless noted. The only later commit, `a47aeb5d`, rewrites one code comment in `view.zod.ts`. The derived gate union runs at that head, and its result is in the report. Head `fc5a47d0` then merges `origin/main` `75b21692` through `scripts/pm/os-regen-merge.sh` (api-surface and export-origins regenerated on the merged tree; `check:generated` green) and adds the changeset's narrowing arm. The changeset gates at that head are reported on #20456. - `pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2`: **570 files, 16730 passed, 1 todo**, exit 0. - `pnpm --filter @objectstack/spec exec vitest run --project repo --maxWorkers=2`: **38 files, 690 passed**, exit 0. - `pnpm --filter @objectstack/spec typecheck`: exit 0. - **The three GUARD pins, unchanged and green** (dependency closure `@objectstack/objectql^...` built first, exit 0): `metadata-protocol` `protocol.graft-folded-form-sections.test.ts` (holds "GUARD: Studio-only round-trip keys still survive the save") and `protocol.graft-normalized-operators.test.ts` (holds "keeps Studio-only auxiliary fields a `parsed.data` swap would strip"): 2 files, 42 passed. `objectql` `protocol-meta.test.ts` (holds "preserves Studio-only auxiliary fields verbatim"): 95 passed. - `check:generated`: the first run named exactly 3 stale artifacts (api-surface, export-origins, reference docs), and they were regenerated with their `gen:` commands. `check:authorable-surface` was green: no authorable key moved. - **Ablation** (on committed `d19cbad8`, via `scripts/ablation-replace.mjs`): the `visibility` declaration renamed away (anchor hit 1 time, blob `d2aacf7a` became `3dd7dd8a`). The closure pin went red, 6 of 34: the declared-member and parse-keeps pairs for `viewItem` and `listOverlay`, and both typed-refusal cases. The restore is proven: blob back to `d2aacf7a` equal to HEAD, `git diff HEAD` empty. The test reads the spec source directly (a relative import), so no `dist/` leg applies. - **Reverse type check** against the rebuilt `dist/ui/index.d.ts` from a scratch consumer: `visibility: 'everyone'` on a `ViewItemWire` fails with TS2322 (exit 2); without that line, `visibility: 'team'` and `VIEW_CONSOLE_ROUND_TRIP_KEYS._isOverride` typecheck (exit 0). ## Acceptance notes - **Ill-typed values are now refused.** A declared key is typed, so a `view` save carrying a non-boolean `isPinned`, a non-integer `sortOrder`, a `visibility` outside the four groups, or an `_isOverride` other than `true` is refused (422) where it used to be stripped and stored. The console writes none of those. Following the seat's answer on #20456 (comment `5874463510`), the changeset declares this: the `yes (narrowing)` arm, a **BREAKING** line naming the refused class with its remedy (correct the value or delete the key), and the ADR-0087 disposition `not-required (no-migration-prescription)`. The level stays `minor`. - **`visibility` is a naming trap.** `private` gets a lock icon in the switcher (`ViewTabBar.tsx:442`) and restricts nobody. It is declared as the ruling orders, with an honest meaning, and the authoring door's guidance says so. - The authoring-door refusal texts for `isPinned` / `sortOrder` / `columnState` (`VIEW_ITEM_SURFACE`, `ListViewShapeSchema` guidance) still say "per-user". Noted, not changed here: they are refusal prose, not the wire. - **For stage (iv).** (a) The metadata-protocol GUARD fixture is a FORM overlay carrying `isPinned` / `sortOrder`. No console write puts those on a form row, so when the pins flip, that fixture moves to a list overlay or drops the two keys. (b) The parse adds `type: 'grid'` to a column-less list patch, and form sections gain `collapsible` / `collapsed` / `columns` defaults: stored parsed, those defaults land in rows. (c) `_isOverride` must survive, or a stored toolbar overlay comes back as a saved view with its merge un-narrowed; this PR is what makes it survive. ## objectui end (the seat's follow-up card, `Blocked-by:` this PR) Align the console's reads to the declared spellings: - read the bound object from `object`, and stop stamping and writing back `objectName` (`ObjectView.tsx:1802`, `index.ts:2698`, `ResourceEditPage.tsx:933`); - stop writing the tab's `id` into a saved view's row (`buildPersistedViewBody`, `ObjectView.tsx:1085`); - `listViews`' flatten of a ViewItem record (`index.ts:5466`-`:5472`) carries only `name` / `label` / `isDefault` / `_draft`. The record's declared row state (`isPinned`, `sortOrder`, `visibility`, `columnState`) is written there but not surfaced by that reader; - retire the bare-array `exportOptions` fold (`ListView.tsx:1783`) once rows are stored parsed; - decide the read-only keys: `showSearch` / `showFilters` / `showSort` → `userActions.*`, and `allowExport`, which has no declared spelling. --- _Generated by [Claude Code](https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4b2d904 commit e967cbd

9 files changed

Lines changed: 385 additions & 33 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
'@objectstack/spec': minor
3+
---
4+
5+
feat(spec): the console's round-trip keys on a stored `view` row are declared on the wire, so a parse keeps them (#20456)
6+
7+
Clause-②: yes (narrowing)
8+
9+
<!-- adr-0087: not-required (no-migration-prescription) Nothing authored moves: no key an authoring door accepts changes its spelling, type or legality, because the four keys are console state the authoring doors refuse by name. The only producer, objectui's console, writes none of the values now refused (census at the `.objectui-sha` pin: a boolean pin, an integer reorder index, the marker as `true`, and `visibility` only carried forward from a stored value). So `objectstack migrate meta` has no mechanical rewrite to perform; a stored row holding a refused value is repaired by correcting it or deleting the key. The other categories are closed on facts: `@objectstack/spec` publishes (not `unpublished`); no ADR-0087 id is minted here or pre-dates the base to cover this (not `registered` / `already-registered`); and a Zod schema's accept set changes, so neither `runtime-interface-only` nor `type-surface-only` applies. -->
10+
11+
**BREAKING** accept-set narrowing on the `view` write door (`PUT /api/v1/meta/view/:name`, the Studio and MCP save) and on every door that parses `ViewMetadataSchema`, shipped as `minor` under the repo's launch-window convention. The newly declared keys are typed, so a non-boolean `isPinned`, a non-integer `sortOrder`, a `visibility` outside `private` / `team` / `organization` / `public`, or an `_isOverride` other than `true` is now refused at the parse (`422 INVALID_METADATA` at the save door), where the strip used to swallow the key and the save stored the body as sent. To fix a refused body, correct the value or delete the key. The console writes none of these values: its pin toggle writes a boolean, its reorder an integer index, and it stamps the marker as `true`. The diff also widens: the keys are now declared, and `VIEW_CONSOLE_ROUND_TRIP_KEYS` is a new export.
12+
13+
`saveMetaItem` stores a `view` body exactly as it was sent (ADR-0005 appendix (c)), and the members of `ViewMetadataSchema` that judge a stored row `.strip()` every key they do not declare. So the keys the console writes onto a stored view and reads back were in the store and nowhere in the contract. A census of objectui's console (at the `.objectui-sha` pin) measured which ones the parse dropped:
14+
15+
- `isPinned` and `sortOrder` on a flattened list overlay (they were already declared on the ViewItem record);
16+
- `visibility`, on both the flattened list overlay and the ViewItem record;
17+
- `_isOverride`, the marker that tells the console a row is the settings overlay of a code-defined view and not a saved view of its own.
18+
19+
## What it does now
20+
21+
- The ViewItem wire member (`ViewItemWireSchema`) and the flattened list overlay (`VIEW_METADATA_MEMBERS.listOverlay`) declare `isPinned`, `sortOrder` and `visibility` from one shared declaration, each with its meaning. The flattened list overlay also declares `_isOverride: true`, and its existing `isDefault` now carries its meaning. A parse of a console-written row keeps every one of them.
22+
- **New export `VIEW_CONSOLE_ROUND_TRIP_KEYS`** (`@objectstack/spec/ui`): each round-trip key, mapped to the members whose rows the console writes it on (`isDefault`, `isPinned`, `sortOrder`, `visibility`, `columnState`, `_isOverride`).
23+
- `visibility` is display grouping only (`private` / `team` / `organization` / `public` in the view switcher). It restricts nobody, and its declared meaning says so.
24+
- None of these keys is authorable. `defineViewItem` still refuses each of them by name, and `visibility` now gets a prescription that says what it is.
25+
26+
## What does not change
27+
28+
- **What is persisted.** The save still stores the request body verbatim. Storing the parsed body is a later, separate change.
29+
- The alias spellings the census found keep their declared spellings: `objectName` is `object`, and a top-level `id` is `name`. The console's filter / sort builder row ids stay `VIEW_CONSOLE_ROW_DECORATIONS`, removed before the parse.

‎content/docs/references/ui/view.mdx‎

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2256,9 +2256,10 @@ This schema accepts one of the following structures:
22562256
| **_packageId** | `string` | optional | Owning package machine id. |
22572257
| **_packageVersion** | `string` | optional | Owning package version. |
22582258
| **_lockDocsUrl** | `string` | optional | Optional documentation link surfaced next to _lockReason. |
2259-
| **isPinned** | `boolean` | optional | Studio round-trip: view pinned in the switcher (per-user state, written by the console — not authored). |
2260-
| **sortOrder** | `integer` | optional | Studio round-trip: position within the switcher (per-user state, written by the console — not authored). |
2261-
| **columnState** | `{ order?: string[]; widths?: Record<string, number> }` | optional | Studio round-trip: per-user column order/widths (runtime-only state, written by the console grid — not authored) |
2259+
| **isPinned** | `boolean` | optional | Console round-trip: the view is pinned in the object's view switcher. Written by the console's pin toggle through the `view` metadata API and read back to draw the pinned group. Stored on the view's row, which has no per-user scope. Not authored. |
2260+
| **sortOrder** | `integer` | optional | Console round-trip: the view's position among the object's saved views in the switcher, 0-based and counted over saved views only (a code-defined view carries none). Written by the console's drag-reorder and read back to order the tabs. Not authored: `order` is the authored default position. |
2261+
| **visibility** | `Enum<'private' \| 'team' \| 'organization' \| 'public'>` | optional | Console round-trip: the group the switcher files this view's tab under (private, team, organization or public). Display grouping only, NOT access control: nothing restricts who can list or open the view by this value. No console control sets it; the console carries a stored value forward when it re-saves the row. Not authored. |
2262+
| **columnState** | `{ order?: string[]; widths?: Record<string, number> }` | optional | Studio round-trip: column order/widths (runtime-only state, written by the console grid and stored on the view's row, which has no per-user scope — not authored) |
22622263

22632264
### Nested Shape: `ViewItemWire[viewKind='list'].config`
22642265

@@ -2327,8 +2328,8 @@ This schema accepts one of the following structures:
23272328

23282329
| Property | Type | Required | Description |
23292330
| :--- | :--- | :--- | :--- |
2330-
| **order** | `string[]` | optional | Column order as field names, leftmost first (runtime-only per-user state — written by the console grid, never authored). |
2331-
| **widths** | `Record<string, number>` | optional | Column widths in pixels, keyed by field name (runtime-only per-user state — written by the console grid, never authored). |
2331+
| **order** | `string[]` | optional | Column order as field names, leftmost first (runtime-only state — written by the console grid, never authored). |
2332+
| **widths** | `Record<string, number>` | optional | Column widths in pixels, keyed by field name (runtime-only state — written by the console grid, never authored). |
23322333

23332334
---
23342335

@@ -2356,9 +2357,10 @@ This schema accepts one of the following structures:
23562357
| **_packageId** | `string` | optional | Owning package machine id. |
23572358
| **_packageVersion** | `string` | optional | Owning package version. |
23582359
| **_lockDocsUrl** | `string` | optional | Optional documentation link surfaced next to _lockReason. |
2359-
| **isPinned** | `boolean` | optional | Studio round-trip: view pinned in the switcher (per-user state, written by the console — not authored). |
2360-
| **sortOrder** | `integer` | optional | Studio round-trip: position within the switcher (per-user state, written by the console — not authored). |
2361-
| **columnState** | `{ order?: string[]; widths?: Record<string, number> }` | optional | Studio round-trip: per-user column order/widths (runtime-only state, written by the console grid — not authored) |
2360+
| **isPinned** | `boolean` | optional | Console round-trip: the view is pinned in the object's view switcher. Written by the console's pin toggle through the `view` metadata API and read back to draw the pinned group. Stored on the view's row, which has no per-user scope. Not authored. |
2361+
| **sortOrder** | `integer` | optional | Console round-trip: the view's position among the object's saved views in the switcher, 0-based and counted over saved views only (a code-defined view carries none). Written by the console's drag-reorder and read back to order the tabs. Not authored: `order` is the authored default position. |
2362+
| **visibility** | `Enum<'private' \| 'team' \| 'organization' \| 'public'>` | optional | Console round-trip: the group the switcher files this view's tab under (private, team, organization or public). Display grouping only, NOT access control: nothing restricts who can list or open the view by this value. No console control sets it; the console carries a stored value forward when it re-saves the row. Not authored. |
2363+
| **columnState** | `{ order?: string[]; widths?: Record<string, number> }` | optional | Studio round-trip: column order/widths (runtime-only state, written by the console grid and stored on the view's row, which has no per-user scope — not authored) |
23622364

23632365
### Nested Shape: `ViewItemWire[viewKind='form'].config`
23642366

@@ -2402,8 +2404,8 @@ This schema accepts one of the following structures:
24022404

24032405
| Property | Type | Required | Description |
24042406
| :--- | :--- | :--- | :--- |
2405-
| **order** | `string[]` | optional | Column order as field names, leftmost first (runtime-only per-user state — written by the console grid, never authored). |
2406-
| **widths** | `Record<string, number>` | optional | Column widths in pixels, keyed by field name (runtime-only per-user state — written by the console grid, never authored). |
2407+
| **order** | `string[]` | optional | Column order as field names, leftmost first (runtime-only state — written by the console grid, never authored). |
2408+
| **widths** | `Record<string, number>` | optional | Column widths in pixels, keyed by field name (runtime-only state — written by the console grid, never authored). |
24072409

24082410
---
24092411

‎packages/spec/api-surface/ui.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@
419419
"UserFilters (type)",
420420
"UserFiltersParsed (type)",
421421
"UserFiltersSchema (const)",
422+
"VIEW_CONSOLE_ROUND_TRIP_KEYS (const)",
422423
"VIEW_CONSOLE_ROW_DECORATIONS (const)",
423424
"VIEW_FILTER_LIST_VALUE_OPERATORS (const)",
424425
"VIEW_FILTER_OPERATORS (const)",

‎packages/spec/export-origins/ui.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@
405405
"UserFilters": "src/ui/view.zod.ts#UserFilters (type)",
406406
"UserFiltersParsed": "src/ui/view.zod.ts#UserFiltersParsed (type)",
407407
"UserFiltersSchema": "src/ui/view.zod.ts#UserFiltersSchema (const)",
408+
"VIEW_CONSOLE_ROUND_TRIP_KEYS": "src/ui/view.zod.ts#VIEW_CONSOLE_ROUND_TRIP_KEYS (const)",
408409
"VIEW_CONSOLE_ROW_DECORATIONS": "src/ui/view.zod.ts#VIEW_CONSOLE_ROW_DECORATIONS (const)",
409410
"VIEW_FILTER_LIST_VALUE_OPERATORS": "src/ui/view.zod.ts#VIEW_FILTER_LIST_VALUE_OPERATORS (const)",
410411
"VIEW_FILTER_OPERATORS": "src/ui/view.zod.ts#VIEW_FILTER_OPERATORS (const)",

‎packages/spec/src/system/metadata-form-zod-reconciliation.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,21 +304,21 @@ const LEDGER: ReadonlyArray<OmitEntry | SubsetEntry> = [
304304
type: 'view',
305305
path: ROOT_PATH,
306306
key: 'columnState',
307-
why: "platform-written, never authored — `Studio round-trip: per-user column order/widths (runtime-only state, written by the console grid — not authored)`. Declared on the wire members only so the console's own write parses; the authoring door (`ViewItemSchema`) rejects the key by name",
307+
why: "platform-written, never authored — `Studio round-trip: column order/widths (runtime-only state, written by the console grid and stored on the view's row, which has no per-user scope — not authored)`. Declared on the wire members only so the console's own write parses; the authoring door (`ViewItemSchema`) rejects the key by name",
308308
},
309309
{
310310
kind: 'omit',
311311
type: 'view',
312312
path: ROOT_PATH,
313313
key: 'isPinned',
314-
why: "platform-written, never authored — `Studio round-trip: view pinned in the switcher (per-user state, written by the console — not authored)`; the authoring door (`ViewItemSchema`) rejects the key by name",
314+
why: "platform-written, never authored — `Console round-trip: the view is pinned in the object's view switcher. … Not authored.`; the authoring door (`ViewItemSchema`) rejects the key by name",
315315
},
316316
{
317317
kind: 'omit',
318318
type: 'view',
319319
path: ROOT_PATH,
320320
key: 'sortOrder',
321-
why: "platform-written, never authored — `Studio round-trip: position within the switcher (per-user state, written by the console — not authored)`; the authoring door (`ViewItemSchema`) rejects the key by name and points the author at `order`, the authored default",
321+
why: "platform-written, never authored — `Console round-trip: the view's position among the object's saved views in the switcher … Not authored`; the authoring door (`ViewItemSchema`) rejects the key by name and points the author at `order`, the authored default",
322322
},
323323

324324
// Deprecated or legacy alias — deliberately not offered to new authors, the

0 commit comments

Comments
 (0)