Skip to content

feat(engine): evaluate conditional edges independently - #55

Merged
Zhoujie628 merged 3 commits into
project-openan:mainfrom
Zhoujie628:main
Sep 9, 2026
Merged

Zhoujie628 merged 3 commits into
project-openan:mainfrom
Zhoujie628:main

Conversation

@Zhoujie628

@Zhoujie628 Zhoujie628 commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

Closes #54

Summary

  • Replace N-choose-1 route selection with per-edge allow/deny: onRoute is called once per conditional edge, RouteDecision.allow()/deny() answers that edge, and unconditional edges always run — fixing mixed-edge steps where an unconditional successor could previously be outvoted. RouteDecision.nextStep and RouteRequest.candidates are removed (breaking, recorded in the changelog).
  • Normalize routing failures per edge (sync throw / null future / null decision / timeout → "onRoute failed for edge -> " with the original cause preserved); all conditional callbacks are invoked before the atomic all-or-nothing successor decision.
  • Reject duplicate outgoing targets, null edges and blank targets during workflow validation; emit route_decision once per edge after the routing phase succeeds.

Test plan

  • Full main reactor mvn -B clean verify: 321/321 green (engine 205, starter 21, samples 95)
  • New regression tests: null future and synchronous exception still invoke every remaining conditional callback and dispatch no successor; timeout identifies the edge; deny-all ends the branch; mixed edges run unconditional + allowed conditional targets; merge does not wait for denied branches
  • Three cross-review rounds completed (semantics / formatting & imports / failure normalization), artifacts under reviews/

Replace the N-choose-1 route selection with per-edge allow/deny: onRoute
now receives one conditional edge per call (RouteRequest carries the step,
condition and upstream window) and answers with RouteDecision.allow/deny
for that edge. Unconditional edges always run and bypass the callback, so
mixed-edge steps no longer risk swallowing an unconditional successor;
allowed conditional edges activate in parallel with them.

Routing failures are normalized per edge: synchronous throws, null
futures, null decisions and timeouts all become edge-identifiable
failures ("onRoute failed for edge <src> -> <tgt>") that preserve the
original cause, invoke every remaining conditional callback first, and
suppress all successors. Workflow validation now rejects duplicate
outgoing targets, null edges and blank targets. The route_decision event
is emitted once per edge after the whole routing phase succeeds.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
Record the breaking routing change in the changelog (single-edge
RouteRequest, allow/deny RouteDecision, removed nextStep/candidates,
new graph validation rules, per-edge route_decision events) and align
the bilingual API reference, callback contract, design, developer and
integration guides with the implemented semantics.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
@Zhoujie628
Zhoujie628 requested a review from a team as a code owner September 9, 2026 06:33
Expand the wildcard imports (model, client, java.util, java.util.concurrent
and static Assertions) that the IDE auto-collapsed back into explicit
single-class imports across the seven touched files. No code change.

Signed-off-by: Zhoujie628 <zhoujie628@users.noreply.github.com>
@Zhoujie628
Zhoujie628 merged commit e15c0a7 into project-openan:main Sep 9, 2026
3 checks passed
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.

Per-edge conditional routing with edge-identifiable failures

1 participant