Skip to content

fix(spec): the ui-bulk-action-param-unknown-keys-refused migration text names the promoted field-backed bulk route - #22888

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-22858-bulk-param-route-text
Oct 11, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-22858-bulk-param-route-text

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #22858
Clause-②: no

What changed

Text only, in one file: packages/spec/src/migrations/entries/semantic/18.ui-bulk-action-param-unknown-keys-refused.ts, the major-18 D3 entry that objectstack migrate meta prints. Two clauses said the bulk surface has no field-backed param route. Since objectui 29b99490 (an ancestor of the console pin), a PROMOTED bulk action resolves its field-backed params through the single-record dialog's resolver. Both clauses now say that the AUTHORED bulkActionDefs[].params surface has no such route, name the promoted route, and name its two keys (accept / maxSize arrive from the field). The wording follows what 581ca7d4e4 landed in packages/spec/src/ui/bulk-action.zod.ts: the module comment at :151-:170, the field guidance at :211-:221, and the widget-config prescription at :252-:267.

Plus a patch changeset for @objectstack/spec. No regeneration commit: registry.ts, spec-changes.json and the upgrade guide are git-ignored. packages/spec/CHANGELOG.md is not touched; it is release-owned.

Before and after (evaluated strings, clause by clause; every other clause is byte-identical)

replacement, before:

the keys that belong one layer out are pointed there (visible and a capability gate belong on the DEF, visibleWhen belongs on an options[] entry, field / objectOverride / carryOver / defaultFromRow / requiresFeature are field-backed ACTION-param contracts the bulk surface does not implement); and the widget-config family (…) is answered with one prescription naming FieldSchema as the shape those keys are real on.

replacement, after:

the keys that belong one layer out are pointed there (visible and a capability gate belong on the DEF, visibleWhen belongs on an options[] entry, carryOver / defaultFromRow / requiresFeature are ACTION-param contracts the bulk surface does not implement); field / objectOverride declare a FIELD-BACKED param, and an authored bulkActionDefs[].params entry has no such route — it reaches the dialog as written, and nothing on that path resolves it against the object's field definitions — so the field rejection offers two fixes: declare the param inline, or declare the action on the object with that field-backed param and name it in the view's bulkActions, the PROMOTED route, whose params are resolved through the single-record dialog's resolver when the bulk dialog opens; and the widget-config family (…) is answered with one prescription naming FieldSchema as the shape those keys are real on, and saying that of them only accept / maxSize declared there reach this dialog, through a promoted action.

reason, before:

⛔ Do not read their rejection as "the renderer ignores them", and ⛔ do not answer it by declaring the key on the object's FIELD: the bulk surface has no field-backed param route, so that value does not reach this dialog either.

reason, after:

⛔ Do not read their rejection as "the renderer ignores them", and ⛔ do not answer it by declaring the key on the object's FIELD and keeping the authored def: an authored bulkActionDefs[].params entry has no field-backed param route, so that value does not reach this dialog either. The one route that consults the field is a PROMOTED action — an action the object declares, named in the view's bulkActions, whose field-backed params ({ field }) are resolved through the single-record dialog's resolver when the bulk dialog opens — and of these keys only accept / maxSize arrive that way: lookupFilters / lookupColumns / lookupPageSize / descriptionField are resolved and then dropped on the bulk path, and the rest are never read off the field.

The diff also re-wraps two string-concatenation lines with no byte change to the evaluated text. That was proved by evaluating entry at the base 75b6d6a048 and at this head, splitting each field at clause boundaries, and diffing: only the clauses quoted above differ, and surface / acceptanceCriteria are identical.

The claim, verified at the console pin

.objectui-sha at the base is 4997995022 (the card was filed against 0df67f237c; the pin has moved since). git merge-base --is-ancestor 29b99490 4997995022 exits 0, which is self-proving even in a shallow checkout. All readings use git show 4997995022:… in objectui:

  • The promoted route resolves field-backed params. packages/plugin-grid/src/ObjectGrid.tsx:5174-:5183: resolveDialogParams calls resolvePromotedBulkParams(def, { objectName, objects, fieldLabel, fieldOptionLabel, locale }) when the dialog opens, for a def carrying actionDef (a promoted one). packages/plugin-grid/src/resolveBulkActions.ts:197-:212: that function passes the action's params to resolveActionParams from @object-ui/fields, the single-record dialog's resolver, then maps each result through toBulkParam.
  • accept / maxSize arrive. packages/fields/src/resolveActionParams.ts:781-:782 (field-backed branch): accept: param.accept ?? field.accept, maxSize: param.maxSize ?? field.maxSize. resolveBulkActions.ts:172-:173: toBulkParam forwards both. packages/plugin-grid/src/components/bulkParamToField.ts:163, :167: the ...extra spread carries them onto the widget's field bag.
  • lookupFilters / lookupColumns / lookupPageSize / descriptionField are resolved, then dropped. resolveActionParams.ts:757, :759-:761 resolve them (with the snake id_field read at :756). toBulkParam (resolveBulkActions.ts:159-:175) emits none of them; its docblock at :146-:149 says so.
  • The rest are never read. The field-backed return (resolveActionParams.ts:766-:784, with the lookup extras at :754-:762) reads no min, max, step, precision, scale, rows, crop, capture, dimensions, defaultName, allowCreate, picker, subtitle or avatarField off the field.
  • carryOver / defaultFromRow / requiresFeature stay unimplemented on the promoted route too, which is why the replacement keeps that clause. toBulkParam forwards neither carryOver nor visible (the target that requiresFeature is lowered into), and the resolver context at ObjectGrid.tsx:5177-:5183 passes no row, so defaultFromRow has nothing to read.

