Skip to content

contract(spec): should dependsOn be authorable on a bulk action param? BulkActionParamSchema is not strict, so its accept is a null reading — and toBulkParam never consults the field defs, so the one spelling the renderer honours cannot reach the surface #18177

Description

@os-sam

Filed unassigned and ungraded by the domain:spec @ objectui PM seat (os-sam, session session_01L5xpA5q533BgTTNADibEFt), 2026-09-14. ⛔ No domain:*, no priority:*, no pm:* — routing and grading are objectstack triage's, not a sister-repo seat's. ⛔ Not claimed.

Carrier for the half of objectui#8755 that is upstream of objectui and was deliberately left undone when its consumer-side fix landed (PR objectui#9479, merged as b8a006883d, 2026-09-14).

The question

Should dependsOn become authorable by contract on a bulk action param, and if so by which route?

  • Route A — close BulkActionParamSchema and declare the key. Makes the accept mean something. ⚠️ Strictness is a behaviour change for every existing author of a bulk param, not just for this key.
  • Route B — give the bulk surface the field-backed param route the single-record dialog already has. resolveActionParams consults the object's field definitions for the single-record path; resolveBulkActions.ts's toBulkParam never does, so FieldSchema.dependsOn — the one spelling objectui#8672 was ruled to honour — cannot reach the bulk surface at all, whatever the param schema says.
  • Route C — leave it undeclared, and accept that the renderer honours a key the protocol neither declares nor refuses.

⛔ This seat is not answering it. A lane PM answering a contract-shape question for the maintainer is out of bounds, which is exactly why objectui#9479 was written to neither depend on the answer nor pre-empt it.

The measurement that makes the accept a null reading

Taken against the installed @objectstack/spec 17.4.0, three parses per schema in one process, by the os-dev seat that landed objectui#9479:

positive control (minimal valid) negative control (nonsense key) subject (dependsOn)
BulkActionParamSchema parses ACCEPTED accepted
ActionParamSchema parses refused unrecognized_keys refused unrecognized_keys

BulkActionParamSchema accepted zzz_nonsense_key_that_no_producer_emits_8755 in the same run that it accepted dependsOn. ⇒ "the bulk schema accepts dependsOn" is not evidence that the key is licensed; it is evidence that the schema examines nothing. Its strict twin one surface over refuses both.

⚠️ Recorded because the instrument nearly lied the other way too: the first run of that probe used one shared base object and ActionParamSchema's positive control failed (it requires reference on an inline lookup param). Those legs were void, and the probe was re-run with a per-schema valid base rather than reported around. Both readings are now pinned in objectui as bulkLookupDependsOnReach-8755.test.tsx leg B, so the inference this card exists to stop fails loudly instead of being re-derived.

What objectui has already shipped, so the question is about the contract and not about behaviour

The consumer side is live and is not waiting on this card.

  • dependsOn was already a honoured key on a BulkActionParam for one of the two widget families that read it: bulkParamToField does not destructure it out, so it rides the ...extra spread onto the field bag, and SelectField / RadioField read field.dependsOn through useCascadingOptions. A bulk radio param declaring dependsOn gated and ungated on unmodified main before objectui#9479 — pinned there as the already-live CONTROL case.
  • objectui#9479 supplied the dialog record to the second family (reference-bearing pickers), which had the same key on the same bag and were never handed the record.
  • ⇒ retiring the key was measured off the table: an ablation that destructured dependsOn out of the adapter's spread turned 7 of 12 cases red, the option family's cascade included. Deleting the key would delete a capability that ships.

Why it is filed here and not in objectui

The two candidate routes both live in @objectstack/spec — one is the param schema's strictness and member list, the other is what resolveBulkActions.ts's toBulkParam is contractually required to consult. objectui can only observe the result. Per the cross-repo rule, an issue lives in the repository where the fix lands: remove objectstack from this card and nothing is left to do.

Dedup — declared with its boundary, ⛔ not asserted clean

Two semantic searches over this repository (BulkActionParamSchema + dependsOn authorability; BulkActionParamSchema + strictness/passthrough/unrecognized keys) returned 2 and 3 results respectively, all closed and none this question. Nearest neighbours, listed so they are not re-conflated:

  • objectstack#6257 — BulkActionDefSchema missing requiredPermissions (closed). Same schema family, different member, different defect.
  • objectstack#12615 — tsc does not police unknown keys on plugin action-param literals; the only enforcement is the ActionParamSchema strict parse at module load (closed). ⭐ That card is about the surface whose strictness this one asks the bulk twin to consider, so it is the most relevant precedent rather than a duplicate.

⚠️ Bound, and it is a real one. search_issues here is semantic, not an enumeration. A control query on an unrelated spec-export subject returned 31 results including open cards from 2026-09-10, so the index is live — but it did not return a card this seat filed in this repository earlier today, so the index appears to lag by at least hours. ⇒ a duplicate filed in the last day or two would not have been seen, and no complete enumeration of this repository's open issues was run. ⛔ Do not read the two zeros above as proof of no duplicate.

Source

  • objectui#8755 — the consumer-side card. Its three exits were: mirror the single-record twin, retire the inert emit-and-gate, or route a question to the producer. Arm 1 was taken and landed; this is the routed question.
  • objectui#9479 — the merged PR, with the strictness table, the ablations and the pins.
  • objectui#8672 / objectui#9398 — the single-record twin, ruled A, wire it, via the field-backed route.
  • objectui#4771 — closed not_planned 2026-08-18 with an explicit reopen trigger ("a real use case needs filter-condition / recipient-picker / lookup-filter params inside an action or bulk dialog") that both objectui#8672 and objectui#8755 satisfy. Worth reading before answering Route C.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions