Commit a6df727
committed
feat(core): inventory ActionDef's keys and warn on the ones nothing reads (objectstack#4075 step 1)
`ActionDef` ends with `[key: string]: any`, so it accepts any key of any type.
Deleting `ActionDef.execute` produced ZERO compile errors even though the field
had just been removed (objectui#2990), and stale metadata still authoring
`execute: 'markDone'` type-checks today. The same deletion against
`@object-ui/types`' `ActionSchema` — no index signature — correctly produced
TS2353 at the authoring site. One reader can catch a retired key; the other is
structurally incapable.
Step 1 is the non-breaking half: make the key set visible, warn on anything
outside it, change no types.
What the inventory found, which is step 2's worklist:
- 18 keys the SPEC owns that `ActionDef` never declared — `visible`, `locations`,
`icon`, `variant`, `order`, `component`, `bulkEnabled`, `requiredPermissions`
and 10 more. `ActionEngine` reads two of them through `as any` casts
(`(ra.action as any).visible`, `(action as any).locations`); those casts exist
only because the field is undeclared.
- 17 keys `ActionDef` declares that the spec does not own — `actionType`, `api`,
`chain`, `onClick`, `toast` and others, several already marked legacy. This is
objectui's own dialect and needs the #4115 treatment: documented as deliberate,
or retired.
- `execute` is not simply gone from the spec — it is a live TOMBSTONE, still in
`ActionSchema` so the parser can reject it BY NAME with the rename
prescription. So it is warned about separately and more loudly than an unknown
key: an unknown key is probably a typo, a retired key is metadata that used to
work.
- `to` / `external` / `newTab` / `replace` are a real objectui dialect — the
`navigation` alias's own spelling, read off the action when no nested
`navigate` object is present. Declared here rather than left to trip the
warning, with a tripwire test that fails if the spec ever adopts one.
The lists are data because TypeScript types do not survive to runtime, and
`keyof ActionDef` cannot substitute — the index signature widens it to
`string | number`, which is the problem itself. `actionKeys.pin.test.ts`
re-derives each list from its real source (the interface via the AST, the spec
via its schema) so a hand-maintained list cannot drift from what it mirrors.
The spec key list is pinned rather than resolved at runtime: `ActionSchema` is a
lazy proxy that does not forward `.shape`, so reading it means walking zod
internals — fine in a test, wrong in shipped code. `@object-ui/types` made the
same call for `ActionComponent`.
Discrimination proof: dropping any entry from `ACTION_DEF_KEYS` fails with
"ActionDef declares keys the inventory is missing: <name>"; the warning tests
assert it stays silent on a well-formed action, names `targt`, gives `execute`
its rename prescription, warns once rather than per click, and says nothing in
production. Core type-checks clean and all 207 existing action tests still pass.
One pin is deliberately inverted: the suite asserts the index signature is STILL
THERE. The day that fails, step 3 has landed, `tsc` catches unknown keys itself,
and this warning plus `executeScript`'s rename branch can retire together.
Refs objectstack#4075, objectstack#3903, objectui#2990, #3856, #3855, #2169, AGENTS.md PD #12
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvv6qysks2dRLaGfpTdgEy1 parent ea84651 commit a6df727
4 files changed
Lines changed: 428 additions & 0 deletions
File tree
- packages/core/src/actions
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
| |||
475 | 476 | | |
476 | 477 | | |
477 | 478 | | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
478 | 485 | | |
479 | 486 | | |
480 | 487 | | |
| |||
Lines changed: 170 additions & 0 deletions
| 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 | + | |
0 commit comments