Repository navigation
fix(spec): the bulk action param rejection text names the promoted field-backed route (#22780) - #22852
Conversation
… route The four sentences in bulk-action.zod.ts that said the bulk surface has no field-backed param route now name the promoted route (an action the object declares, named in the view's bulkActions), whose field-backed params the renderer resolves through the single-record dialog's resolver. The authored bulkActionDefs[].params refusal stays; its reason and remedy change, and the widget-config prescription states which field settings the promoted route carries. Text only: no schema shape or accept-set change. Claude-Session: https://claude.ai/code/session_016njDy8ozy9B9Ns5Y8kAWEK Co-authored-by: Claude <noreply@anthropic.com>
…hema has no idField) Claude-Session: https://claude.ai/code/session_016njDy8ozy9B9Ns5Y8kAWEK Co-authored-by: Claude <noreply@anthropic.com>
…ce text Claude-Session: https://claude.ai/code/session_016njDy8ozy9B9Ns5Y8kAWEK Co-authored-by: Claude <noreply@anthropic.com>
…lk-promoted-route-text
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. 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): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5eb015585338e7ccc1bad3c097d93ffc504ea9a4 && git checkout 5eb015585338e7ccc1bad3c097d93ffc504ea9a4
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d48931871479ccc303e10493e80799225b220038 cbce5d7831070cb1de797e8687ab7dbcea7b999f && git checkout -B drift-repro d48931871479ccc303e10493e80799225b220038 && git merge --no-ff cbce5d7831070cb1de797e8687ab7dbcea7b999f
node scripts/docs-audit/affected-docs.mjs --json d48931871479ccc303e10493e80799225b220038 |
Contract reviewServed-tier: Inputs read: card #22780 (body; comments ① Derived judgments
② Semver level
③ Boundary flags
Deviations, each answered:
Out-of-scope findings, each answered or escalated:
Implemented-by: VERDICT: PASS |
Fixes #22780
Clause-②: no
Text only. Four sentences in
packages/spec/src/ui/bulk-action.zod.tssaid the bulk surface has no field-backed param route. Since objectui29b99490, a PROMOTED bulk action's field-backed param resolves through the single-record dialog's resolver, and the console pin now carries that commit. Each sentence now names the promoted route. The authoredbulkActionDefs[].paramsrefusal stays; only its reason and remedy change. No schema shape, accept set or export moves.Implemented by
os-devfor thedomain:specseat 2, PM sessionsession_016njDy8ozy9B9Ns5Y8kAWEK, branchclaude/issue-22780-bulk-promoted-route-text.What changed
BulkActionParamSchemaguidance.field(shipped in everyfieldrejection). The reason is now "an authoredbulkActionDefs[].paramsentry has no such route: it reaches the dialog as written". The remedy offers two fixes. Declare the param inline (name+type, plusobject/labelFieldfor a picker). Or declare the action on the object with the field-backed param ({ field }, plusobjectOverride) and name it in the view'sbulkActions. It also says the promoted form runs the action once per selected record, because that changes what the button does.BULK_PARAM_WIDGET_CONFIG_KEYSprescription (shipped in every widget-config rejection). The "does not reach this dialog either" clause is replaced. A key declared on the FIELD reaches the bulk dialog only through a promoted action. The prescription names what that route carries, and says that of the refused keys onlyaccept/maxSizearrive that way.BULK_PARAM_WIDGET_CONFIG_KEYSsays the same, with the measurement it rests on.dependsOnJSDoc now reads "one vocabulary, two doors". The FIELD is read by the single-record dialog and by a promoted bulk def. The param is where an authored def writes the key.What the promoted route carries, re-measured on objectui
maindca25aff2These are read from source: plugin-grid
resolvePromotedBulkParams/toBulkParam, and@object-ui/fieldsresolveActionParam.type, translatedlabel,options(with translated option labels),required,description(as the help text; the resolver readsfield.help ?? field.description),placeholder,defaultValue,multiple,accept,maxSize. For a reference-bearing field (EXPANDABLE_FIELD_TYPES) it also carriesreference(asobject),displayField(aslabelField) anddependsOn.toBulkParam:lookupFilters,lookupColumns,lookupPageSizeanddescriptionField, plus the snake-onlyid_field/title_formatreads.min,max,step,precision,scale,rows,crop,capture,dimensions,defaultName,allowCreate,picker,subtitle,avatarField).idFieldis not named as "dropped" in the shipped text.FieldSchemarefusesidField(unrecognized_keys, measured), so no field can declare it.29b99490:git log 29b99490..origin/mainoverresolveActionParams.ts,resolveBulkActions.tsandbulkParamToField.tslists no commit. The two commits since then that touchObjectGrid.tsx(752504520,69bca0af6) change the write census and the paged footer's fan-out query, not the param path;BulkActionDialog.tsxis unchanged.This agrees with the card's list and objectui#12119's contract review. It adds
required,description,placeholderandmultiple, which the resolver also inherits.Premise checks
.objectui-sha=0df67f237c.git merge-base --is-ancestor 29b99490 0df67f237cexits 0 in../objectui. An exit 0 proves itself, so no control leg is owed.packages/spec,content/docsandskills. Two other places carry the "no field-backed route" claim. Neither is edited here (see Acceptance notes).content/docsandskills/**carry no hit.check:generatedreports all 14 up to date, andcheck:docsreports 226 generated files in sync. No reference page moves.Pins
The two cases in
bulk-action.test.tsthat read these strings are re-pointed at named subjects instead of prose:`bulkActions`and`accept` / `maxSize`(it pinned'no field-backed param route');fieldcase asserts no rename arrow, plus`object`and`bulkActions; it pinned'FIELD-BACKED'and'Declare the param inline'.Reverse verification. The fix was committed first. The base text of
bulk-action.zod.tswas then restored into the tree withgit restore --source=1eff3224d7(blob281e495c), and the file run went red:Tests 2 failed | 37 passed (39), exactly the two re-pointed cases. Restored withgit checkout HEAD --: blob2e798a0bequals the HEAD blob, andgit statusis clean. At HEAD:Tests 39 passed (39).Tests and gates
Taken at
cbce5d7831, which isorigin/main31b5a5f7f5merged in. Since thenmainhas moved by two commits (metadata-protocol,scripts/pm/os-regen-merge.sh, one docs page). Neither touchespackages/specor these files.pnpm --filter @objectstack/spec build: exit 0.pnpm --filter @objectstack/spec typecheck: exit 0, includingcheck:test-typecheckOK.pnpm --filter @objectstack/spec test:Test Files 648 passed (648),Tests 19342 passed | 1 todo.pnpm --filter @objectstack/spec check:generated: "All 14 generated artifacts are up to date".dispatch-gates --commands --repo objectstack-ai/objectstack: 85 commands derived, all run with exit codes recorded.--ranreconciliation: "85 derived famil(ies) accounted for — 84 run, 1 NOT-MEASURED".check:doc-formula-expressions(@objectstack/formula/@objectstack/lint) andcheck:lean-entry-closure(@objectstack/objectql).check:dual-build-cjs-loads. Reason: it reads every package'sdist/(88 unbuilt), a whole-repo build left to CI..tsfiles:eslint.config.mjsfiles: ['**/*.{ts,…}']and['packages/**/*.{ts,…}']; neither file was reported ignored.--no-inline-config --format jsongave 2 results, 0 errors, 0 warnings.parserOptions.project/projectService, so no type-aware linting.--print-configshowsparserOptions={ ecmaVersion, sourceType }. This diff cannot change a verdict on an untouched file. Repo-widepnpm lintis CI's.Acceptance notes (noted, not filed)
packages/spec/src/migrations/entries/semantic/18.ui-bulk-action-param-unknown-keys-refused.ts(reason, and thereplacementclause "field-backed ACTION-param contracts the bulk surface does not implement") still says "the bulk surface has no field-backed param route". The text is generated intoregistry.tsand printed byobjectstack migrate meta. It is not edited here, for two reasons: it is outside this card's claimed file surface, and it brings its own gate family (gen:migration-registry,check:spec-changes,check:upgrade-guide, and the cli'smigrate-meta-engine-guidancetest). It is named for the seat in the report. Its conclusion for the widget-config keys still holds, exceptaccept/maxSizeon a promoted def.packages/spec/CHANGELOG.md(17.5.0 entry) carries the same sentence. That file is release-owned, and the sentence was true when it shipped, so nothing is owed there.execution: 'aggregate'def that names a declared action and authors noparamsgets that action attached, andresolvePromotedBulkParamsthen resolves the action's field-backed params too. The shipped text names only thebulkActionsroute, the one objectui#12119 pins.toBulkParam)" and the alias comment "toBulkParammaps the same three".Generated by Claude Code