Repository navigation
Commit 27e4d65
fix(core): the console runs a stored action that leaves
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9Ubb6NNyYYEoRck5PnHDXNdfpc)_
Fixes #26879
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:控制台动作运行器(`@object-ui/core` 的 `ActionRunner`)在选派发路由的唯一一处,把「没写
`type`」的已存动作读成 spec 的默认值 `script`,于是它走已注册的 `script` 派发,打平台动作路由 `POST
/api/v1/actions/{object}/{action}`。
- **为什么改**:spec 的 `ActionSchema.type` 默认是
`script`,但控制台跑的是存储里的原样行、不是解析后的行。Studio「新建」骨架和旧版 Studio 存下的无 `type`
动作,路由被解析成动作自己的名字,匹配不到执行器,被报「not executable」,点了没反应。
- **风险与回滚**:低。只影响「无 `type`、无
`actionType`、有名字、名下没注册处理器、也没写运行器自有键(navigate/api/endpoint/onClick/redirect/显式
reload、close)」的动作:原来必然被拒,现在走 script。未知 `type`、空动作仍拒绝;按名注册的处理器仍优先。回滚即还原
`resolveDispatchType` 一个函数。
- **先看**:`ui/packages/core/src/actions/ActionRunner.ts` 的
`resolveDispatchType` 与 `declaresRunnerBehavior`(新增)以及 `execute`
里改用它的那一行;`ActionRunner.specDefaultType-26879.test.ts`(8 个用例)。
- **两分钟验证**:`pnpm --dir ui exec vitest run
packages/core/src/actions/__tests__/ActionRunner.specDefaultType-26879.test.ts`,预期
8 个测试全绿。
- **需要你做的**:无,席位落地。
## What changes
- **One place picks the route.** `execute` used to resolve the dispatch
key as `type || actionType || name`. It now calls `resolveDispatchType`,
which keeps the first three legs (an authored `type`, the `action:*`
block's `actionType`, the `name` when a handler is registered under it
or the action carries a runner-own key) and, for a named action that has
none of those, answers `ActionSchema.type`'s default, `script`. Nothing
unnamed takes the default, so `{}` still lands in `executeActionSchema`
and is refused.
- **The same key is asked twice, as before:** by `refusalBeforeInput`
(the dispatch's early refusal, so a typeless script action meets the
script dispatch's row guard) and by `dispatchCollected`.
- `declaresRunnerBehavior` names the runner-own keys once;
`executeActionSchema`'s guard now reads it instead of its own copy (same
keys: `navigate` never reaches that guard because `dispatchCollected`
runs it first).
- **Fork taken: the runner, not the serve path.** The card offered
either the console reading a typeless action as `script` at route
selection, or the serve path returning the parsed row. The runner is in
this lane's file surface and covers every unparsed source at once
(stored rows from any Studio build or by hand), with no server change.
No writer adds `type`, and no stored row is rewritten.
- `@object-ui/core`'s exports are unchanged: both helpers and the
constant are module-private.
- One root changeset, `@object-ui/core` patch.
## Tests
New
`ui/packages/core/src/actions/__tests__/ActionRunner.specDefaultType-26879.test.ts`,
8 cases:
- A typeless `{ name, body }` and a typeless `{ name, operation:
'update', patch }` both POST `/api/v1/actions/tasks/NAME` through the
real `createServerActionHandler`.
- A typeless action is asked the `script` dispatch's
`refuseBeforeInput`.
- **The default is the spec's:** the stored row is parsed with
`@objectstack/spec`'s `ActionSchema`, and with a spy handler under every
runnable type the typeless action reaches exactly the handler named by
the parsed `type`. If the spec's default ever moves, this case goes red.
- Not swallowed by the default: an unknown `type` is refused, `{}` is
refused as "not executable", a handler registered under the action's
name runs ahead of `script`, and a typeless named `redirect` action
still redirects.
The typeless update shape already reached the route through the
`operation` check that runs ahead of `type` (pinned in
`ActionRunner.updateOperation.test.ts`); it is pinned again here at the
new resolution.
## Acceptance notes
- The card's two shapes run on the script route; an unknown `type` and
an empty schema are still refused (cases above).
- The New skeleton in `ObjectActionsPanel.tsx` still leaves `type` off,
as its comment intends; with this change that row runs. Its pinned Type
control reading "—" until the first write is untouched (outside this
claim's file surface).
## Verification
All at head `e7e7e357`, a worktree off `origin/main` `8074feb6` (main
has moved 27 commits since, none in `ui/packages/core/`; `git
merge-tree` against it is clean).
<details><summary>Tests, ablation and type-check</summary>
- `pnpm --dir ui exec vitest run packages/core/src/actions/` under
`scripts/pm/os-verify-lock.sh`: `Test Files 45 passed (45)`, `Tests 660
passed (660)`; the new file alone, verbose: 8/8.
- Every ui test file that names `ActionRunner`, `ActionProvider`,
`useActionRunner` or `useConsoleActionRuntime` outside
`packages/core/src/actions/` (383 files: app-shell, plugin-grid,
components, react, plugin-detail, plugin-view, console and others),
`--maxWorkers=2` in four locked batches: 47 + 45 + 145 + 146 files
passed, 630 + 452 + 1656 + 1310 tests passed, 0 failed.
- **Ablation** through `scripts/ablation-replace.mjs` on the committed
head: `return SPEC_DEFAULT_ACTION_TYPE;` replaced by `return name;`
(anchor 1 -> 0, blob `ecfc5fa6` -> `9f29d4cd`). The new file went `3
failed | 5 passed (8)`: the typeless body action, the early-refusal case
and the spec-default case. The typeless update case stays green, as
expected: `operation` is read ahead of `type`. Restored: blob back to
`ecfc5fa6` = HEAD, `git diff HEAD` empty.
- `pnpm exec turbo run type-check --filter=@object-ui/core
--concurrency=2` under the lock: `VERDICT command-exit 0`, 4/4 tasks,
core's `type-check` a cache miss (it runs `tsconfig.test.json` too, so
the new test file is compiled).
</details>
<details><summary>Derived dispatch gates (34/34)</summary>
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 34 commands; every one exited 0, the
PR-body gates (`check-closing-keyword-parity`,
`check-adr-0087-registration`, `check-changeset-no-major`) against this
body.
- `pnpm --dir ui exec vitest run scripts/` under the lock: `Test Files
178 passed | 2 skipped (180)`, `Tests 5065 passed | 2 skipped (5067)`.
- `pnpm check:type-check-debt` under the lock: `0 raw tsc error(s)
total, none above its recorded number`.
- `dispatch-gates --ran`: `34 derived famil(ies) accounted for — 34 run,
0 NOT-MEASURED`.
- `pnpm check:new-line-citations` (from `ui/`): `0 new citation(s)`.
Control-byte self-scan of the three files: no hit.
</details>
No dogfood battery: no `!` in the title and no `(narrowing)` arm.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jUfE6TDKDHQvod289V)_
Co-authored-by: Claude <noreply@anthropic.com>type to its default as a script action (#26964)1 parent c6853b1 commit 27e4d65
3 files changed
Lines changed: 258 additions & 9 deletions
File tree
- .changeset
- ui/packages/core/src/actions
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1075 | 1075 | | |
1076 | 1076 | | |
1077 | 1077 | | |
| 1078 | + | |
| 1079 | + | |
| 1080 | + | |
| 1081 | + | |
| 1082 | + | |
| 1083 | + | |
| 1084 | + | |
| 1085 | + | |
| 1086 | + | |
| 1087 | + | |
| 1088 | + | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
| 1124 | + | |
| 1125 | + | |
| 1126 | + | |
| 1127 | + | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
1078 | 1133 | | |
1079 | 1134 | | |
1080 | 1135 | | |
| |||
1452 | 1507 | | |
1453 | 1508 | | |
1454 | 1509 | | |
1455 | | - | |
1456 | | - | |
| 1510 | + | |
| 1511 | + | |
| 1512 | + | |
1457 | 1513 | | |
1458 | 1514 | | |
1459 | 1515 | | |
| |||
2560 | 2616 | | |
2561 | 2617 | | |
2562 | 2618 | | |
2563 | | - | |
2564 | | - | |
2565 | | - | |
2566 | | - | |
2567 | | - | |
2568 | | - | |
2569 | | - | |
| 2619 | + | |
| 2620 | + | |
| 2621 | + | |
2570 | 2622 | | |
2571 | 2623 | | |
2572 | 2624 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
0 commit comments