Skip to content

Commit 7a96bf8

Browse files
docs(spec): the sha-less objectui line citations move to their liveness rows (#23621)
Fixes #23434 Clause-②: no The last part of issue 23434, under claim 6184826965. It moves the remainder listed in landing record 6184152953 under ruling 6165388570 (letter C) item 1 ("The published spec source carries no renderer citation after this") into the matching liveness notes, in item 2's spelling. The two live citations with no matching note stay as named exceptions (the "stays: no ledger row" rows below); the seat's ACCEPT on this PR keeps `Fixes` on that reading. It also carries residual 2 of the post-hoc review 6184726608. Ruling 6181034096 (Q2 → A) keeps retirement history in place, and this PR applies that test to two of the listed lines. ## What changes Every edit to `packages/spec/src` is to a comment. The ledger notes take the moved records as `objectui @sha FILE#SYMBOL`, each read at objectui `b9814b334` (the `.objectui-sha` pin on this base). | source line(s) on base `8d05456cbe` | record | disposition | ledger row | |---|---|---|---| | `data/field.zod.ts:1816` | slider `step` reader | moved | `field.json` `step` | | `data/field.zod.ts:1835` | vector `dimensions` reader | moved | `field.json` `dimensions` | | `ui/action.zod.ts:966`, `:969`, `:970` (+ `:971`, a `.ts` line) | param-dialog `description` chain | moved; stale claim corrected | `action.json` `description` | | `system/translation.zod.ts:161` (a `.ts` line, outside the 8 files) | the same chain, on the translation slot | moved; stale claim corrected (bounded in-place fix, below) | `action.json` `description` | | `ui/bulk-action.zod.ts:81` (+ `:73`, `:76`, `:79`, `.ts` lines) | bulk param `options[]` passthrough | moved; stale claim dropped | `view.json` `list.bulkActionDefs` | | `ui/i18n-label-resolver.ts:136` | the two resolvers' composition order | moved | `page.json` `regions`, entry [2] (`page:tabs` `items[].label`) | | `ui/view.zod.ts:456`, `:458` (+ `:457`) | row-`id` decoration producers | moved | `view.json` `list.filter` and `list.sort` | | `ui/view.zod.ts:965` (+ `:967`) | `ViewFilterRule` row `id` | moved | `view.json` `list.filter` | | `ui/view.zod.ts:1701` | `allowAddTab` reader | moved | `view.json` `list.userFilters` | | `ui/view.zod.ts:2803` | sort entry row `id` | moved | `view.json` `list.sort` | | `ui/app.zod.ts:963` | `areas[].order` retirement record | stays: retirement history | none | | `ui/dashboard.zod.ts:1462` | `widgets[].aria` removal record | stays: retirement history | none | | `ai/build-progress.zod.ts:100` (+ `:102`) | build-progress phase readers | stays: no ledger row | none | | `ui/view.zod.ts:5283` (+ `:5284`) | the "pin this view" trace on `ViewItemSchema` | stays: no ledger row | none | Each moved comment now names its row, in the form PR #23591 used ("read points recorded in `liveness/view.json`, row `list.filter`"). **Residual 2 (review 6184726608).** `view.json` `list.exportOptions` named `ObjectGrid.tsx` by line (`:1596-:1611`, `:1620-:1631`). It now names `objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#exportableFormats` (`formats`, `streaming`) and `#handleExport` (`maxRecords`, `includeHeaders`, `fileNamePrefix`, and `streaming` again for the server-stream choice). The note keeps that the first measurement was by line at objectui `origin/main@878140b`. **Two stale claims, corrected on the move.** These were renderer readings that no longer hold at the pin. Each source comment now states only the contract, and the ledger records the current reading: - `ui/action.zod.ts` and `system/translation.zod.ts` said the description resolver falls back from `objects.{object}._actions.{action}.description` to `globalActions.{action}.description`. At objectui `b9814b334`, `useObjectLabel.ts#actionSuffixes` reads one address only: the object's for an action with a key object, the global one for an action without (objectui#11439 retired the chain). That matches the spec's own `packages/spec/src/system/i18n-resolver.ts#actionTranslationNode`. The `action.json` `description` evidence carried the same stale chain and now reads by symbol. - `ui/bulk-action.zod.ts` said objectui's bulk-param option TYPE is closed (a label/value pair only). At `b9814b334`, `objectql.ts#BulkActionParam` types an option entry open, with an index signature. The passthrough reasoning does not depend on the type, and it stays. ## The four items listed without a ledger row (6184152953): one reading each | item | reading | reason | |---|---|---| | `ai/build-progress.zod.ts`, objectui `dda8f3815` (the same record as line 100 above) | stays | `BuildProgressFrame` is a stream frame, not a registered metadata type, so no ledger file covers it. The module's own "Liveness watch" section says so, and it keeps each reading beside its surface by design. A row would mean enrolling the frame in `check-liveness.mts`'s `SPEC_ONLY_SCHEMAS`, as `query` and `realtime_subscription` were, each by its own card with a census. That widens what the gate governs, which is not this card's to decide. | | `api/dataset-selection.test.ts` (objectui `@98178b2`) | stays | Writer provenance for test specimens: the request shapes five objectui call sites build. This is the class 6184152953 keeps for the 30 pin-test citations. `DatasetSelection` is a query request, and `dataset.json` governs `DatasetSchema` only. | | `system/metadata-form-zod-reconciliation.test.ts:578-579` | stays | The comment records that a row is impossible: planting `config` in `view.json` failed `check:liveness` as an ORPHAN. The walk stops at the `view` union's container arm (`check-liveness.mts#shapeOf`). It is a dated census of seven keys, not a renderer read point. | | the `VIEW_CONSOLE_ROUND_TRIP_KEYS` census (`ui/view.zod.ts`, and `ui/view-console-round-trip-keys.test.ts:19`, `:42`) | stays | The same walk boundary: the round-trip keys live on the `viewItem` and `listOverlay` arms, which have no rows. The record is also the symbol ADR-0005 appendix (c) cites (`docs/adr/0005-metadata-customization-overlay.md`, `packages/spec/src/ui/view.zod.ts#VIEW_CONSOLE_ROUND_TRIP_KEYS`). It names no renderer file. | ## The recount, on `origin/main` `8d05456cbe` (re-taken on `9a6f790a38`, which changes none of the six source files: the same 16) - Instrument: `git grep -nE '[A-Za-z0-9_-]+\.tsx:[0-9]+' -- 'packages/spec/src/**' ':!*.test.ts'`. It gives 38 lines. 22 of them are in `conversions/registry.ts`, `migrations/**` and `registry.ts.template`, which are group R and stay. That leaves **16** in the 8 named files: build-progress 1, field 2, action 3, app 1, bulk-action 1, dashboard 1, i18n-label-resolver 1, view 6. Landing record 6184152953 says 17, but its own per-file list sums to 16. - Control: the same instrument at HEAD still counts the 22 group-R lines (22 → 22), so its zeros elsewhere are readings. - The records also cite objectui by `.ts:NNN`. A wider instrument (objectui package paths with `:NNN`, any `.ts`/`.tsx`) adds 8 lines on the same records. It also finds one record outside the 8 files, `system/translation.zod.ts:161`. In-repo `.ts:NNN` citations (`dataset-compiler.ts`, `memory-driver.ts`, `kernel-base.ts`, `middleware.ts`) and the cloud one in `agent.zod.ts` are not renderer citations, and they stay. - After this PR: 16 → **4** `.tsx:NNN` lines (the four "stays" rows above), and 21 → **5** on the wide instrument. ## Bounded in-place fix, outside the claim's file surface `system/translation.zod.ts:161` is not in claim 6184826965's file surface. I fixed it here because all four of os-dev's bounded in-place conditions hold: 1. It is the same defect class: a sha-less objectui `file:line` in published spec source. 2. The fix is mechanical, in the shape this card fixed. 3. No open PR touches the file. I read the file lists of all 12 open non-release PRs. 4. The gate family is the same; no new verification surface. The claim's file surface needs this file added. The seat records that. ## Verification Head `5596717198` merges `origin/main` `9a6f790a38` into this PR's one change commit, `f7160d1f2e`. Head `023b160afe` follows it with one changeset-only commit (the headline now names which read points moved and which stay); no build or test input changed. The merge was clean, and it brought PR #23600 and PR #23601, which touch `packages/spec`. After the merge, `git diff --stat origin/main HEAD` is still these 11 files (+62 / -54). Every reading below was taken on `5596717198` after the merge: - `pnpm --filter @objectstack/spec build` through `os-verify-lock.sh`: VERDICT command-exit 0. After it, `git status` was clean, so the build wrote no tracked file. - `pnpm --filter @objectstack/spec typecheck && pnpm --filter @objectstack/spec test` (vitest `--project local`; no `test:repo`) through the lock: VERDICT command-exit 0. "Test Files 678 passed (678) · Tests 20741 passed | 1 todo (20742)". - Comment-only check. Each of the 6 changed `.ts` files was parsed with TypeScript at `origin/main` and at head and printed with comments removed. 6 of 6 are identical. The control: a one-character string-literal mutation printed differently, and a comment-only mutation printed the same. - Ledger anchors. The 21 new `objectui @sha FILE#SYMBOL` anchors were checked with `scripts/symbol-anchors.mjs#symbolSegmentResolution` against `git show SHA:FILE` in an objectui clone. 21 of 21 are declarations, and 0 are unresolved. The `containers.tsx` anchors on the edited `page.json` line are declarations too. Negative control: one bogus path and two bogus symbols gave 3 of 3 unresolved. The clone was read only, and its `git status` stayed empty. - `check-spec-docblock-symbol-anchors`, with `OBJECTUI_CHECKOUT` set to that clone and without it: the same verdict, exit 0 both times. "4888 anchors … 3 cross-repo … 0 NEW line anchors on tracked targets survive (199 citations name no tracked file …)". None of the 3 cross-repo anchors is `objectui:`, so the variable had nothing to judge in spec source. - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths) derived 81 commands. The list is the same as on the pre-merge head. Each command was run with its exit code captured before any pipe, then reconciled with `--ran`: "81 derived famil(ies) accounted for — 78 run, 3 NOT-MEASURED". - 77 exited 0. They include `check:liveness`, `check:docs`, `check:api-surface`, `check:authorable-surface`, `check:empty-state`, `check:issue-citations`, `check:nul-bytes`, `check:doc-authoring`, `check-closing-keyword-parity` and lint's `check:doc-formula-expressions` (after building `@objectstack/formula`, `@objectstack/sdui-parser` and `@objectstack/lint`). - 3 exited 3, prerequisite not met: `check:dual-build-cjs-loads`, `check:i18n-walk-parity` and `check:lean-entry-closure`. They read the built output of packages this diff does not touch (every dist, `packages/cli/dist`, `packages/objectql/dist`). This is a declared narrowing, and CI's `Lint & Repo Gates` runs them. - 1 exited 1, and it comes from the base: `check:platform-checklist`. It reports the same 7 ABSENT SYMBOL findings PR #23591 reported (`areas/access-security.json` 5, `attachments-storage.json` 1, `search.json` 1), plus that area's anchor floor (27 against 28). This PR touches none of those paths. - `pnpm --filter @objectstack/spec run check:generated`: "All 14 generated artifacts are up to date". - Census on head: 4 `.tsx:NNN` lines and 5 on the wide instrument, with group R still at 22. ## Acceptance notes - **Census class, stated.** This PR moves the `file:line` spelling: the third spelling PR #23591 left. Symbol-only mentions of renderer components in prose stay, as they did in PRs #23589 to #23591. Examples are "objectui's `ActionParamDialog`" and "the console's filter builder". They name no file or line, and a pin hop cannot falsify them. - **Observed, not filed (carrier: none).** Existing ledger rows this card did not move into still cite objectui by line. Examples: `app.json` `navigation.order` (`NavigationRenderer.tsx:1154, :913` at objectui `@940ba24`; at `b9814b334` the sort is `packages/layout/src/navOrder.ts#byNavOrder`), `translation.json` `objects` (`useObjectLabel.ts:397-400`), `view.json` `list.kanban`, `list.emptyState` and `list.aria`. Ruling item 2 governs the spelling of moved records. Respelling the ledger's older entries is not a defect class, and this card does not claim it. - **Observed, not filed.** Three census sentences say "at the `.objectui-sha` pin" without naming the tree: `VIEW_CONSOLE_ROUND_TRIP_KEYS`, the switcher row-state docblock in `ui/view.zod.ts`, and `view-console-round-trip-keys.test.ts`. No gate ties them to the pin any more, so a pin hop forces nothing. Naming the tree the #20456 census used would make them dated readings. - **Retirement test, applied.** `ui/app.zod.ts:963` sits in the `areas[].order` retirement docblock (retired 17.0.0), and `ui/dashboard.zod.ts:1462` in the `widgets[].aria` removal record (call graph closed 2026-08-04). Both are parts of retirement records, so ruling 6181034096 keeps them as dated history. The `app.zod.ts` line no longer points at the sort at the pin. As history it is not re-measured. - No ablation: no tested behaviour changed. - No label written: a published file changes and a patch changeset is present, so `skip-changeset` does not apply. --- _Generated by [Claude Code](https://claude.ai/code/session_01LFqdRsuM5nkqoJdHd5ztVk)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e611e2b commit 7a96bf8

11 files changed

Lines changed: 62 additions & 54 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
The sha-less objectui `File.tsx:NNN` read points that have a liveness row leave the published spec source and move into that row. Two live citations with no ledger row stay in `packages/spec/src`, named under "Unchanged on purpose" below.
6+
7+
Clause-②: no
8+
9+
- **Sha-less line citations.** Ten live read-point records named an objectui file by line, with no SHA. Each moves into the note of its liveness row as `objectui @SHA FILE#SYMBOL`, re-read at objectui `b9814b334`, and the source comment now names the row: `data/field.zod.ts` (`field.json`, rows `step` and `dimensions`), `ui/action.zod.ts` and `system/translation.zod.ts` (`action.json`, row `description`), `ui/bulk-action.zod.ts` (`view.json`, row `list.bulkActionDefs`), `ui/view.zod.ts` (`view.json`, rows `list.filter`, `list.sort` and `list.userFilters`) and `ui/i18n-label-resolver.ts` (`page.json`, row `regions`).
10+
- **Two stale renderer claims are no longer stated.** For an action bound to an object, the console's description resolver no longer falls back from `objects.{object}._actions.{action}.description` to `globalActions.{action}.description`. objectui's bulk-param option type is no longer closed. The comments in `ui/action.zod.ts`, `system/translation.zod.ts` and `ui/bulk-action.zod.ts` said both. They now state only the contract, and the ledger records the current reading.
11+
- **`liveness/view.json`, row `list.exportOptions`** names its reader by symbol instead of by line.
12+
- **Unchanged on purpose.** Retirement history stays where it is: the `areas[].order` record in `ui/app.zod.ts` and the `widgets[].aria` record in `ui/dashboard.zod.ts`. Two citations with no ledger row also stay: the build-progress phase reading in `ai/build-progress.zod.ts`, and the "pin this view" trace on `ViewItemSchema` in `ui/view.zod.ts`.
13+
- No schema, type, export, default, accept or refuse change. No `.describe()` text changed.

‎packages/spec/liveness/action.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
"description": {
1414
"status": "live",
1515
"verifiedAt": "2026-08-10",
16-
"evidence": "objectui @5e52495 packages/app-shell/src/views/ActionParamDialog.tsx:215 renders it as the dialog's DialogDescription; objectui @5e52495 packages/app-shell/src/hooks/useConsoleActionRuntime.tsx:206 and objectui packages/app-shell/src/views/RecordDetailView.tsx:586 both feed it as `description: actionDescription(objForI18n, action?.name, action?.description)`; objectui packages/i18n/src/useObjectLabel.ts:463 resolves objects.{o}._actions.{a}.description then globalActions.{a}.description then this literal; framework: packages/cli/src/utils/i18n-extract.ts emits the key and packages/spec/src/system/translation.zod.ts declares the translation slot.",
17-
"note": "Added #7367 — the RENDERER half predates the key by design: the consumer chain above shipped while `ActionSchema` (strictObject) refused `description`, so no producer could reach it (the mirror image of declared-but-unenforced). Live from the moment this key exists: the dialog reads `action.description` directly, no second input required. Mechanism for the 2026-08-10 ruling on #7278 — an action with `params` carries its confirm question here instead of in `confirmText`, so one decision is one dialog."
16+
"evidence": "objectui @b9814b334 packages/app-shell/src/views/ActionParamDialog.tsx#ActionParamDialog renders it as the dialog's DialogDescription, falling back to the generic `actionDialog.description` string; objectui @b9814b334 packages/app-shell/src/hooks/useConsoleActionRuntime.tsx#paramCollectionHandler and objectui @b9814b334 packages/app-shell/src/views/RecordDetailView.tsx#paramCollectionHandler both feed it as `actionDescription(objForI18n, action?.name, action?.description)`; objectui @b9814b334 packages/i18n/src/useObjectLabel.ts#actionDescription resolves it through objectui @b9814b334 packages/i18n/src/useObjectLabel.ts#actionSuffixes, reading objects.{o}._actions.{a}.description for an action with a key object or globalActions.{a}.description for one without, never both, then this literal; framework: packages/cli/src/utils/i18n-extract.ts emits the key and packages/spec/src/system/translation.zod.ts declares the translation slot.",
17+
"note": "Added #7367 — the RENDERER half predates the key by design: the consumer chain above shipped while `ActionSchema` (strictObject) refused `description`, so no producer could reach it (the mirror image of declared-but-unenforced). Live from the moment this key exists: the dialog reads `action.description` directly, no second input required. Mechanism for the 2026-08-10 ruling on #7278 — an action with `params` carries its confirm question here instead of in `confirmText`, so one decision is one dialog. Moved out of spec source, #23434: packages/spec/src/ui/action.zod.ts (this key's docblock) and packages/spec/src/system/translation.zod.ts (the translation slot's comment) cited this chain by line, sha-less. Re-read at objectui @b9814b334 on 2026-10-15: the object-then-global fallback both described, and this entry's evidence with them, is gone — objectui#11439 retired it, so the client resolves one bundle entry the way packages/spec/src/system/i18n-resolver.ts#actionTranslationNode does."
1818
},
1919
"objectName": {
2020
"status": "live",

‎packages/spec/liveness/field.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@
192192
"step": {
193193
"status": "live",
194194
"verifiedAt": "2026-08-08",
195-
"note": "CAVEAT — RENDERER-only: objectui SliderField.tsx:14 reads `field.step ?? 1`; the write path never validates the grid (record-validator.ts's numeric branch enforces min/max for slider and reads step nowhere). Ruled UI-only and deliberately unenforced 2026-08-08 (#6514) — see docs/audits/2026-06-dead-surface-disposition-plan.md (P2 field) and the comment beside the declaration in src/data/field.zod.ts."
195+
"note": "CAVEAT — RENDERER-only: objectui @b9814b334 packages/fields/src/widgets/SliderField.tsx#SliderField reads `sliderField?.step ?? 1` and hands it to the Slider (re-read 2026-10-15; first cited by line, sha-less, here and in packages/spec/src/data/field.zod.ts beside the declaration — moved out of spec source, #23434); the write path never validates the grid (record-validator.ts's numeric branch enforces min/max for slider and reads step nowhere). Ruled UI-only and deliberately unenforced 2026-08-08 (#6514) — see docs/audits/2026-06-dead-surface-disposition-plan.md (P2 field) and the comment beside the declaration in src/data/field.zod.ts."
196196
},
197197
"group": {
198198
"status": "live",
@@ -329,7 +329,7 @@
329329
},
330330
"dimensions": {
331331
"status": "live",
332-
"note": "vector field — objectui VectorField.tsx:11 reads the flat `dimensions` prop. The live authoring path; `Field.vector(n)` emits this. (The dead nested `vectorConfig` block was removed in 16.0, #2377.)"
332+
"note": "vector field — objectui @b9814b334 packages/fields/src/widgets/VectorField.tsx#VectorField reads the flat `dimensions` prop (`vectorField?.dimensions`, the value's length when unset; re-read 2026-10-15; first cited by line, sha-less, here and in packages/spec/src/data/field.zod.ts beside the declaration — moved out of spec source, #23434). The live authoring path; `Field.vector(n)` emits this. (The dead nested `vectorConfig` block was removed in 16.0, #2377.)"
333333
},
334334
"inlineTitle": {
335335
"status": "live",

‎packages/spec/liveness/page.json‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎packages/spec/liveness/view.json‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949
},
5050
"filter": {
5151
"status": "live",
52-
"note": "objectui: ListView.tsx client-side filter shaping (audit L15); no list-render prop reaches the server query (audit data-flow note)."
52+
"note": "objectui: ListView.tsx client-side filter shaping (audit L15); no list-render prop reaches the server query (audit data-flow note). The console's filter rows carry a React list key that the wire door removes before the parse (packages/spec/src/ui/view.zod.ts, the VIEW_CONSOLE_ROW_DECORATIONS header and the ViewFilterRule docblock; moved out of spec source, #23434): `id: crypto.randomUUID()` is stamped on each new row by objectui @b9814b334 packages/components/src/custom/filter-builder.tsx#FilterBuilder (its `addCondition`), and again on a stored filter read back into the builder by objectui @b9814b334 packages/plugin-view/src/config/view-config-utils.ts#parseTriplet and objectui @b9814b334 packages/plugin-view/src/config/view-config-utils.ts#parseSingleOrNested (both reached from that file's parseSpecFilter); re-read 2026-10-15, first cited by line, sha-less."
5353
},
54-
"sort": {"status": "live", "note": "objectui: ListView.tsx (audit L15).", "children": {"field": {"status": "live", "verifiedAt": "2026-09-13", "evidenceScope": "in-repo", "note": "Read in this repo by `normalizeSortNodes` (packages/metadata-protocol/src/protocol.ts:3468, `fromElement`), which reads `el.field` off every sort entry and is the funnel every metadata ingress passes through; it lowers onto the engine `orderBy`. Drilled here rather than inherited because #17053 retired the bare string arm of this union, which is what made the entry's own keys visible to the walk."}, "order": {"status": "live", "verifiedAt": "2026-09-13", "evidenceScope": "in-repo", "note": "Read in this repo by `normalizeSortNodes` (packages/metadata-protocol/src/protocol.ts:3468) alongside `field`, and validated by its `direction()` helper (:3447) which refuses anything but 'asc'/'desc'. Divergence from `field` would be the signal worth recording; there is none \u2014 a sort entry is inert without both."}}},
54+
"sort": {"status": "live", "note": "objectui: ListView.tsx (audit L15). The console's sort rows carry the same React list key (packages/spec/src/ui/view.zod.ts, the VIEW_CONSOLE_ROW_DECORATIONS header and the sort entry's docblock; moved out of spec source, #23434): `id: crypto.randomUUID()` is stamped by objectui @b9814b334 packages/components/src/custom/sort-builder.tsx#SortBuilder (its `normalize`, for a row without one, and its `addItem`), and again on a stored sort read back by objectui @b9814b334 packages/plugin-view/src/config/view-config-utils.ts#toSortItems; re-read 2026-10-15, first cited by line, sha-less.", "children": {"field": {"status": "live", "verifiedAt": "2026-09-13", "evidenceScope": "in-repo", "note": "Read in this repo by `normalizeSortNodes` (packages/metadata-protocol/src/protocol.ts:3468, `fromElement`), which reads `el.field` off every sort entry and is the funnel every metadata ingress passes through; it lowers onto the engine `orderBy`. Drilled here rather than inherited because #17053 retired the bare string arm of this union, which is what made the entry's own keys visible to the walk."}, "order": {"status": "live", "verifiedAt": "2026-09-13", "evidenceScope": "in-repo", "note": "Read in this repo by `normalizeSortNodes` (packages/metadata-protocol/src/protocol.ts:3468) alongside `field`, and validated by its `direction()` helper (:3447) which refuses anything but 'asc'/'desc'. Divergence from `field` would be the signal worth recording; there is none \u2014 a sort entry is inert without both."}}},
5555
"searchableFields": {
5656
"status": "live",
5757
"note": "objectui: ListView.tsx (audit L15)."
@@ -186,7 +186,7 @@
186186
"bulkActionDefs": {
187187
"status": "live",
188188
"evidence": "packages/spec/src/ui/bulk-action.zod.ts",
189-
"note": "objectui: ListView.tsx:1343 forwards rich defs to ObjectGrid (BulkActionDialog). Dispatch: useBulkExecutor.ts run() — per-record fan-out by default; execution:'aggregate' defs go through the ONE-call bulkCall branch injecting params._selectedIds (ObjectGrid.runBulkActionAggregate, objectui#3139). Verified objectui@4bf612c. #4457 gave the def a SHAPE (it was z.record(z.any())): the entry schema is BulkActionDefSchema, strict, and it refuses the combinations that parse but the executor never reads — so this row's liveness now covers the keys inside a def, not just the array. A PROMOTED def's field-backed params (packages/spec/src/ui/bulk-action.zod.ts; moved out of spec source, #23434): resolved when the dialog opens by objectui main @dca25aff2 packages/plugin-grid/src/resolveBulkActions.ts#resolvePromotedBulkParams through `resolveActionParams` (objectui 29b99490), then renamed onto the bulk vocabulary by the same file's #toBulkParam, which carries the field's type, translated label, options, required, description, placeholder, defaultValue, multiple, `dependsOn`, `accept` and `maxSize` (plus a reference-bearing field's reference and display field) and drops the lookup settings."
189+
"note": "objectui: ListView.tsx:1343 forwards rich defs to ObjectGrid (BulkActionDialog). Dispatch: useBulkExecutor.ts run() — per-record fan-out by default; execution:'aggregate' defs go through the ONE-call bulkCall branch injecting params._selectedIds (ObjectGrid.runBulkActionAggregate, objectui#3139). Verified objectui@4bf612c. #4457 gave the def a SHAPE (it was z.record(z.any())): the entry schema is BulkActionDefSchema, strict, and it refuses the combinations that parse but the executor never reads — so this row's liveness now covers the keys inside a def, not just the array. A PROMOTED def's field-backed params (packages/spec/src/ui/bulk-action.zod.ts; moved out of spec source, #23434): resolved when the dialog opens by objectui main @dca25aff2 packages/plugin-grid/src/resolveBulkActions.ts#resolvePromotedBulkParams through `resolveActionParams` (objectui 29b99490), then renamed onto the bulk vocabulary by the same file's #toBulkParam, which carries the field's type, translated label, options, required, description, placeholder, defaultValue, multiple, `dependsOn`, `accept` and `maxSize` (plus a reference-bearing field's reference and display field) and drops the lookup settings. An authored param's `options[]` entries (packages/spec/src/ui/bulk-action.zod.ts, the `.passthrough()` rationale; moved out of spec source, #23434): objectui @b9814b334 packages/plugin-grid/src/components/bulkParamToField.ts#bulkParamToField spreads each entry into the field metadata (`options?.map(o => ({ ...o, value: String(o.value) }))`), so every extra key reaches the widget, whose option vocabulary is objectui @b9814b334 packages/types/src/field-types.ts#SelectOptionMetadata, extending objectui @b9814b334 packages/types/src/select-option.ts#SelectOptionBase (`color`, `visibleWhen`, `disabled` and `icon` beyond the pair); the select cell reads `option?.color` in objectui @b9814b334 packages/fields/src/index.tsx#SelectCellRenderer. The renderer's own param type now agrees: objectui @b9814b334 packages/types/src/objectql.ts#BulkActionParam types an `options` entry open (an index signature, citing objectstack#4001), where the source's sha-less reading had it closed (`Array<{ label; value }>`). Re-read 2026-10-15, first cited by line, sha-less."
190190
},
191191
"virtualScroll": {
192192
"status": "dead",
@@ -207,7 +207,7 @@
207207
"exportOptions": {
208208
"status": "live",
209209
"verifiedAt": "2026-08-13",
210-
"note": "objectui: ObjectGrid.tsx reads five object keys — formats/streaming (:1596-:1611), maxRecords/includeHeaders/fileNamePrefix (:1620-:1631) — re-measured objectui origin/main@878140b. Object form adopted at #8010 (option A ruling 2026-08-12): the spec used to publish a bare format array the renderer never read (.formats on an array is undefined), so no declaration was both type-legal and functional; the bare array stays accepted and lifts to { formats } at parse. Sub-value 'pdf' removed same change (#1301 NOT_PLANNED) — enum error map carries the prescription; conversion view-export-options-pdf-removed strips stored sources."
210+
"note": "objectui reads five object keys: `formats` and `streaming` in objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#exportableFormats (the menu's format set), and `maxRecords`, `includeHeaders` and `fileNamePrefix` (with `streaming` again, for the server-stream choice) in objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#handleExport — re-read 2026-10-15; first measured by line at objectui origin/main@878140b, respelled by symbol under #23434. Object form adopted at #8010 (option A ruling 2026-08-12): the spec used to publish a bare format array the renderer never read (.formats on an array is undefined), so no declaration was both type-legal and functional; the bare array stays accepted and lifts to { formats } at parse. Sub-value 'pdf' removed same change (#1301 NOT_PLANNED) — enum error map carries the prescription; conversion view-export-options-pdf-removed strips stored sources."
211211
},
212212
"userActions": {
213213
"status": "live",
@@ -246,7 +246,7 @@
246246
},
247247
"userFilters": {
248248
"status": "live",
249-
"note": "objectui: UserFilters.tsx — element/fields/tabs/showAllRecords wired (audit L15); object views narrow to ObjectUserFiltersSchema (ADR-0047 amendment, #2679/objectui#2338)."
249+
"note": "objectui: UserFilters.tsx — element/fields/tabs/showAllRecords wired (audit L15); object views narrow to ObjectUserFiltersSchema (ADR-0047 amendment, #2679/objectui#2338). `allowAddTab` (packages/spec/src/ui/view.zod.ts, the #5073 close record; moved out of spec source, #23434): read as `config.allowAddTab` by objectui @b9814b334 packages/plugin-list/src/UserFilters.tsx#UserFilters and handed to objectui @b9814b334 packages/plugin-list/src/UserFilters.tsx#TabFilters, which draws the add-tab affordance and holds the added tabs in component state only; re-read 2026-10-15, first cited by line, sha-less."
250250
},
251251
"responsive": {
252252
"status": "dead",

‎packages/spec/src/data/field.zod.ts‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,9 +1812,10 @@ export const FieldSchema = lazySchema(() => {
18121812
language: z.string().optional().describe('Programming language for syntax highlighting (e.g., javascript, python, sql)'),
18131813
// `step` is the slider's **UI increment** and deliberately NOT a stored-value constraint —
18141814
// ADR-0049's "ledger" half, ruled 2026-08-08 (#6514). Note it is renderer-LIVE, not dead,
1815-
// which is why it is NOT in the pruned list above and never joins it: objectui's
1816-
// `packages/fields/src/widgets/SliderField.tsx:14` reads it (`field.step ?? 1`) and hands it
1817-
// to the Slider, and `packages/spec/liveness/field.json` ledgers it `live` on that evidence.
1815+
// which is why it is NOT in the pruned list above and never joins it: objectui's slider
1816+
// widget reads it (`step ?? 1`) and hands it to the Slider, and
1817+
// `packages/spec/liveness/field.json` ledgers it `live` on that evidence (row `step`, which
1818+
// records the read point).
18181819
// What it does not do is BIND the written value: the numeric branch of
18191820
// `packages/objectql/src/validation/record-validator.ts` enforces `min`/`max` for `slider`
18201821
// and reads `step` nowhere. The settings-side ruling (#6199 / PR #6501, which DID enforce a
@@ -1832,7 +1833,8 @@ export const FieldSchema = lazySchema(() => {
18321833
currencyConfig: CurrencyConfigSchema.optional().describe('Which currency an amount is in: for a currency field, and for a formula field whose returnType is currency. Absent: dynamic mode.'),
18331834

18341835
// Vector field — flat dimensionality (the live authoring path).
1835-
// The renderer reads this flat sibling (objectui VectorField.tsx:11).
1836+
// The renderer reads this flat sibling (read point recorded in
1837+
// `liveness/field.json`, row `dimensions`).
18361838
dimensions: z.number().int().min(1).max(10000).optional().describe('Vector dimensionality (e.g., 1536 for OpenAI embeddings)'),
18371839

18381840
/**

0 commit comments

Comments
 (0)