STEP18_RATIONALE in packages/spec/src/migrations/registry.ts.template carries no fragment for this entry: the sorted list goes from ui-ai-chat-window-retired (:2747) to ui-form-layout-inline-grid-retired (:2762), and the template has zero field-backed hits. So nothing moves there.

The new text carries no tracker id. packages/cli/test/migrate-meta-engine-guidance.test.ts refuses a hash sign followed by four or five digits in the printed block.

Verification

Every reading below is at head 30e041142c (base 75b6d6a048), in a fresh worktree, with each verdict read from the tool's own line.

  • @objectstack/spec build (lock): VERDICT command-exit 0. It runs gen:migration-registry (build-migration-registry --self-test: ok, wrote 422 semantic entries). The new text is in the generated registry.ts (git-ignored) and in dist/migrations (one hit each), and the old sentence has zero hits. The build left git status clean.
  • @objectstack/spec test (local project): 648 files, 19375 passed, 1 todo, exit 0. typecheck: exit 0 (tsc --noEmit, check:scripts-typecheck, check:test-typecheck OK).
  • scripts/step18-rationale-merge.test.ts (repo project, the one repo test that reads the template): 9/9 passed, exit 0.
  • CLI closure build turbo run build --filter='@objectstack/cli^...' --concurrency=2: 58/58 tasks successful, VERDICT command-exit 0.
  • packages/cli/test/migrate-meta-engine-guidance.test.ts (--project integration, after that build): 3/3 passed, exit 0. It spawns os migrate meta --all, finds every semantic entry's block verbatim in stdout (this one included), and refuses a tracker id in it.
  • node scripts/check-adr-0087-registration.mjs --base origin/main: this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen).
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths): 82 commands, of which 81 were run, all exit 0. Three of them first answered PREREQUISITE NOT MET (exit 3: doc-formula-expressions, dts-closure, lean-entry-closure, which need built workspace packages). They were re-run after the CLI closure build and exit 0. --ran reconciliation: 82 derived, 81 run, 0 NOT-MEASURED, 1 UNRUN.
    • The UNRUN one is pnpm check:dual-build-cjs-loads: NOT MEASURED, reason: it needs a whole-workspace build, which this dispatch rules out.
    • The spec gates that read dist (check:api-surface, check:authorable-surface, check:docs, check:spec-changes, check:upgrade-guide, check:liveness, check:strictness-ledger and the rest, 18 in all) ran after the spec build. check:authorable-surface prints only the allowed baseRev-lag info line.
  • Artifact rosters (the 50 families the no-path run lists, PR-context guards wired to this PR): run after this PR opened, because the PR-context guards read its number and body. Their results are in the os-dev-report comment on the card, not here: this body is written once.
  • NOT MEASURED: the five path-scheduled CI jobs and the four type-check lanes the derivation names as CI-only (Test Core, Temporal Conformance, Dogfood Regression Gate, Dogfood Verify CLI, Build Core; the workspace typecheck filters). Reason: they are CI's own shell over CI's filters, with no local invocation.
  • Not merged with origin/main: two commits have landed since the base (72b26ed4f5 and 40bc51f3f9). Neither touches either path in this diff. The PR's merge ref and the merge queue test the joint state.

Acceptance notes

  • acceptanceCriteria is left untouched, as ruled. Its closing sentence still says that where a widget-config key's behaviour is gone, "the remedy is a spec issue asking for the key, not a local workaround". For accept / maxSize there is now a second remedy: the landed prescription's "for accept / maxSize move the param onto a promoted action". The reason clause printed just above it now states that remedy, so the printed block is not wrong, only incomplete in its last sentence. Whether to align that sentence is a call for the reviewing seat. Carrier: the seat reviewing this PR. Noted here; no card is filed.

Generated by Claude Code

…cked route

The major-18 semantic entry ui-bulk-action-param-unknown-keys-refused said
the bulk surface has no field-backed param route. Since objectui 29b99490
(carried by the console pin) a promoted bulk action resolves its field-backed
params through the single-record dialog's resolver, and accept / maxSize
arrive from the field. The replacement and reason clauses now say the
AUTHORED bulkActionDefs[].params surface has no such route and name the
promoted one, in the wording BulkActionParamSchema's rejection text uses.

Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 139 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 45e206e4987494dcb3f762ae527caf28f8ca3491 → packageMentionDocs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Oct 11, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Landing pre-checks at d743b538b2, by the owning seat: all green, queued

domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-11T22:03Z · holder of claim 6112257310 on #22858.

  • The review: the seat's ACCEPT on spec: migration entry ui-bulk-action-param-unknown-keys-refused says the bulk surface has no field-backed param route, but the console pin carries objectui 29b99490 #22858, on this head. It is migration-entry text only (@objectstack/spec patch, Clause-②: no). This body's Verification heading names the pre-merge head 30e041142c; the readings were re-taken at this head, as the report 6114291332 records.
  • CI: 35 check-runs, 32 success and 3 skipped. check-expected-skips --pr 22888 reads all three in the roster.
  • Governed: check-governed-merges --pr objectstack-ai/objectstack#22888 reads NOT governed: +40 / −11.
  • Closing keywords: the body carries Fixes #22858 alone, and no commit message carries one.
  • main drift since the merge base 45e206e498: main (now 3fdb92db00) moved neither of the PR's paths, and git merge-tree against it exits 0. GitHub reports clean.

pr_ready and automerge_enable follow.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 11, 2026 22:04
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 11, 2026 22:04
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit 3f69471 Oct 11, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-22858-bulk-param-route-text branch October 11, 2026 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

2 participants