Skip to content

Commit 024ecfc

Browse files
committed
docs: name the schedule trigger as a producer that states callerParamKeys: []
The callerParamKeys TSDoc, the screen verdict's docblock, the flows guide and the pending caller-param-keys changeset each listed the schedule trigger among the producers that leave the key absent. It now states the empty list, so each statement is corrected. Adds this change's own changeset. Claude-Session: https://claude.ai/code/session_01Evb5jFDZGKQE9KG4jbMfMF Co-authored-by: Claude <noreply@anthropic.com>
1 parent afde207 commit 024ecfc

6 files changed

Lines changed: 33 additions & 10 deletions

File tree

‎.changeset/19846-automation-caller-param-keys.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ A screen whose fields the run's caller already supplied continues without pausin
1212

1313
**What the key says.** The keys of the caller's own `params`, recorded before the door seeds anything. An empty array means the caller supplied nothing; an absent key means the producer does not say.
1414

15-
**Who fills it.** The action door (`dispatchFlowAction`: `POST /api/v1/actions/...` and MCP `run_action`) and the trigger door (`buildAutomationContext`: `POST /api/v1/automation/:name/trigger`, the legacy `POST /api/v1/automation/trigger/:name`, and a declarative `type: 'flow'` endpoint). Record-change, schedule, time-relative and webhook triggers, and code calling `execute` directly, leave it absent. `subflow` and `map` nodes drop the parent's list from the child run's context, because it describes the parent's bag.
15+
**Who fills it.** The action door (`dispatchFlowAction`: `POST /api/v1/actions/...` and MCP `run_action`) and the trigger door (`buildAutomationContext`: `POST /api/v1/automation/:name/trigger`, the legacy `POST /api/v1/automation/trigger/:name`, and a declarative `type: 'flow'` endpoint). Record-change, time-relative and webhook triggers, and code calling `execute` directly, leave it absent; the schedule trigger, which has no caller, states an empty list (#19900). `subflow` and `map` nodes drop the parent's list from the child run's context, because it describes the parent's bag.
1616

1717
**What the screen does with it.** When the key is present, a field is caller-supplied when its name is in the list and `params` holds a value for it; the inference is not consulted. A present value that is not an array names nothing, so the screen pauses. When the key is absent, the inference from #15787 applies unchanged.
1818

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/trigger-schedule': patch
3+
'@objectstack/spec': patch
4+
---
5+
6+
A scheduled run no longer skips a screen whose field is named `schedule`, `jobId` or `flowName` (#19900).
7+
8+
The schedule trigger starts each run with three seeds of its own in `params` — `jobId`, `flowName` and `schedule` — and there is no caller behind the run. It stated nothing about that, so a `screen` node's headless verdict inferred who supplied each field from `params`, read those three seeds as the caller's answers, and continued past a screen whose field shared one of the names: the run completed with the trigger's value (for `schedule`, the cron descriptor) as the answer.
9+
10+
The trigger now sets `AutomationContext.callerParamKeys: []` — "the caller supplied nothing" — which the verdict reads instead of inferring. A screen in a scheduled flow pauses, whatever its fields are named. The three seeds stay in `params`; flows that read them are unaffected.
11+
12+
`@objectstack/spec`: the `callerParamKeys` TSDoc now names the schedule trigger as a producer that states the empty list, and no longer lists it among the producers that leave the key absent. No type changes.

‎content/docs/automation/flows.mdx‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -957,9 +957,13 @@ a column named like one of the fields and including when a field is named like
957957
one of the seeded id keys. ⛔ `waitForInput: false` remains the wrong tool for
958958
the headless case: it skips the form for interactive users too.
959959

960-
A run started any other way — a record-change, schedule, time-relative or
961-
webhook trigger, a `subflow` or `map` child, or code calling the engine directly
962-
— carries no such list, and the screen falls back to inferring the caller's keys
960+
A scheduled run has no caller, and the schedule trigger states exactly that —
961+
an empty list — so its own `jobId`, `flowName` and `schedule` params never
962+
answer a screen field: a screen in a scheduled flow pauses.
963+
964+
A run started any other way — a record-change, time-relative or webhook
965+
trigger, a `subflow` or `map` child, or code calling the engine directly —
966+
carries no such list, and the screen falls back to inferring the caller's keys
963967
from the bag. That inference does not treat a key as the caller's when it is
964968
named `recordId` or `<object>Id`, when its value equals what the bag carries
965969
under `recordId` or `<object>Id` or the record's `id`, or when the subject

‎packages/services/service-automation/src/screen-input-contract.ts‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,11 @@ export interface HeadlessScreenContext {
280280
*
281281
* ## Absent: the inference, kept for producers that state nothing
282282
*
283-
* A record-change, schedule, time-relative or webhook trigger, a `subflow` /
284-
* `map` child run, or code calling the engine directly carries no signal, and
285-
* for those the verdict below still infers — unchanged, and failing toward a
286-
* pause.
283+
* A record-change, time-relative or webhook trigger, a `subflow` / `map` child
284+
* run, or code calling the engine directly carries no signal, and for those the
285+
* verdict below still infers — unchanged, and failing toward a pause. (The
286+
* schedule trigger has no caller and states `[]`, #19900, so its `jobId` /
287+
* `flowName` / `schedule` seeds never reach the inference.)
287288
*
288289
* This distinction is the whole safety story of {@link judgeHeadlessScreen},
289290
* because the params bag a flow action reaches the engine with is NOT the

‎packages/spec/src/contracts/automation-context-caller-param-keys.pin.test.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
* not a bag of values, and not a boolean per key.
1414
* 2. **Additive.** A context literal without it still type-checks, so no
1515
* existing `IAutomationService.execute` caller moves, and an absent key is
16-
* what every producer other than the two doors sends.
16+
* what every producer other than the two doors and the schedule trigger
17+
* (which states `[]`, #19900) sends.
1718
* 3. **An empty list is a legal value** — "the caller supplied nothing" — and
1819
* it is a different value from an absent key.
1920
*

‎packages/spec/src/contracts/automation-service.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,13 @@ export interface AutomationContext {
173173
* a client that mirrors the row id into `params.recordId` is addressing the
174174
* row, not answering a question the flow asks.
175175
*
176+
* One producer with no caller at all states the empty list: the schedule
177+
* trigger (`ScheduleTrigger` in `@objectstack/trigger-schedule`, #19900).
178+
* Its `jobId`, `flowName` and `schedule` keys in {@link params} are its own
179+
* seeds, so none of them answers a question the flow asks.
180+
*
176181
* Absent means the producer does not state provenance: a record-change,
177-
* schedule, time-relative or webhook trigger, a `subflow` or `map` child run
182+
* time-relative or webhook trigger, a `subflow` or `map` child run
178183
* (those two nodes drop the parent's list from the child context, because it
179184
* describes the PARENT's bag), or code calling `execute` directly. Its
180185
* consumer, the `screen` node's headless verdict in

0 commit comments

Comments
 (0)