Repository navigation
feat(components)!: action values ride properties.params; params is only the input list (#10289) - #10460
Conversation
…y the input list objectui#10289 ruling A. action:button and action:icon read static execution values from properties.params and forward them as the runner's params. A node-level params OBJECT is ignored with a dev-mode warning; an ActionParam[] params still routes to actionParams. The guide, the app-shell README and the navigate_* handler comments now teach properties.params. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3S
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3S
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3S
|
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
|
Contract reviewServed-tier: ① Contract correctness. The ruling is batch #224 item 4, letter A.
② Tests.
③ Blast radius, measured in a detached worktree at head:
Implemented-by: |
Fixes #10289
Clause-②: yes
What this does
This implements ruling A on the card (comment
5825589480, maintainer 「批 #224 同意」): an action'sparamsis only theActionParam[]inputs list. A node's static execution values rideproperties.params.action:buttonandaction:iconread static values only from the node'sproperties.params. They forward those values to the runner asActionDef.params, which is wherenavigate_create/navigate_editreadobjectName/recordId.paramsobject is not read. It is ignored, and a development build logs one warning per action ([action:button] action "X" carries an OBJECT under node-level params; it is ignored ...). The warning namesproperties.params, andbodyExtrafor an api payload. It is silent in production. The precedent is the dev-only, warn-onceconsole.warnthatauto-trigger.tsand coreactionKeys.tsuse.paramsarray still works as the input list and is forwarded asactionParams.action:iconused to forward anyparamsraw; it now routes through the sameparamsPayloadasaction:button. The runner already treated an arrayparamsasactionParams, so the input path behaves as before.action:barmember, which is mounted withoutSchemaRenderer, can carry inputs inparamsand values inproperties.params, and both are forwarded.schema.properties.paramsitself instead of the hoistedschema.params.SchemaRenderercopiesproperties.paramsonto the node, andaction:barmembers skip that hoist. An identity check tells a hoisted copy apart from a node-level object. The helper ispackages/components/src/renderers/action/static-params.ts.Docs:
content/docs/guide/record-edit-modes.mdand the@object-ui/app-shellREADME now teachproperties.paramsin both examples. They say that a node-levelparamsobject is ignored, and how to migrate. The README also had a stale claim that templates insideparamsare not evaluated, which objectui#10282 had already made false. That claim is replaced.Census (taken on the base
0348bc9f1, before the change)Instrument: a one-off scanner run over every tracked file (CHANGELOGs excluded). It walks every JSON document for a
paramskey holding a plain object, and it matchesparamsfollowed by an object literal in ts/tsx/js/mjs/md/mdx/yaml text. Each text hit was then classified by hand. Nothing re-derives this reading; it is a historical measurement, not a live count.Authors of a node-level
paramsobject on anaction:button/action:iconnode: 13.content/docs/guide/record-edit-modes.mdpackages/app-shell/README.mdAppContent.tsx, thenavigate_*handler commentaction-bodyShape-forward.test.tsx(action:button)action-forward-precedence.test.tsx(the shared fixture)action-params-templates-7867.test.tsxexamples/,apps/andschema-catalog: 0. The JSON walk found noparamsobject anywhere.skills/: 0. Its one actionparamsis theActionParam[]form, inskills/objectui/rules/protocol.md. No governed file is touched.sys_metadatarows): NOT MEASURED, because this repo cannot read it..changeset/7867-action-params-templates.md(pending) shows one node-level example. It is another card's changeset and was not edited. The new changeset says that the form is no longer read.ActionDef.params(the values channel that handlers and hosts build in code), query params, nav-item params, i18n label params and similar. None of them is an authored action node.Readers, and a premise correction
paramsPayloadnon-array branch inaction:button, andaction:icon's rawparamsforward. Both are moved.recordFormNavigation.ts(action.params?.recordId/objectName) anduseObjectActions.tsread the runner'sActionDef.params. They do not read the authored node. Core declares that key as the values map (params?: Record string-to-any), andaction:buttonnow fills it fromproperties.params. They cannot readproperties.paramsthemselves, because the handler receives anActionDef, which has noproperties. So they keep their reads. Only their docs changed: theNavigationActionDefdocblock and theAppContentcomment now describe the channel and teachproperties.params. The card's list of these two files as object-form readers was half right: the keys they read are the right ones, but on the runner layer.Boundary: surfaces left unchanged here
These also forward a non-array
paramsas values, but they are spec action entries, not SDUI nodes. They have nopropertiesbag, and another ruling governs them:element:button's inlineaction;action:group/action:menuitems;page:header'sdispatchHeaderAction.For a
type: 'api'action, the objectstack#5777 ruling keeps the runner reading an objectparamsas the payload for one version window, with a dev warning, removed at 18. Spec already refuses the object form at the authoring door, and the ADR-0087 conversion rewrites it tobodyExtra. Retiring these surfaces now would pre-empt that window, so they are listed rather than changed.Tests
New pin file
packages/components/src/renderers/action/__tests__/action-params-properties-10289.test.tsx(21 tests). It coversaction:buttonandaction:icon, each on both mounts (direct registry mount and throughSchemaRenderer), and pins the following:properties.params;properties.params;properties.paramswins over a node-level object;ActionParam[]path still arrives asactionParams;Union at
c3aff649a(final HEAD), all run from the repo root:packages/components/src/renderers/action/, the bodyShape / bodyExtra / element:button 8071 / page-header-actions suites, app-shellrecordFormNavigation.test.ts, andscripts/__tests__/for doc-expression-carriage and both action-forward-parity suites: 32 files, 548 tests passed.@object-ui/componentstype-check(tsc --noEmit && tsc -p tsconfig.test.json, which includes the tests): green atc3aff649a.@object-ui/app-shelltype-check: green at5f7cb6fc5. Only comments and docs changed in app-shell after that.Ablation
Each leg ran through
ablation-replace.mjs. The anchor was proven to land (anchor 1 to 0, blob changed), and the restore was proven on disk (blob equal to HEAD,git diff HEADempty). These tests import the renderers by relative path, so the mutated source is what runs. The direction was predicted before each run.action:buttonvalues read reverted to the oldparams: schema.params: 10 red. That is button direct-mount properties, both not-read pins, direct-mount wins, the production pin, the 3 bodyShape wire pins, 7867 CASE A, and precedence's carried values. The SchemaRenderer-mount "reads from properties.params" pin stays green, as predicted, because the hoist puts the same object onschema.params.action:iconback to a rawparamsforward: 8 red. That is the icon properties, not-read (both mounts), wins, input list (both mounts), both-channels, and the precedence carried-values pins.Gates run locally
check:action-forward-parity,check:handler-key-reads,check:changeset-claims,check:pending-changeset-literals,changeset:check,check:control-bytes,check:new-line-citations(0 new),check:doc-types,check:doc-fences,check:doc-example-ids,check:doc-example-readers,check:unreferenced-sources,check:spec-symbols,check:component-surface-parity,check:test-path-roots,check:action-ref-convention,check-changeset-presence,check-doc-links,check-doc-expression-carriage(report-only).no-explicit-any/ react-refresh warnings.check-governed-queue-guard --teston the 12 changed paths: NOT GOVERNED.check:readme-exports, because it needs every package'sdist/*.d.tsand the README edit adds no import. Also NOT MEASURED:check:sdui-registration-pins, because it needs a console build and no registration changed. Both are left to CI.packages/typeswas not touched, so the Spec Main Shape Gate type-check does not apply.Acceptance notes
SchemaRendererstill evaluates a node-levelparamsbag (carrier 1 of objectui#10282). No in-tree renderer reads that value any more, so the evaluation is dead work, and the unevaluated-expression diagnostic can still name a leaf inside it.@object-ui/reactwas left unchanged to keep this PR to the renderers the ruling names. A follow-up can drop carrier 1 there.SchemaRenderer, thepropertieshoist copiesproperties.paramsover a node-levelparams. So one node cannot carry both an input list (node-level) and values (properties.params) on that path; the values win. Nothing in the repo authors both, and base behaved the same way. Directly mountedaction:barmembers get both.properties.params.recordId. The 7867 pin now asserts that exact path.Attribution: this change was written in session
https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3S.Generated by Claude Code