Skip to content

Commit 76eb07a

Browse files
committed
docs(spec): regenerate the three reference tables; correct the protocol page's copy of the same claim
`gen:schema && gen:docs` after the `undoable` describe() correction. The text renders into three generated tables — `ui/action`, `data/object` and `kernel/metadata-plugin` — all regenerated here. `content/docs/protocol/objectui/actions.mdx` is hand-written and carried the identical false claim ("the patch names exactly the fields whose prior values are captured"). Corrected in place under the bounded same-defect exemption: same defect class, mechanical transposition of the corrected sentence, the file is held by no open PR (26 scanned), and the derived gate-family set is byte-identical with and without the edit. Changeset: patch on `@objectstack/spec` — the description ships in the package, so a consumer reading the reference page sees a different promise. Claude-Session: https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho Co-authored-by: Claude <noreply@anthropic.com>
1 parent 28fafd8 commit 76eb07a

5 files changed

Lines changed: 20 additions & 4 deletions

File tree

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+
`ActionSchema.undoable` — the published description now names the WRITTEN set, not `patch` alone (#19148).
6+
7+
**FROM** — "`operation: 'update'` is the declared form of that action — its `patch` names exactly the fields whose prior values are captured."
8+
9+
**TO** — "`operation: 'update'` is the one declared operation and the declared form of that action: what the undo captures is the prior value of EVERY field the action writes — the merged write bag, `patch` UNDER the collected `params`, not `patch` alone. An action with no `operation` declares no write set, so nothing anchors the capture there."
10+
11+
An `operation: 'update'` action writes two sources: the static `patch` AND whatever its `params` collect. On any params-carrying action, "exactly the `patch` fields" is a strict subset of what the action writes, so an Undo built to the old sentence restores part of the change and reports the action as undone.
12+
13+
- **Prose only — no schema change, no accept/reject outcome moves.** The same author input parses the same way before and after; `Clause-②: no`.
14+
- **The executor already captured the union.** `executeDeclarativeUpdateAction` keys `undoData` off `Object.keys(data)`, `data` being `declarativeUpdateWrite`'s merged bag `{ ...patch, ...params }`. The sentence was the outlier, and the EXECUTOR CONTRACT doc block ~200 lines above in the same file already read "exactly the fields written".
15+
- **One operation, one rule.** The `operation` enum carries exactly one member, `'update'` (`'delete'` and `'custom'` are refused with their reason), so the per-operation capture rule is a one-row rule and is written as one.
16+
- The describe text renders into three generated reference tables (`ui/action`, `data/object`, `kernel/metadata-plugin`), regenerated here; the hand-written protocol page `content/docs/protocol/objectui/actions.mdx` carried the identical claim and is corrected in the same edit.

‎content/docs/protocol/objectui/actions.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ The `type` field selects how an action is dispatched. The complete enum is **`sc
5151
| `api` | Call an API endpoint (`method` defaults to `POST`). | Yes |
5252
| `form` | Open a FormView by name, routed to `/_console/forms/:name` **inside the console shell**; the submit lands on the created record. | Yes |
5353

54-
The one thing that is not a type: the **declarative single-record field write**. It is spelled `operation: 'update'` + `patch` — the same words a list view's `bulkActionDefs` uses for the bulk form — and it rides the default `script` route: the platform action route performs the write on the data plane **as the caller** (never system-elevated), so the caller's permissions, the object's hooks and its validations fire exactly as for a user edit. Beside `operation: 'update'` an action carries no executor binding of its own — `target`, `body`, `method`, `bodyExtra` and any other explicit `type` are refused — and `patch` is merged under whatever the `params` dialog collects, so a fixed value can be declared without exposing it in the dialog. `undoable` has its anchor here: the patch names exactly the fields whose prior values are captured.
54+
The one thing that is not a type: the **declarative single-record field write**. It is spelled `operation: 'update'` + `patch` — the same words a list view's `bulkActionDefs` uses for the bulk form — and it rides the default `script` route: the platform action route performs the write on the data plane **as the caller** (never system-elevated), so the caller's permissions, the object's hooks and its validations fire exactly as for a user edit. Beside `operation: 'update'` an action carries no executor binding of its own — `target`, `body`, `method`, `bodyExtra` and any other explicit `type` are refused — and `patch` is merged under whatever the `params` dialog collects, so a fixed value can be declared without exposing it in the dialog. `undoable` has its anchor here: the capture is the prior value of every field the action writes — the merged bag, `patch` under `params`, not `patch` alone.
5555

5656
```ts
5757
{ name: 'task_complete', label: 'Complete', operation: 'update', patch: { status: 'done' },

‎content/docs/references/data/object.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ const result = ApiMethod.parse(data);
461461
| **successMessage** | `string \| Record<string, string>` | optional | Success message to show after execution |
462462
| **errorMessage** | `string \| Record<string, string>` | optional | Error message to show when the action fails (overrides the raw error). |
463463
| **refreshAfter** | `boolean` | optional (default: `false`) | Refresh view after execution |
464-
| **undoable** | `boolean` | optional | Offer an Undo affordance after this single-record update action succeeds. `operation: 'update'` is the declared form of that action — its `patch` names exactly the fields whose prior values are captured. |
464+
| **undoable** | `boolean` | optional | Offer an Undo affordance after this single-record update action succeeds. `operation: 'update'` is the one declared operation and the declared form of that action: what the undo captures is the prior value of EVERY field the action writes — the merged write bag, `patch` UNDER the collected `params`, not `patch` alone. An action with no `operation` declares no write set, so nothing anchors the capture there. |
465465
| **resultDialog** | `{ title?: string \| Record<string, string>; description?: string \| Record<string, string>; acknowledge?: string \| Record<string, string>; format?: Enum<'qrcode' \| 'code-list' \| 'secret' \| 'text' \| 'json'>; … }` | optional | Render API response in a one-shot reveal dialog (suppresses successMessage when set). |
466466
| **visible** | `boolean \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Visibility predicate — `true`/`false` literal, CEL string, or `{dialect, source}` envelope. The action is offered when it evaluates TRUE. Omit = always visible. |
467467
| **requiresFeature** | `Enum<'twoFactor' \| 'organization' \| 'multiOrgEnabled' \| 'degradedTenancy' \| …>` | optional | Public auth feature flag gating this action; lowered into `visible` at parse time. |

‎content/docs/references/kernel/metadata-plugin.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ const result = MetadataBulkResultSchema.parse(data);
330330
| **successMessage** | `string \| Record<string, string>` | optional | Success message to show after execution |
331331
| **errorMessage** | `string \| Record<string, string>` | optional | Error message to show when the action fails (overrides the raw error). |
332332
| **refreshAfter** | `boolean` | optional (default: `false`) | Refresh view after execution |
333-
| **undoable** | `boolean` | optional | Offer an Undo affordance after this single-record update action succeeds. `operation: 'update'` is the declared form of that action — its `patch` names exactly the fields whose prior values are captured. |
333+
| **undoable** | `boolean` | optional | Offer an Undo affordance after this single-record update action succeeds. `operation: 'update'` is the one declared operation and the declared form of that action: what the undo captures is the prior value of EVERY field the action writes — the merged write bag, `patch` UNDER the collected `params`, not `patch` alone. An action with no `operation` declares no write set, so nothing anchors the capture there. |
334334
| **resultDialog** | `{ title?: string \| Record<string, string>; description?: string \| Record<string, string>; acknowledge?: string \| Record<string, string>; format?: Enum<'qrcode' \| 'code-list' \| 'secret' \| 'text' \| 'json'>; … }` | optional | Render API response in a one-shot reveal dialog (suppresses successMessage when set). |
335335
| **visible** | `boolean \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Visibility predicate — `true`/`false` literal, CEL string, or `{dialect, source}` envelope. The action is offered when it evaluates TRUE. Omit = always visible. |
336336
| **requiresFeature** | `Enum<'twoFactor' \| 'organization' \| 'multiOrgEnabled' \| 'degradedTenancy' \| …>` | optional | Public auth feature flag gating this action; lowered into `visible` at parse time. |

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const result = ActionSchema.parse(data);
4949
| **successMessage** | `string \| Record<string, string>` | optional | Success message to show after execution |
5050
| **errorMessage** | `string \| Record<string, string>` | optional | Error message to show when the action fails (overrides the raw error). |
5151
| **refreshAfter** | `boolean` | optional (default: `false`) | Refresh view after execution |
52-
| **undoable** | `boolean` | optional | Offer an Undo affordance after this single-record update action succeeds. `operation: 'update'` is the declared form of that action — its `patch` names exactly the fields whose prior values are captured. |
52+
| **undoable** | `boolean` | optional | Offer an Undo affordance after this single-record update action succeeds. `operation: 'update'` is the one declared operation and the declared form of that action: what the undo captures is the prior value of EVERY field the action writes — the merged write bag, `patch` UNDER the collected `params`, not `patch` alone. An action with no `operation` declares no write set, so nothing anchors the capture there. |
5353
| **resultDialog** | `{ title?: string \| Record<string, string>; description?: string \| Record<string, string>; acknowledge?: string \| Record<string, string>; format?: Enum<'qrcode' \| 'code-list' \| 'secret' \| 'text' \| 'json'>; … }` | optional | Render API response in a one-shot reveal dialog (suppresses successMessage when set). |
5454
| **visible** | `boolean \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Visibility predicate — `true`/`false` literal, CEL string, or `{dialect, source}` envelope. The action is offered when it evaluates TRUE. Omit = always visible. |
5555
| **requiresFeature** | `Enum<'twoFactor' \| 'organization' \| 'multiOrgEnabled' \| 'degradedTenancy' \| 'oidcProvider' \| 'sso' \| 'ssoEnforced' \| 'deviceAuthorization' \| 'admin' \| 'phoneNumber' \| 'phoneNumberOtp'>` | optional | Public auth feature flag gating this action; lowered into `visible` at parse time. |

0 commit comments

Comments
 (0)