Skip to content

Commit f7160d1

Browse files
committed
docs(spec): the sha-less objectui line citations move to their liveness rows
Ten live read-point records in packages/spec/src 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 b9814b3, and the source comment names the row. The view.json list.exportOptions note is respelled by symbol. Retirement history and the two records with no ledger row stay. Claude-Session: https://claude.ai/code/session_01LFqdRsuM5nkqoJdHd5ztVk Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8d05456 commit f7160d1

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 last live renderer line numbers leave the published spec source: `packages/spec/src` no longer cites an objectui `File.tsx:NNN` for a live read point.
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)