Repository navigation
fix(components): spec action entries stop forwarding an object params as values on non-api types (objectui#10462) - #10579
Conversation
… as values on non-api types (objectui#10462) element:button inline actions, action:group and action:menu items and page:header header actions now route params like action:button: an array goes to actionParams, an object is forwarded as values only on type api (the objectstack#5777 window), and any other type drops it with a development warning. page:header keeps its _rowRecord stash. Co-Authored-By: Claude <noreply@anthropic.com>
…n-api-object-params
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Fixes #10462
Clause-②: no
What this does
This finishes ruling A on objectui#10289 for the spec action-entry surfaces. Under that ruling, an action's
paramsis only theActionParam[]input list. Triage (comment5827659739) moves the non-apitypes now, and theapitype keeps the objectstack#5777 window.The four surfaces now route
paramsthe way PR objectui#10460 routes it onaction:button:paramsparams, non-apitypeparams,type: 'api'element:buttoninlineactionactionParams(as before)action:groupitemsactionParams(wasparams)action:menuitemsactionParams(wasparams)page:headerdispatchHeaderAction, with a recordactionParams(as before)_rowRecordstash stayspage:header, no record contextreadActionEntryParamValuessits instatic-params.ts, next to PR objectui#10460'sreadStaticParamValues, and all four sites call it. It uses the same warn-once memo and the same production gate. It is a separate function because a spec action entry has noproperties.paramsbag, so the node helper's warning would send the author to a key this surface does not have. Forapiit returns the object unchanged. The runner still reads that object as the payload and prints its own objectstack#5777 warning, which namesbodyExtra.apidecision uses the dispatched type. That isaction.actionType || action.typeonelement:button(the value it forwards astype),action.typeon the group and menu, andtype || actionTypeonpage:header, which is the runner's own order.page:header's stash is kept. When there is a record,paramsis{ _rowRecord }for a non-apiaction. Only the authored object is left out. When there is no record context, the entry is still dispatched as authored, except that a non-apiobjectparamsis removed. Without that, the no-record path would still pass the values through.actionParamson the group and menu: it mirrorsaction:button. The runner reads the collection list fromactionParamsor an arrayparams, whichever is present, so param collection behaves as before. The forwarded-params pin inaction-forward-parity.test.tsxstays green.MetadataTypeActions.tsx(app-shell) was measured and left unchanged. It rejects anytypeother thanapiwith a toast before it readsparams, and it does not go through the action runner (it builds and sends its own request). So it never forwards an objectparamson a non-apitype. Its object read is theapiarm, which this card does not touch.Reproduction (base
8740e86ce, before the change)The new pin file was committed first and run on the unchanged base: 10 failed / 9 passed (19). All five surface variants failed the non-
apipin withexpected 'account' to be undefined: thenavigate_edithandler received the authoredobjectName/recordIdasActionDef.params. The group and menu array pins failed withexpected undefined to deeply equal [ { name: 'reason', … } ], because the list reached the runner underparamsand notactionParams. Thepage:headerstash pin failed withexpected { objectName: 'account', …(2) } to deeply equal { _rowRecord: … }. All fiveapicontrols passed.Tests
New pin file
packages/components/src/renderers/action/__tests__/action-entry-object-params-10462.test.tsx(19 tests). It runs over 5 surface variants (element:button,action:group,action:menu,page:headerwith and without a record). Each variant gets three pins: non-apiobject not forwarded plus one warning, array asactionParams, and theapicontrol. The file adds twopage:headerstash pins (non-apidrop, and theapimerge control) and two warning pins (once per action across clicks; silent in production, values still dropped). After the change: 19 passed (19).Union at the final head
1d8b74e83(after mergingorigin/main), from the repo root:pnpm exec vitest run --maxWorkers=2 packages/components/src/renderers/pluspage-header-actions,element-button-action,elementButtonActionMembers-8071,action-group,action-bodyShape-forwardandscripts/__tests__/check-action-forward-parity.test.ts: 132 files, 1323 passed, 10 skipped.packages/components/on the pre-merge head44b1d0c9a: 302 files passed, 1 skipped; 2989 tests passed, 17 skipped. The merge touched none of this change's files.@object-ui/componentstype-check(tsc --noEmit && tsc -p tsconfig.test.json; the new test file is in the second program, count 1 from--listFilesOnly): green at1d8b74e83, after building the dependency closure.Reverse verification (ablation)
Both legs were run through
ablation-replace.mjsafter the commit. The anchor was proven to land (1 to 0, blob changed), and the restore was proven on disk (blob equal to HEAD,git diff HEADempty). The tests import the renderers by relative path, so the mutated source is what runs. The direction was predicted before each run.action:group's object branch reverted to a rawparams: action.paramsforward: 2 red (the group non-apipin and the warn-once pin), 17 green. Predicted: the array andapilegs stay green.page:header's record branch reverted to mergingrawParamsinto the stash: 2 red (the header non-apipin and the stash pin), 17 green. The no-record variant stays green, as predicted.Gates run locally (at
1d8b74e83)Green:
check:action-forward-parity(5 surfaces, 0 known gaps, every payload excess-property CHECKED),check:handler-key-reads,check:control-bytes,check:new-line-citations(0 new),check:changeset-claims,check:unreferenced-sources,changeset:check,check-changeset-presence(1 changeset for 6 published source files). Before the merge the following were also green:check:pending-changeset-literals,check:test-path-roots,check:action-ref-convention,check:spec-symbols,check:component-surface-parity.--format json): 6 files, 0 errors. The new lines add twono-explicit-anywarnings, one each in group and menu, foraction.params as anyon theactionParamsbranch. This is the same castaction:buttonuses:UIActionSchema'sActionParam[]does not assign to the runner'sActionParamDef[](TS2322 without it, measured).check-governed-queue-guard --teston the 7 changed paths: NOT GOVERNED.pnpm lintand the fullpnpm test. CI runs them.Acceptance notes
@object-ui/app-shellis not touched, so there is no app-shell changeset.paramsat the authoring door. PR objectui#10460's census found no in-repo JSON authoring the object form on an action node. This PR did not re-take that census for these entry surfaces.apiarm on these surfaces is still retired together with the objectstack#5777 removal at 18, as the card's direction says. Nothing here moves it.Attribution: this change was written in session
https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb(seatdomain:ui#3).Generated by Claude Code