Parallel execution fork/join — Phases 1–3: Java engine, TypeScript parity, viewer/sim UI (#88) - #97
Open
EricWittmann wants to merge 32 commits into
Open
Parallel execution fork/join — Phases 1–3: Java engine, TypeScript parity, viewer/sim UI (#88)#97EricWittmann wants to merge 32 commits into
EricWittmann wants to merge 32 commits into
Conversation
- TRANSITION error recovery now targets the actual failing branch instead of guessing "root", so recovery works when a branch fails inside a parallel region (closes the failing node's history entry, no phantom branch). Threads branchId through executeActionNode/applyResolution and the surrounding error-recovery call sites; adds a fail-safe guard for a missing branch id. Success-path history completion is now branch-aware. - Info/event accessors (getHumanTaskInfo/getReceiveEventInfo/getWaitInfo/ getActionInfo/matchesEvent) gain nodeId-addressable overloads; the no-arg methods delegate to them and, during concurrent WAITING (currentNodeId null), scan parked branches. - moveBranch clears a join's arrival record once it fires so a loop-back re-entry starts clean. - Remove dead completeCurrentHistoryEntry overloads. - Add tests: parallel-region TRANSITION recovery, concurrent receive-event branch addressing, and nested fork/join completion.
…structural rules (#88)
Brings the TS simulation + validation to parity with the Phase 1 Java engine: active-branch token model, shared fork/join analyzer, structural validation rules, and fork fan-out / AND-join synchronization in the simulator.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add withParallelHint HOC to wrap node components and display a small corner badge indicating the node's parallel role (fork or join) in the workflow editor. The hint is only visible in the editor and does not appear in the read-only viewer. - parallelHint.tsx: New HOC that renders fork/join labels when data.parallelRole is set - parallelHint.css: Styles for the corner badge (top-right position) - nodeTypes.ts: Compose withParallelHint as the innermost wrapper around all node types
…ewer, and editor guides (#88) Phase 5 documentation: add subsections for parallel execution semantics across six user-guide pages, create the CVE analyze-and-notify worked example, update mkdocs nav and index links, and verify all cross-task references resolve correctly via mkdocs build --strict.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Phases 1, 2, and 3 of parallel execution (fork/join) for workflows, per the design spec in
docs/superpowers/specs/2026-09-04-parallel-execution-fork-join-design.md:@apitomy/flow-uisimulation and validation, so thebrowser-side simulator and validator agree with the Java engine byte-for-byte.
WorkflowViewer, editor simulation overlay, and simulationpanel render concurrent fork/join branches instead of a single cursor.
Editor authoring affordances and remaining docs (Phases 4–5) are follow-ups.
Closes #88 (Phases 1–3).
Phase 1 — Java engine + validator
ActiveBranch(branchId, nodeId);WorkflowInstancegainsactiveBranches+joinArrivals(with a derivedcurrentNodeIdfor the single-branch case);HistoryEntrygains an optional trailingbranchId(8-arg canonical + 7-arg back-compat ctor).Legacy-serialized instances deserialize without NPE (null-coercing canonical ctor).
ParallelRegionsanalyzer — a pure fork→join analysis shared by the engine and validator.A fork is a node whose ≥2 outgoing edges are all unconditional (no condition, none default);
the AND-join is the node where those branches re-converge.
UNCONDITIONAL_MULTIPLE_EDGES(that shape is now valid fork authoring) andemits structural codes
MIXED_FORK_EDGES,FORK_WITHOUT_JOIN,PARALLEL_BRANCH_REACHES_END.advance()— fork fan-out, AND-join wait-for-all (fires once), fail-fast branchfailure,
ENDterminates the whole instance, branch-attributed history; error-handlerTRANSITIONrecovery targets the actual failing branch (correct inside parallel regions, fail-safe otherwise).
completeNode(workflow, instance, nodeId, result)resumes one parked branch whilesiblings keep waiting;
completeCurrentNodedelegates for the single-branch case. Info/event accessors(
get*Info,matchesEvent) are branch-addressable bynodeIdfor concurrent WAITING instances.Phase 2 — TypeScript parity (
@apitomy/flow-ui)Brings the TS simulation + validation to parity with the Phase 1 engine. Each piece is a faithful port
of its Java counterpart, verified method-by-method:
types/instance.ts— active-branch instance state (ActiveBranch,activeBranches,joinArrivals),currentNodeId: string | nullfor wire parity, and branch-attributedHistoryEntry.branchId.simulation/parallelRegions.ts— pure port ofParallelRegions(fork detection, join discovery,structural problems). Outgoing edges are traversed in
priorityorder, matching JavaWorkflow.getOutgoingEdges.validation/validateWorkflow.ts— retiresUNCONDITIONAL_MULTIPLE_EDGES; addsvalidateParallelStructureemitting exactly the same three codes as the Java validator, with the sameskip-guard and
errorseverity.simulation/simulate.ts— reshaped to the active-branch token model, then extended with forkfan-out (child branch ids
<parent>.<index>, assigned in priority order) and AND-join synchronization(continuing branch
<join>#join), fail-fast, and END-cancels-siblings. Back-compat derived fields(
currentNodeId,blockedOn) keep existing single-path UI consumers working unchanged.Phase 3 — viewer / simulation UI (
@apitomy/flow-ui)Renders concurrent branches everywhere the UI previously assumed a single cursor. All multi-branch
derivation is extracted into pure, framework-free helpers (unit-tested with vitest); the React
components are thin renderers over them.
utils/parallelView.ts— pure branch-view helpers:activeNodeIds(parked-aware),activeEdgeIds(per-branch arrival-edge selection),parkedNodes,branchPaths(per-branch pathgrouping), and
simNodeClass(class precedence failed > blocked > current > visited > idle). Rootback-compat throughout via
entry.branchId ?? 'root'.utils/nodeHistory.ts—nodeVisitsByBranchgroups a node's visits by branch for branch-awaredetail.
WorkflowViewer— highlights every active node (with a terminal-statecurrentNodeIdfallback),animates the arrival edge of every active branch while preserving historical traversed-edge styling,
and groups the NodeDetail visit selector by branch with a Branch row.
WorkflowEditor— the simulation overlay classes are computed from the active-branch set (sharedsimNodeClass), and resume is widened to target a specific parked node.SimulationPanel— shows the list of all active nodes, a one-at-a-time picker across blockedbranches (fill a mock, deliver, repeat), and a path list grouped per branch.
Backward compatibility
Non-parallel workflows run through the same token driver with a single
rootbranch on both sides, soexisting single-cursor behavior, serialized instances, and the full prior test suites are preserved
unchanged. The Phase 3 UI renders a plain linear workflow exactly as before (one active node, one
unlabeled path, single-block resume). Phase 3 is presentation-only — no engine, type, or validation
files were touched.
Testing
mvn -f engine/pom.xml test→ 180 tests, 0 failures. Coverage: fork-runs-both,join-waits-for-all & fires once, fail-fast, END-cancels, branch-attributed history,
resume-one-leaves-sibling-waiting, nested fork/join, parallel-region error recovery, and concurrent
branch-addressable event matching.
npx vitest run→ 194 tests, 0 failures;tsc --noEmit,npm run lint, andnpm run buildall clean. Coverage mirrors the engine's parallel tests plus the analyzer, validatorstructural rules, and the Phase 3 branch-view helpers (active/parked node sets, per-branch arrival
edges with cross-branch isolation, branch path grouping, node-class precedence). Per project
convention (no jsdom/RTL) the React components are verified by tsc/lint/build plus the green suite.
Deferred follow-ups (tracked, out of scope for this PR)
UNBALANCED_PARALLEL,CROSSING_PARALLEL_REGIONS,PARALLEL_REGION_CYCLE(need region-crossing detection + intra-region SCC analysis) — in both the Javaand TS validators. Both fail safe on such graphs at runtime today.
MAX_TRANSITIONS(=100) now that it counts across all branches — very wide/deep parallelgraphs could trip it.
picker keys by node and resolves them iteratively).