Skip to content

Commit 1cbe165

Browse files
chore(objectui): bump the console pin to ab1879721595 (carries objectui f624f278, b0bf413c and ab187972) (#21625)
Fixes #21616 Clause-②: no Moves the bundled Console's objectui pin from `89cad75d5570` (#21380) to objectui `main` at claim time, `ab187972159583b595facdcae3c73b50f6f312e9`, so the Console carries objectui#11553, objectui#11544 and objectui#11562, and objectui's own move onto `@objectstack/*` 17.6.0. Unblocked by this, once it lands: #12438 (B1's re-run), #21464 (the held object-grid `columns` member). #21596's run reads whatever console this pin builds. ## Range `89cad75d5570..ab1879721595`: 65 non-merge commits, 119 changesets added (one no longer present at the tip, read from the commit that added it), 111 releasing (43 declared breaking, all by the author's annotation), 8 release-nothing, 1 commit without a changeset (`6903eafbc`, a docs example). `git merge-base --is-ancestor` exits 0 against objectui `origin/main` for the old pin and for every commit named below; `ab1879721595` is `origin/main` at the claim-time read. ## The landings this bump carries | objectui landing | merge commit | who waits here | |---|---|---| | objectui#11553 — Studio reaches the organization's package-less flows at `/studio/~org/automations` (PR objectui#11565) | `f624f278d77e` | #12438 B1's re-run | | objectui#11544 — a grouped grid's group headers read the object field's `options` only, never a column's (PR objectui#11563) | `b0bf413cac21` | #21464's held object-grid `columns` member | | objectui#11562 — `record:details` edit mode edits a `textarea` field in a multi-line textarea, so a save keeps its line breaks (PR objectui#11567) | `ab1879721595` (the pin itself) | the console this repo ships | | objectui#11438 — objectui resolves `@objectstack/*` 17.6.0 and follows its mechanical contract moves (PR objectui#11531) | `6158e4c93f0b` | none; carried by the range | ## What changed here, and why - `.objectui-sha` and `.changeset/console-ab1879721595.md`, written by `scripts/bump-objectui.sh ab187972159583b595facdcae3c73b50f6f312e9 --no-commit` (auto level `minor`). The explicit sha is passed because the shared `../objectui` checkout sits on another branch. The script's `adr-0087: TODO` placeholder is answered `not-required (no-migration-prescription)`, in the wording the previous bumps used, naming all 43 declared-breaking entries (26 commits). Each is objectui's own surface: its validators, layout nodes, node-type keys, CLI, designer and drill-report types. Where an entry narrows toward an ObjectStack shape, ObjectStack already declares that shape: the `{ condition, style }` rule, a dataset-bound dashboard widget, `deleteBehavior`, `percentScaleOf`. Measured: none of the 22 retired or narrowed node keys probed is a `ComponentPropsMap` row (56 rows) or a `PageComponentType` member (31). - `packages/sdui-parser/objectui-lockstep.json`, re-recorded with `pnpm gen:sdui-lockstep` against the build worktree at the pin (`OBJECTUI_ROOT=.cache/objectui-ab1879721595`; the generator correctly refused the off-pin shared checkout). It reads 214 grammar lines (blob `0131f27cf86d`), 25 codes and containment predicate `76c18fb95d1f`, all unchanged, so no port is owed. - `sdui.manifest.json` + `scripts/sdui-manifest.record.json`, from `node scripts/gen-sdui-manifest-node.mjs` over the tree `pnpm objectui:build` built at the pin. It has 107 components, none added or removed. Fourteen changed their published inputs: - `grid` drops `smColumns` / `mdColumns` / `lgColumns` / `xlColumns`, and its `columns` and `gap` become value sets. `stack` / `flex` `gap` and `container` `padding` become value sets too. - `page:header` drops the inert `breadcrumb`. - `object-grid` gains `description`, `emptyState` and `keyboardNavigation`. `object-pivot` gains `drillDown`, and `record:line_items` gains ten inputs. - Descriptions changed on `object-grid` / `object-kanban` `conditionalFormatting`, `action:button` / `action:icon` `successMessage`, and the `fields` input of the three form blocks (`object-form`, `embeddable-form`, `object-master-detail-form`). - The 49 asserting pin citations in `packages/spec/src` (`check:objectui-pin-citations` reds on any pin move) were re-measured at the new pin, not restamped. Each anchor was mapped through its cited file's diff and re-read. Block hashes and corpus counts were re-taken with a method that first reproduced every `89cad75d5` number: the selection block still hashes to `c88443302d40…`, and the corpus is 10071 files with `objectstack` 16044 and `@objectstack/spec` 6461 at the old pin, against 10267, 16377 and 6665 here. This regenerates `packages/spec/src/migrations/registry.ts` and `content/docs/references/ui/view.mdx`. It adds `.changeset/objectui-pin-citations-ab1879721595.md` (`@objectstack/spec` patch), because the `FormField.span` describe and six migration descriptions name the pin. - Records whose claim moved, not only their numbers: - The four `action:*` rows. objectui#11344 now forwards `outcomeMessages` to the runner. The `action:button` / `action:icon` rows record it as a key the renderer forwards and the row does not declare: it arrives on the `action:bar` member path, and objectui leaves the input unpublished until the row declares it. The `action:group` / `action:menu` rows record it riding each member's forward. - The `object-tree` paragraph now cites the regenerated manifest record. - Patch round, after the contract review: `object-grid` `keyboardNavigation`. The grid reads the key at this pin (objectui#11068, `154075ab1`: `ObjectGrid.tsx:5458` hands `schema.keyboardNavigation ?? inlineEditable` to `data-table.tsx`, which makes the cells one roving Tab stop). So the describe drops `[EXPERIMENTAL — not enforced]` and its "no renderer reads it" sentence, and states the measured behaviour. The member docblock and the block docblock's [#20694] paragraph record the read and keep the `db11afd4967c` measurement as history. `content/docs/references/ui/component.mdx` is regenerated. - The same sweep found two more records of the same class: - `object-grid` `emptyState`'s record called the unresolved locale map "a renderer gap". objectui#11227 (`6158e4c93`) ends that gap: `ObjectGrid.tsx:6468-6469` resolves `title` / `message` against the display locale. - `ActionSchema.outcomeMessages` was `planned`, with an author warning that the console does not show outcome copy yet. The console reader is objectui#11344 (`c476be0e0`, `ActionRunner.composeSuccessMessage`), so the row is `live`, as it prescribed for this commit. This adds `packages/spec/liveness/action.json` and its count shard `liveness/state-counts/action.md` to the diff, and the `successMessage` row's note records the interpolation. - Every other anchor held on a byte-identical file or moved with its cited text byte-identical. That includes the three quoted-first-line anchors in `ui/view.zod.ts` that redded: `ObjectView.tsx` `2293` -> `2299`, `objectql.zod.ts` `2145` -> `2370` (still `.strict()`) and `1160` -> `1419` (still without `map`). No key, default, enum member or export moves. - No example, test or gate needed adapting for the breaking entries or for objectui#11438's behaviour changes. Measured on this branch: - The showcase JSX pages use `flex` gaps 1, 2, 3, 4, 6 and 8 and `grid` gap 5 with columns 3 and 4, all inside the new sets. - No example names a retired grid `*Columns` key or any retired node key (0 `git grep` hits). - No example dashboard widget uses the dataset-less inline-object form, which the spec refuses without `dataset` anyway. - All three example `percent` fields declare `max: 100`, so objectui#11475's storage-driven scaling reads them as whole percents. - No example uses `is_empty` / `$empty` on a value provider. ## Browser verification (`examples/app-showcase`, this branch) `pnpm dev -- --fresh --ui --no-watch -p 41737` ran at `87d7c51424`, before the merge, with its own ephemeral DB and the seeded admin. The four `main` commits merged afterwards touch no console asset. `check:console-sha` reports `objectui@ab1879721595`. The run was driven in headless Chromium (`/opt/pw-browsers/chromium`) with every API response captured. | carried fix | drive | result at `ab1879721595` | |---|---|---| | objectui#11553 | `POST /api/v1/automation/showcase_task_completed/clone` `{ name: 'pinprobe_flow_clone', label: 'Pinprobe flow clone' }`, then open `/_console/studio/~org/automations` | clone **200**. `GET /api/v1/meta/flow/pinprobe_flow_clone` **200**, `_packageId` null. The page header reads "Organization flows · Automations". The rail lists "Pinprobe flow clone" and the canvas opens it (`?surface=flow:pinprobe_flow_clone`, status draft). Studio's home lists "NOT IN A PACKAGE · Organization flows" beside "No writable packages yet" | | objectui#11544 | Tasks list → Group → Add group field → Status | five headers, keyed `backlog` / `done` / `in_progress` / `in_review` / `todo`, labelled from the object field's options: Backlog, Done, In Progress, In Review, To Do. Each counts 2, matching `POST /api/v1/data/showcase_task/query` (`groupBy: ['status']`, 5 records). The retired column-`options` read cannot be authored (the strict `ListColumnSchema` refuses `options`), so there is no pre-fix leg to contrast | | objectui#11562 | `PATCH` a task's `notes` to `"Call back Monday.\n\nBudget approved, needs legal review.\n"`, open its record page, double-click Notes, append "Signed off.", Save | the editor is a `TEXTAREA` whose value carries both line breaks. The stored value after the save is `"Call back Monday.\n\nBudget approved, needs legal review.\nSigned off."` | Smoke: the `/_console/home` launcher, Capability Map, Command Center (大屏), the JSX Command Center (`grid columns={4} gap={5}`), the Delivery Operations dashboard (KPI tiles and charts drawn), Chart Gallery, Component Gallery and Task Board. 0 page errors. Non-2xx responses were only `401 /auth/get-session` before sign-in, `404 /usage/storage` and one `404 ?state=draft` no-draft probe. Only the PIDs this run started were stopped. ## Gates and tests run locally, at `4fc15b7e67` (sync round), `5eadf35375` (patch round) and `b93b5fec00` `4fc15b7e67` is the head after merging `origin/main` `5b5e83f446` with `scripts/pm/os-regen-merge.sh`. The merge commit `501902fb09` had no conflict hunk. `component.zod.ts` and `migrations/registry.ts` auto-merged, and both sides' added and removed lines are intact, compared line for line against each side's own diff. The os-regen driver kept this branch's side of `content/docs/references/ui/component.mdx`, dropping main's object-metric `aggregate` and `trend` rows (`3f1bc816a2`). `check:generated --fix` regenerated it in `4fc15b7e67`, and it now differs from main only by this PR's `keyboardNavigation` row. The PR's own contribution, its diff against `origin/main`, is the same 25 paths with the same added and removed lines as at `5eadf35375`. At `4fc15b7e67`, `dispatch-gates --commands` derived the same 128 commands from the same 25-path diff, and all 128 exited 0. `--ran` reports 128 derived, 128 run, 0 NOT-MEASURED. These also exited 0: - `check:objectui-pin-citations --verify-anchors` (54 asserting citations match `ab1879721`; 7 content assertions verified) - `check:authorable-surface`, `check:migration-registry` (`registry.ts` current: 360 semantic entries, with main's `ui-object-metric-aggregate-trend-typed`), `check:generated` (all 15 artifacts current), `check:docs` and `check:liveness` - `@objectstack/spec` test (609 files, 18057 passed, 1 todo) and typecheck - eslint on the 15 changed TS files (0 errors, 0 warnings) At `5eadf35375`, `dispatch-gates --commands` derived 128 commands from the 25-path diff (the 127 below plus `check:platform-checklist`), and all 128 exited 0. `--ran` reports 128 derived, 128 run, 0 NOT-MEASURED. These also exited 0: - `check:objectui-pin-citations --verify-anchors` (54 asserting citations match `ab1879721`; 7 content assertions verified) - `check:generated` and `check:docs` (`component.mdx` regenerated by `check:generated --fix`) - `check:liveness` (after `gen:liveness-counts`) - `@objectstack/spec` test (608 files, 18017 passed, 1 todo) and typecheck - `@objectstack/lint` `lint-liveness-properties.test.ts` (95 passed) - eslint on the 15 changed TS files (0 errors, 0 warnings) `b93b5fec00` is the head after merging `origin/main` `f97660cdd6` with `scripts/pm/os-regen-merge.sh`. The regenerated `registry.ts` is byte-identical to the merge's and keeps main's new `element-text-variant-heading-subheading-retired` entry. - `node scripts/pm/dispatch-gates.mjs --commands` derived 127 commands, the same set before and after the merge. All 127 exited 0 at this head, and the `--ran` reconciliation reports 127 derived, 127 run, 0 NOT-MEASURED, every exit recorded. On the pre-merge pass at `87d7c51424`, `check:skill-examples` and `check:dual-build-cjs-loads` first exited 3 (PREREQUISITE NOT MET: no `dist/`) and exited 0 after `pnpm build`. - Named by the dispatch, all exit 0: - `check-adr-0087-registration --base origin/main`, `check-changeset-no-major --base origin/main` - `check:console-sha`, `check:console-injection`, `check:sdui-lockstep`, `check-sdui-manifest` - `check:objectui-pin-citations --verify-anchors` (49 asserting citations match `ab1879721`; 7 content assertions verified) - `check:migration-registry`, `check:objectui-bump` - `@objectstack/spec check:generated` (after `check:generated --fix` regenerated `content/docs/references/ui/view.mdx`) - The console build passed its single-zod canary (one `{major:4,minor:6,patch:5}` literal) and its spec-injection check. - `pnpm build` exited 0. `pnpm --filter @objectstack/spec test`: 608 files, 18017 passed, 1 todo. `pnpm --filter @objectstack/sdui-parser test`: 218 passed. `pnpm --filter @objectstack/spec typecheck`: exit 0. - `eslint --no-inline-config` was run on the 13 changed TS files: 0 errors, 0 warnings. The population is `**/*.{ts,…}` (`eslint.config.mjs:971`), and the config enables no type-aware linting (`:327-328`), so the diff cannot move a judgment on an untouched file. Repo-wide `pnpm lint` is left to CI. Environment: Node 22.22.0 sufficed. At this pin objectui locks `jsdom` 29.1.1 (`engines ^22.13.0`), so no newer Node was needed. ## Acceptance notes - objectui, measured in the browser run above, not touched here: switching the list's Group field leaves stale "(empty)" groups stuck on "Loading grid…". The server answers only the real groups. Title (10 groups), then Priority, showed 13 groups (9 phantom + 4); then Status 8 (3 + 5); then Priority 8 (4 + 4). `useServerGrouping.ts` and `useGroupedData.ts` are byte-identical at `89cad75d5570` and `ab1879721595`, so this hop does not reach them. Not measured in a browser at the old pin. - `object-kanban`'s `conditionalFormatting` is still `z.unknown()` in this spec, while objectui#11522 now declares only the `{ condition, style }` rule on that block. This is the same typing-by-reference move #21464 makes for its object-block members. - The `action:button` / `action:icon` rows in `ui/component.zod.ts` still do not declare `outcomeMessages`, which objectui now forwards. Declaring it is a contract decision, recorded on the rows and not made here. - `conversions/registry.ts`' `PAGE_HEADER_COMPONENT_TYPES` docblock still calls `page-header` objectui's legacy alias. objectui retired that node key in this range (`ad1785c1d`). The conversion itself is unaffected. --- _Generated by [Claude Code](https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 96b0e31 commit 1cbe165

25 files changed

Lines changed: 1042 additions & 264 deletions

‎.changeset/console-ab1879721595.md‎

Lines changed: 161 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
The spec's objectui citations, and the shipped description text that names the `.objectui-sha` pin (the `FormField.span` describe and six migration-entry descriptions), are re-measured against the new console pin, objectui `ab1879721595`.
6+
7+
Clause-②: no
8+
9+
Several records were corrected rather than moved, because objectui changed what they describe on this hop.
10+
11+
- **`object-grid` `keyboardNavigation`.** The grid now reads the key (objectui#11068), so its describe drops the `[EXPERIMENTAL — not enforced]` marker and the sentence that said no renderer reads it and authoring it changes nothing. The describe now says what the grid does: the data cells become one Tab stop that the arrow keys, Home / End and Ctrl+Home / Ctrl+End move between. It is on by default when the grid renders editable, `true` turns it on for a read-only grid, and `false` turns it off on an editable one.
12+
- **`object-grid` `emptyState`.** Its record now says the grid resolves `title` and `message` against the display locale (objectui#11227), so an inline locale map draws.
13+
- **`ActionSchema.outcomeMessages`.** The console reader landed (objectui#11344). The key's liveness row is now `live`, and authoring it no longer draws the "the console does not show outcome copy yet" author warning. The `successMessage` row records that `${result.*}` is interpolated.
14+
- **The four `action:*` rows.** The action renderers forward `outcomeMessages` to the action runner. The `action:button` and `action:icon` rows record it as a key the renderer forwards and the row does not declare. The `action:group` and `action:menu` rows record that each member's own `outcomeMessages` rides the member forward.
15+
16+
Every other anchor either held on a byte-identical file or moved with its cited text byte-identical. The corpus counts in the six migration entries were re-taken with the method that reproduces the previous pin's numbers. No key, default, enum member or export moves.

‎.objectui-sha‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
89cad75d55702cc4f267bead5bf267de575d5842
1+
ab187972159583b595facdcae3c73b50f6f312e9

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ Sort field and direction pair
735735
| **navigation** | `{ mode?: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation?: boolean; openNewTab?: boolean; size?: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Row-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`) |
736736
| **editable** | `boolean` | optional | Enable inline cell editing |
737737
| **singleClickEdit** | `boolean` | optional | Enter cell edit on single click (default true when editable) |
738-
| **keyboardNavigation** | `boolean` | optional | [EXPERIMENTAL — not enforced] Arrow-key cell navigation on the WAI-ARIA grid pattern. Defaults to on when `editable` is set; a read-only grid keeps its Tab behaviour unless this is `true`. No renderer reads it yet: it is declared ahead of the grid's keyboard-navigation build, so authoring it changes nothing today |
738+
| **keyboardNavigation** | `boolean` | optional | Arrow-key cell navigation on the WAI-ARIA grid pattern: the grid's data cells become one Tab stop that the arrow keys, Home / End and Ctrl+Home / Ctrl+End move between. Defaults to on when the grid renders editable — `editable` set and the viewer allowed to edit; a grid that renders read-only keeps every cell its own Tab stop unless this is `true`, and `false` turns it off on an editable grid |
739739
| **resizable** | `boolean` | optional | Allow column resize (the renderer default is on) |
740740
| **resizableColumns** | `never` | optional | [REMOVED] `object-grid` property `resizableColumns` was removed in @objectstack/spec 17.7.0 (ADR-0049) — it was the legacy second spelling of `resizable`, read only when `resizable` was absent, so one switch had two spellings and a grid authoring both silently ignored this one. Use `resizable`. Rename the key; the value (a boolean) is unchanged. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. |
741741
| **reorderableColumns** | `boolean` | optional | Allow column drag-reorder |

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ Column footer summary configuration
213213
| **required** | `boolean` | optional | Required override |
214214
| **hidden** | `boolean` | optional | Hidden override |
215215
| **colSpan** | `integer` | optional | Absolute column span (1-4). The renderer clamps it to the form grid's current column count, so the cell starts at a real column boundary at every surface width and never overflows (`colSpan: 4` in a 3-column grid renders as 3); a `colSpan` within the column count renders as authored, and `colSpan: 1` emits no span class at all. |
216-
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `89cad75d5570`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
216+
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `ab1879721595`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
217217
| **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) |
218218
| **language** | `string` | optional | Code editor language (for type=code) |
219219
| **keyField** | `{ field?: string; label?: string \| Record<string, string>; placeholder?: string \| Record<string, string>; helpText?: string \| Record<string, string>; … }` | optional | Key column config for record-typed fields |
@@ -343,7 +343,7 @@ Form-view select option — the object-field option shape minus the per-option `
343343
| **required** | `boolean` | optional | Required override |
344344
| **hidden** | `boolean` | optional | Hidden override |
345345
| **colSpan** | `integer` | optional | Absolute column span (1-4). The renderer clamps it to the form grid's current column count, so the cell starts at a real column boundary at every surface width and never overflows (`colSpan: 4` in a 3-column grid renders as 3); a `colSpan` within the column count renders as authored, and `colSpan: 1` emits no span class at all. |
346-
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `89cad75d5570`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
346+
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `ab1879721595`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
347347
| **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) |
348348
| **language** | `string` | optional | Code editor language (for type=code) |
349349
| **keyField** | `{ field?: string; label?: string \| Record<string, string>; placeholder?: string \| Record<string, string>; helpText?: string \| Record<string, string>; … }` | optional | Key column config for record-typed fields |

‎packages/sdui-parser/objectui-lockstep.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
],
77
"objectui": {
88
"repo": "https://github.com/objectstack-ai/objectui.git",
9-
"rev": "89cad75d55702cc4f267bead5bf267de575d5842",
10-
"revDate": "2026-10-02T06:25:01+00:00",
9+
"rev": "ab187972159583b595facdcae3c73b50f6f312e9",
10+
"revDate": "2026-10-03T17:12:55+00:00",
1111
"source": "packages/sdui-parser/src",
1212
"files": [
1313
"packages/sdui-parser/src/body-dialect.ts",
@@ -21,7 +21,7 @@
2121
"packages/sdui-parser/src/validate.ts"
2222
]
2323
},
24-
"recordedAgainstPin": "89cad75d55702cc4f267bead5bf267de575d5842",
24+
"recordedAgainstPin": "ab187972159583b595facdcae3c73b50f6f312e9",
2525
"grammarRegion": {
2626
"file": "packages/sdui-parser/src/parse.ts",
2727
"delimiter": "/* ---------------------- the JS literal subset (#6614) ---------------------- */",

‎packages/spec/liveness/action.json‎

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,14 @@
103103
},
104104
"successMessage": {
105105
"status": "live",
106-
"note": "objectui toast. 2026-10-01 (#21095): the describe() now also declares that the message may interpolate ${result.*} on a type:'api' / type:'script' action (the scope `onSuccess.navigate` declares) and that it is the fallback when a declared `outcomeMessages` entry does not match the response's `outcome`. Those two halves are declared ahead of their reader, by ruling A on objectstack-ai/cloud#2315 (spec first, then the console, then cloud): measured at objectui @e420df31 packages/core/src/actions/ActionRunner.ts#handlePostExecution, the toast is `result.data.message || action.successMessage || runner default` with no interpolation, so a ${result.X} token renders literally until objectstack-ai/objectui#11344 lands (re-read unchanged at objectui @31971ff1). The KEY stays `live` — the toast reads it — and a row's verdict is per key, so the interpolation half is recorded here and on the `outcomeMessages` row rather than by re-grading a working key. Census when declared: zero successMessage values in this repo or objectui carry a `${` token, so nothing that already renders changes meaning."
106+
"note": "objectui toast. 2026-10-01 (#21095): the describe() now also declares that the message may interpolate ${result.*} on a type:'api' / type:'script' action (the scope `onSuccess.navigate` declares) and that it is the fallback when a declared `outcomeMessages` entry does not match the response's `outcome`. Those two halves are declared ahead of their reader, by ruling A on objectstack-ai/cloud#2315 (spec first, then the console, then cloud): measured at objectui @e420df31 packages/core/src/actions/ActionRunner.ts#handlePostExecution, the toast is `result.data.message || action.successMessage || runner default` with no interpolation, so a ${result.X} token renders literally until objectstack-ai/objectui#11344 lands (re-read unchanged at objectui @31971ff1). The KEY stays `live` — the toast reads it — and a row's verdict is per key, so the interpolation half is recorded here and on the `outcomeMessages` row rather than by re-grading a working key. Census when declared: zero successMessage values in this repo or objectui carry a `${` token, so nothing that already renders changes meaning. Re-read at objectui @ab1879721595 (2026-10-03): objectui#11344 landed in the pin's range — packages/core/src/actions/ActionRunner.ts#composeSuccessMessage fills `${result.*}` in the message it shows and uses `successMessage` as the fallback after a matching `outcomeMessages` entry, so both halves declared ahead of their reader are read; `result.data.message` is no longer a rung."
107107
},
108108
"outcomeMessages": {
109-
"status": "planned",
110-
"verifiedAt": "2026-10-01",
111-
"evidenceScope": "in-repo",
112-
"authorWarn": true,
113-
"authorHint": "The console does not show outcome copy yet: until its reader ships, a successful action still toasts `successMessage` (or the server's own message), whatever `outcome` the handler returns. Keep the map — it is accepted, validated and translated today — and keep a `successMessage` as the fallback.",
114-
"evidence": "packages/spec/src/ui/action.zod.ts#refuseInertOutcomeMessages (authoring-time: the map is refused on a type with no server response to report an outcome and beside `resultDialog`, which suppresses the toast; the declarative-update table refuses it beside `operation: 'update'`); packages/spec/src/system/i18n-resolver.ts#translateAction (the REST localization seam overlays each DECLARED outcome's translated copy at the action's one address: `_actions.<a>.outcomeMessages.<outcome>` for a bound action, `globalActions` for an object-less one); packages/cli/src/utils/i18n-extract.ts#pushActionOutcomeMessages (one translation key per declared outcome, beside `successMessage`)",
115-
"note": "PLANNED, carrier objectstack-ai/objectui#11344 (the console's success toast picks `outcomeMessages[result.outcome]`, interpolates ${result.*}, falls back to `successMessage`, then the runner default). Declared by ruling A on objectstack-ai/cloud#2315 (maintainer 2026-10-01), the mechanism half of ruling B there — the server returns facts, the console composes the message in the user's locale — landing spec+client first (#21095), the console second, cloud's producers LAST. Measured at objectui @e420df31: packages/core/src/actions/ActionRunner.ts#handlePostExecution composes the toast from `result.data.message || action.successMessage || runner default` and reads no `outcomeMessages`; re-read unchanged at objectui @31971ff1 (the `.objectui-sha` pin after the base merge), and objectui main 3c3ce15 has no reader either. The in-repo pieces cited in `evidence` validate, translate and extract the copy; none of them SELECTS or shows it, which is what a `live` verdict would claim. Flip to `live` on the commit that cites the console reader at the `.objectui-sha` pin — and drop `authorWarn` / `authorHint` in that same edit: a warned `live` row reds this gate (#21127)."
109+
"status": "live",
110+
"verifiedAt": "2026-10-03",
111+
"evidenceScope": "cross-repo",
112+
"evidence": "objectui @ab1879721595: packages/core/src/actions/ActionRunner.ts#composeSuccessMessage — the success toast's text: `outcomeMessages[outcome]` off the handler's return value, then `successMessage`, then the runner's default text, with `${result.*}` filled in whichever is shown (called from `handlePostExecution`); objectui @ab1879721595: packages/components/src/renderers/action/action-button.tsx#ActionButtonRenderer — forwards the key to the runner, and `action:bar` spreads a registered action onto `action:button` whole (`action-icon.tsx`, `action-group.tsx` and `action-menu.tsx` forward it too); packages/spec/src/ui/action.zod.ts#refuseInertOutcomeMessages (authoring-time: the map is refused on a type with no server response to report an outcome and beside `resultDialog`, which suppresses the toast; the declarative-update table refuses it beside `operation: 'update'`); packages/spec/src/system/i18n-resolver.ts#translateAction (the REST localization seam overlays each DECLARED outcome's translated copy at the action's one address: `_actions.<a>.outcomeMessages.<outcome>` for a bound action, `globalActions` for an object-less one); packages/cli/src/utils/i18n-extract.ts#pushActionOutcomeMessages (one translation key per declared outcome, beside `successMessage`)",
113+
"note": "LIVE from the `.objectui-sha` pin ab1879721595 (2026-10-03): the console reader objectstack-ai/objectui#11344 (objectui c476be0e0) is in the pin's range 89cad75d5570..ab1879721595, so the flip this row prescribed lands on the pin bump that carries it, with `authorWarn` / `authorHint` dropped in the same edit. At 89cad75d5570 no objectui source outside `packages/types` named the key (0 hit lines), and `handlePostExecution` toasted `result.data.message || action.successMessage || runner default`; at ab1879721595 the server-message rung is gone and `composeSuccessMessage` selects the outcome copy. An `outcome` reaches it only from a handler that returns one, which a `script` handler's author writes beside the map and an `api` target returns in its body. History: PLANNED, carrier objectstack-ai/objectui#11344 (the console's success toast picks `outcomeMessages[result.outcome]`, interpolates ${result.*}, falls back to `successMessage`, then the runner default). Declared by ruling A on objectstack-ai/cloud#2315 (maintainer 2026-10-01), the mechanism half of ruling B there — the server returns facts, the console composes the message in the user's locale — landing spec+client first (#21095), the console second, cloud's producers LAST. Measured at objectui @e420df31: packages/core/src/actions/ActionRunner.ts#handlePostExecution composes the toast from `result.data.message || action.successMessage || runner default` and reads no `outcomeMessages`; re-read unchanged at objectui @31971ff1 (the `.objectui-sha` pin after the base merge), and objectui main 3c3ce15 has no reader either. The in-repo pieces cited in `evidence` validate, translate and extract the copy; none of them SELECTS or shows it, which is what a `live` verdict would claim. Flip to `live` on the commit that cites the console reader at the `.objectui-sha` pin — and drop `authorWarn` / `authorHint` in that same edit: a warned `live` row reds this gate (#21127)."
116114
},
117115
"errorMessage": {
118116
"status": "live",

‎packages/spec/liveness/state-counts/action.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ committed anywhere: `check:liveness` sums the shards when it reads them.
1212

1313
| Type | live | exp | elsewhere | dead | planned | classified |
1414
|---|---|---|---|---|---|---|
15-
| `action` | 45 | 0 | 0 | 4 | 1 | 50 |
15+
| `action` | 46 | 0 | 0 | 4 | 0 | 50 |

0 commit comments

Comments
 (0)