Skip to content

bug(service-automation): execute() never carries the flow author's successMessage / errorMessage — only resume() does, so a triggered run's friendly text is silently dropped #9414

Description

@os-zhuang

Found while implementing #9378 (trigger-route status unification, PR #9413). Filed rather
than fixed there: different defect class (a missing field, not a status classification),
and it changes what a successful run returns, which #9378's ruling does not cover.

Measured

packages/services/service-automation/src/engine.ts, origin/main @ bc6434b.

AutomationResult declares the pair as a general terminal-result feature
(packages/spec/src/contracts/automation-service.ts):

Friendly terminal messages copied from the flow definition
(`flow.successMessage` / `flow.errorMessage`) so a screen-flow runner can
show a meaningful toast instead of a generic "Done" / the raw error.
`successMessage` is set on terminal success, `errorMessage` on failure.

Only ONE producer honours it. Grepping the engine for both names:

  • successMessage: flow.successMessage — one site, inside resumeInternal's terminal
    success return.
  • errorMessage: flow.errorMessage — one site, inside resumeInternal's terminal
    failure return.

execute() sets neither, on either exit — not on its success return, not on its failure
return, and not on executeWithoutRetry / retryExecution. So the author's own text
reaches a caller only when the run happened to pause and be resumed. A flow dispatched
straight through POST /api/v1/automation/:name/trigger (or the legacy
POST /automation/trigger/:name, i.e. client.automation.trigger()) never carries it,
even though the flow declares it and the contract says it is set.

Why it matters now

PR #9413 maps a failed trigger run to 400 FLOW_FAILED and carries errorMessage into
error.details.errorMessage — the one documented location the console reads (objectui
flowResponse.ts, PR #4899). That plumbing is correct and inherited verbatim from #8684,
but on the trigger path the field is always absent at the source, so the console falls
back to the raw node error for every non-screen flow. The same holds for successMessage
on the 200 path.

Not decided here

Whether execute() should set both (symmetry with resumeInternal, which is the obvious
reading of the contract text) or whether the contract text should narrow to say these are
screen-flow/resume-only. One of the two is true; the current state — declared generally,
produced on one path — is the shape ADR-0049's enforce-or-remove exists to stop.

Refs


Generated by Claude Code

Metadata

Metadata

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions