Measured while implementing #4162 (making action:menu consume autoTrigger). Filed separately: it affects every overflow action on an ordinary CLICK, not only auto-triggered ones, and predates that card.
Fact
Both renderers hand the runner an explicit key whitelist rather than the action itself. The two whitelists have drifted. Measured on this tree with the real renderers and the real runner, one identical type: 'api' action driven through each path:
PROBE-BTN-KEYS: ["actionParams","description","endpoint","label","locations","method","name","recordIdField","type","undoable"]
PROBE-MENU-KEYS: ["endpoint","locations","method","name","params","type"]
PROBE-MISSING-IN-MENU: ["actionParams","description","label","recordIdField","undoable"]
PROBE-MENU-PARAMS-SHAPE: array-as-params
(Keys with an undefined value filtered out on both sides, so this is what the runner actually receives.)
Four consequences, each already argued at the action:button call site that forwards the key:
label / description — action-button.tsx forwards them so a param-collection dialog titles itself as the action ("Create Environment") instead of a generic "Action parameters" prompt. An overflow action's dialog gets the generic title.
undoable / recordIdField — forwarded by the button so an update action can offer an Undo affordance; the runner never builds the undo operation without them. Clicking the same action from the "More" menu silently loses Undo.
params shape — the button routes an ActionParamDef[] to actionParams and a values object to params; the menu always passes params: action.params. This one does NOT break: ActionRunner accepts an array params as the collection definition (ActionRunner.ts:816), which is why the dialog still opens. It is a latent divergence rather than a live defect, and it is the reason the first bullet is only a wrong title rather than a missing dialog.
Which renderer a given action gets is decided by action:bar's maxVisible split (3 desktop, 1 mobile) and by systemActions, which are ALWAYS in the menu. So the same declared action behaves differently depending on the viewport — the same class of viewport-dependent divergence as #4162 and objectui#4075, on a different key set.
Why it may matter
Reachable today with no metadata change: any undoable update action that sits past maxVisible (or on mobile, past the first action) is offered without Undo, and any action with declared params in the same position gets an unlabelled dialog. No error is raised on either path — the payload is simply thinner, so both failures look like the feature was never declared.
The narrow fix is to bring the menu's forward list up to the button's. The wider question, which is why this is filed rather than patched inside #4162's scope: two hand-maintained whitelists over the same ActionSchema will drift again — bodyExtra (objectstack#6837), bodyShape (objectstack#6938) and resultDialog were each added to both lists one incident at a time. A single shared "action to ActionDef" projection, or a parity test over the two whitelists, is what stops the next one.
action:icon and action:group compose their own payloads too and are not measured here; a fix should check all four rather than just these two.
Related
Generated by Claude Code
Measured while implementing #4162 (making
action:menuconsumeautoTrigger). Filed separately: it affects every overflow action on an ordinary CLICK, not only auto-triggered ones, and predates that card.Fact
Both renderers hand the runner an explicit key whitelist rather than the action itself. The two whitelists have drifted. Measured on this tree with the real renderers and the real runner, one identical
type: 'api'action driven through each path:(Keys with an
undefinedvalue filtered out on both sides, so this is what the runner actually receives.)Four consequences, each already argued at the
action:buttoncall site that forwards the key:label/description—action-button.tsxforwards them so a param-collection dialog titles itself as the action ("Create Environment") instead of a generic "Action parameters" prompt. An overflow action's dialog gets the generic title.undoable/recordIdField— forwarded by the button so an update action can offer an Undo affordance; the runner never builds the undo operation without them. Clicking the same action from the "More" menu silently loses Undo.paramsshape — the button routes anActionParamDef[]toactionParamsand a values object toparams; the menu always passesparams: action.params. This one does NOT break:ActionRunneraccepts an arrayparamsas the collection definition (ActionRunner.ts:816), which is why the dialog still opens. It is a latent divergence rather than a live defect, and it is the reason the first bullet is only a wrong title rather than a missing dialog.Which renderer a given action gets is decided by
action:bar'smaxVisiblesplit (3 desktop, 1 mobile) and bysystemActions, which are ALWAYS in the menu. So the same declared action behaves differently depending on the viewport — the same class of viewport-dependent divergence as #4162 and objectui#4075, on a different key set.Why it may matter
Reachable today with no metadata change: any
undoableupdate action that sits pastmaxVisible(or on mobile, past the first action) is offered without Undo, and any action with declared params in the same position gets an unlabelled dialog. No error is raised on either path — the payload is simply thinner, so both failures look like the feature was never declared.The narrow fix is to bring the menu's forward list up to the button's. The wider question, which is why this is filed rather than patched inside #4162's scope: two hand-maintained whitelists over the same ActionSchema will drift again —
bodyExtra(objectstack#6837),bodyShape(objectstack#6938) andresultDialogwere each added to both lists one incident at a time. A single shared "action to ActionDef" projection, or a parity test over the two whitelists, is what stops the next one.action:iconandaction:groupcompose their own payloads too and are not measured here; a fix should check all four rather than just these two.Related
packages/components/src/renderers/action/action-menu.tsx(handleExecute),action-button.tsx(handleClick),packages/core/src/actions/ActionRunner.tsautoTriggeraction that spills past action:bar's maxVisible lands in action:menu, which never runs it — deep link consumed, nothing triggered #4162action:menuforward / execute payload /undoableoverflow) — no duplicate. Unassigned.Generated by Claude Code