Skip to content

feat(workflow-executor): use a sub-workflow's end as a decision condition source - #2070

Open
christophebrun-forest wants to merge 3 commits into
mainfrom
feature/prd-988-use-sub-workflow-end-as-a-decision-condition-input
Open

christophebrun-forest wants to merge 3 commits into
mainfrom
feature/prd-988-use-sub-workflow-end-as-a-decision-condition-input

Conversation

@christophebrun-forest

@christophebrun-forest christophebrun-forest commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Part of PRD-988. Integration branch for the epic in agent-nodejs. Draft until the orchestrator and front lots are ready.

What this delivers

Lot 2 of PRD-988 (PRD-2028): a deterministic Decision condition can read which End an upstream Sub-workflow step returned from, for example "if Sub-workflow 1 › End is Approved, then A".

Already reviewed and merged here (main, with #2064's nested condition groups, merged in since; an End condition works at any depth of a group):

Existing Get Data conditions are unchanged. Nothing sends a sub-workflow source until the orchestrator does, so this code does nothing on its own.

Contract with the other lots

{ sourceType: 'sub-workflow', sourceStepId: <Sub-workflow step id>, fieldName: 'end', operator, value }

  • value is an End id, or a non-empty list of End ids for in / not_in.
  • The End's name copy goes in a separate key.
  • The executor relies on the CloseSubWorkflow history entry's stepName being the End's BPMN element id.

Before marking ready

  • PRD-2029 (forestadmin-server): parser accepts the condition; executor-version floor at run start and on descent.
  • End-to-end check on a local stack: the CloseSubWorkflow stepName is the End's id, and each operator routes as named.

Rollout

Merging this publishes a new @forestadmin/workflow-executor minor, and that published version is the floor PRD-2029 sets: executors older than it strip sourceType and would read such a condition as Get Data, routing to the fallback.

  • The floor is known only once this merges: 1.36.0 already shipped from main (feat(wf nested condition): allow nested condition on gateway step #2064) without this source, so the orchestrator's DEFAULT_MIN_SUB_WORKFLOW_END_CONDITION_EXECUTOR_VERSION = '1.36.0' is too low and must be raised to the version this merge publishes. Order: this branch → orchestrator floor → front (PRD-2030, PRD-1941).

🤖 Generated with Claude Code

Note

Add sub-workflow End as a condition source type in workflow-executor

  • Deterministic conditions can now resolve their value from a sub-workflow's returned End, in addition to the existing Get Data record lookup. ConditionStepExecutor.resolveConditionValue dispatches on the condition's source type, which defaults to get-data when absent or null. See condition-step-executor.ts.
  • Sub-workflow End conditions accept only the end field and the equal, not_equal, in, and not_in operators. List operators require a non-empty list of non-empty strings; scalar operators require a non-empty string. Validation lives in step-definition.ts.
  • A new call-history walk in run-to-available-step-mapper.ts collects the latest reached End per sub-workflow call, scoped to the pending step's own workflow frame. Results pass through ExecutionContext as subWorkflowEnds.
  • Replaces the condition/group union parser with shape-based dispatch, so invalid condition nodes now report schema-specific issues with paths instead of a bare union failure.
  • Risk: an unrecognized sourceType raises InvalidStepDefinitionError in both toStepDefinition and condition execution, so existing condition definitions with unknown source-type values that previously parsed will now fail validation.

Macroscope summarized 5073c7f.

christophebrun-forest and others added 2 commits November 6, 2026 14:50
…ce type (#2067)

* refactor(workflow-executor): resolve a decision condition by its source type

A condition carries an optional sourceType, absent meaning get-data, so later
source kinds plug in their own resolver. No behaviour change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ondition source (#2068)

* feat(workflow-executor): resolve a sub-workflow's end as a decision condition source

A condition with sourceType sub-workflow and field end reads the id of the End
the most recent call of that Sub-workflow step returned from, among the calls
the pending step's own workflow made. Not reached means not met.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@linear-code

linear-code Bot commented Nov 6, 2026

Copy link
Copy Markdown

PRD-988

@qltysh

qltysh Bot commented Nov 6, 2026

Copy link
Copy Markdown

1 new issue

Tool Category Rule Count
qlty Structure Function with many returns (count = 4): resolveGetDataValue 1

@qltysh

qltysh Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Qlty


Coverage Impact

⬆️ Merging this pull request will increase total coverage on main by 0.1%.

Modified Files with Diff Coverage (4)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
packages/workflow-executor/src/types/validated/execution.ts100.0%
Coverage rating: A Coverage rating: A
...ges/workflow-executor/src/executors/condition-step-executor.ts100.0%
Coverage rating: A Coverage rating: A
...workflow-executor/src/adapters/run-to-available-step-mapper.ts100.0%
Coverage rating: A Coverage rating: A
packages/workflow-executor/src/types/validated/step-definition.ts100.0%
Total100.0%
Commit 5073c7f · 🚦 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.

Resolves the conflict with #2064 (nested condition groups):
- the server condition node carries `sourceType`, nullable like the schema;
- a condition node is dispatched on its shape instead of through z.union, so an
  unknown source type, operator or sub-workflow End rule names the field at fault
  instead of a bare "Invalid input";
- tests cover a sub-workflow End condition inside a group, mixed with Get Data,
  and a second call of a workflow not seeing the Ends of the first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@christophebrun-forest
christophebrun-forest marked this pull request as ready for review November 10, 2026 15:44

This branch has not been deployed

No deployments
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.

1 participant