Skip to content

feat(workflow-executor): pause a Trigger Action step on its approval and resume on the reviewer's branch [PRD-2004] - #2063

Merged
matthv merged 4 commits into
feature/prd-29-handle-action-approvals-within-workflowsfrom
feature/prd-2004-approvals-in-workflows-pause-and-resume-a-trigger-action
Nov 5, 2026
Merged

matthv merged 4 commits into
feature/prd-29-handle-action-approvals-within-workflowsfrom
feature/prd-2004-approvals-in-workflows-pause-and-resume-a-trigger-action

Conversation

@matthv

@matthv matthv commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

What

Executor side of PRD-2004, milestone M1 (automatic mode). Server side: ForestAdmin/forestadmin-server#8741. Contract: Dev split.

  • Contract: the Trigger Action definition keeps approvalOutcomes (the non-strict schema used to drop it). The pending step's context.approvalRequests ({ id, status, approverId }) now reaches the executor, an unknown status being dropped. A record outcome carries awaitingInputReason: 'pending-approval', approvalRequests, selectedOption (approved / rejected) and approverId, all forwarded to the orchestrator.
  • Pause: in Full AI, on a step with approval outcomes, an action filed for approval pauses the step on its request instead of succeeding. A request with no id errors the step.
  • No approval needed: an action that ran reports selectedOption: 'approved'.
  • Replay (checkIdempotency), once the orchestrator requeues the run:
    • approved / rejected → success on that branch with approverId, and the decision is saved in the RunStore;
    • failed → operator error;
    • no status (deleted or unknown request) → error;
    • still open, or no review sent → pause again.
  • Later AI steps read "APPROVED and run by the reviewer" or "REJECTED, NOT executed" instead of "AWAITING APPROVAL".
  • Steps without approvalOutcomes behave exactly as today.

Not in this PR

  • Manual and AI-assisted modes (native front form): PRD-2013.
  • On a step with approval outcomes, a Full AI step skipped for want of a source record succeeds without selectedOption, so the orchestrator errors it rather than going down Approved. Choosing the branch belongs to PRD-2014 (Q7).

How to play it

Follow the "How to play it" section of ForestAdmin/forestadmin-server#8741 with this branch running as the executor.

Part of PRD-2004

🤖 Generated with Claude Code

Note

Add approval pause and resume to Trigger Action steps in workflow-executor

  • Trigger Action steps with approvalOutcomes enabled now pause after filing an approval request and resume on replay without resubmitting the action, succeeding on the approved or rejected branch. See trigger-record-action-step-executor.ts.
  • New schemas and mappers validate and carry approval request reviews through the pending-step context, step definitions, and record outcomes. Adds ApprovalRequestUntrackedError, ApprovalRequestFailedError, and ApprovalRequestGoneError for missing request IDs, failed approvals, and unrecognized review statuses.
  • Execution summaries now distinguish approved (action ran, result unavailable), rejected (not executed), and pending approvals.
  • Behavioral Change: the new pause/resume path applies only to steps with approvalOutcomes set; the existing pending-approval replay path remains for other steps. Missing approval request IDs, failed approvals after review, and reviews with no recognized status now produce step errors; open or missing reviews pause again.

Changes since #2063 opened

  • Added ApprovalBranchesNeedFullAiError and a guard in TriggerRecordActionStepExecutor.pauseForConfirmation that throws it when native-form fallback occurs on a step with approvalOutcomes [0fa16c0]
  • Added a test in trigger-record-action-step-executor.test.ts for the ApprovalBranchesNeedFullAiError path [0fa16c0]
  • Updated the workflow-executor CLAUDE.md documentation [0fa16c0]

Macroscope summarized 9053246.

matthv and others added 3 commits November 5, 2026 10:52
…paused step's requests [PRD-2004]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…request and resume on the reviewer's branch [PRD-2004]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a Trigger Action [PRD-2004]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Nov 5, 2026

Copy link
Copy Markdown

PRD-2004

@qltysh

qltysh Bot commented Nov 5, 2026

Copy link
Copy Markdown

8 new issues

Tool Category Rule Count
qlty Structure Function with many returns (count = 4): toStepOutcome 4
qlty Structure Function with high complexity (count = 17): toUpdateStepRequest 4

@qltysh

qltysh Bot commented Nov 5, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

Unable to calculate total coverage change because base branch coverage was not found.

Modified Files with Diff Coverage (8)

RatingFile% DiffUncovered Line #s
New file Coverage rating: A
packages/workflow-executor/src/types/validated/execution.ts100.0%
New file Coverage rating: A
packages/workflow-executor/src/types/validated/step-outcome.ts100.0%
New file Coverage rating: A
...-executor/src/executors/trigger-record-action-step-executor.ts100.0%
New file Coverage rating: A
...workflow-executor/src/adapters/run-to-available-step-mapper.ts100.0%
New file Coverage rating: A
packages/workflow-executor/src/errors.ts100.0%
New file Coverage rating: A
packages/workflow-executor/src/types/validated/step-definition.ts100.0%
New file Coverage rating: A
...ow-executor/src/adapters/step-outcome-to-update-step-mapper.ts100.0%
New file Coverage rating: A
...ow-executor/src/executors/summary/step-execution-formatters.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@matthv
matthv marked this pull request as ready for review November 5, 2026 10:25

@Scra3 Scra3 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spec (PRD-2004): conforms, except "Always send selectedOption on these steps" on the native-form path, raised inline.

result && !('skipped' in result) && result.submissionOutcome === 'pending-approval';
const approvalRequest = isPendingApproval ? result.approvalRequest : undefined;

if (isPendingApproval && this.hasApprovalOutcomes) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (claude-opus-5-5): Preferential: a paused approval step keeps a done record and resumes through the idempotency replay, and no ADR records that choice.

Code

Paused runs persist a done plus pending-approval record, a reader asks why a waiting step is done, and a pause phase was the alternative.

A way out: record the decision with /adr in docs/adr/.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Opus 5.5 (claude-opus-5-5): No ADR, the paused done record fails the hard-to-reverse leg of the gate.

Why

A later pause phase can still read today's done plus pending-approval records the way checkIdempotency does, so switching costs one read path, not a migration.
The record lives in the client's RunStore and never crosses the orchestrator contract.

Comment thread packages/workflow-executor/CLAUDE.md Resolved
@Scra3

Scra3 commented Nov 5, 2026

Copy link
Copy Markdown
Member

Forest Validator · Review: findings posted

When (UTC) Commit Step Result
05/11 15:21 9053246 Review findings posted · run 2063-20261105150321-Scra3

…Action with approval branches [PRD-2004]

A step finished by hand reports no branch until the native form carries one (PRD-2013), so the
orchestrator errored the run after the human submitted. The step now errors before handing the form
over, and CLAUDE.md states the approval exception to the idempotency replay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@Scra3 Scra3 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved after /verify-fixes run 2063-20261105161509-Scra3-verify: 3 findings of 2063-20261105150321-Scra3 closed or declined, none reopened.

@matthv
matthv merged commit d386f0f into feature/prd-29-handle-action-approvals-within-workflows Nov 5, 2026
39 checks passed
@matthv
matthv deleted the feature/prd-2004-approvals-in-workflows-pause-and-resume-a-trigger-action branch November 5, 2026 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants