Skip to content

Parallel execution fork/join — Phases 1–3: Java engine, TypeScript parity, viewer/sim UI (#88) - #97

Open
EricWittmann wants to merge 32 commits into
mainfrom
issues/gh-88
Open

Parallel execution fork/join — Phases 1–3: Java engine, TypeScript parity, viewer/sim UI (#88)#97
EricWittmann wants to merge 32 commits into
mainfrom
issues/gh-88

Conversation

@EricWittmann

@EricWittmann EricWittmann commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

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:

  • Phase 1 — the Java engine + Java validator.
  • Phase 2 — TypeScript parity for the @apitomy/flow-ui simulation and validation, so the
    browser-side simulator and validator agree with the Java engine byte-for-byte.
  • Phase 3 — viewer / simulation UI: the WorkflowViewer, editor simulation overlay, and simulation
    panel 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

  • Active-branch state modelActiveBranch(branchId, nodeId); WorkflowInstance gains
    activeBranches + joinArrivals (with a derived currentNodeId for the single-branch case);
    HistoryEntry gains an optional trailing branchId (8-arg canonical + 7-arg back-compat ctor).
    Legacy-serialized instances deserialize without NPE (null-coercing canonical ctor).
  • ParallelRegions analyzer — 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.
  • Validation — retires UNCONDITIONAL_MULTIPLE_EDGES (that shape is now valid fork authoring) and
    emits structural codes MIXED_FORK_EDGES, FORK_WITHOUT_JOIN, PARALLEL_BRANCH_REACHES_END.
  • Token-based advance() — fork fan-out, AND-join wait-for-all (fires once), fail-fast branch
    failure, END terminates the whole instance, branch-attributed history; error-handler TRANSITION
    recovery targets the actual failing branch (correct inside parallel regions, fail-safe otherwise).
  • Resume-by-nodecompleteNode(workflow, instance, nodeId, result) resumes one parked branch while
    siblings keep waiting; completeCurrentNode delegates for the single-branch case. Info/event accessors
    (get*Info, matchesEvent) are branch-addressable by nodeId for 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 | null for wire parity, and branch-attributed
    HistoryEntry.branchId.
  • simulation/parallelRegions.ts — pure port of ParallelRegions (fork detection, join discovery,
    structural problems). Outgoing edges are traversed in priority order, matching Java
    Workflow.getOutgoingEdges.
  • validation/validateWorkflow.ts — retires UNCONDITIONAL_MULTIPLE_EDGES; adds
    validateParallelStructure emitting exactly the same three codes as the Java validator, with the same
    skip-guard and error severity.
  • simulation/simulate.ts — reshaped to the active-branch token model, then extended with fork
    fan-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 path
    grouping), and simNodeClass (class precedence failed > blocked > current > visited > idle). Root
    back-compat throughout via entry.branchId ?? 'root'.
  • utils/nodeHistory.tsnodeVisitsByBranch groups a node's visits by branch for branch-aware
    detail.
  • WorkflowViewer — highlights every active node (with a terminal-state currentNodeId fallback),
    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 (shared
    simNodeClass), 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 blocked
    branches (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 root branch on both sides, so
existing 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

  • Java engine: mvn -f engine/pom.xml test180 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.
  • TypeScript UI: npx vitest run194 tests, 0 failures; tsc --noEmit, npm run lint, and
    npm run build all clean. Coverage mirrors the engine's parallel tests plus the analyzer, validator
    structural 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)

  • Emit the remaining validation codes UNBALANCED_PARALLEL, CROSSING_PARALLEL_REGIONS,
    PARALLEL_REGION_CYCLE (need region-crossing detection + intra-region SCC analysis) — in both the Java
    and TS validators. Both fail safe on such graphs at runtime today.
  • Revisit MAX_TRANSITIONS (=100) now that it counts across all branches — very wide/deep parallel
    graphs could trip it.
  • Per-branch targeting when two concurrent branches are parked on the same node (today the blocked
    picker keys by node and resolves them iteratively).
  • Phases 4–5 (editor authoring affordances, docs) per the spec.

- 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.
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.
@EricWittmann EricWittmann changed the title Parallel execution fork/join — Phase 1: Java engine + validator (#88) Parallel execution fork/join — Phases 1–2: Java engine + TypeScript parity (#88) Sep 4, 2026
@EricWittmann EricWittmann changed the title Parallel execution fork/join — Phases 1–2: Java engine + TypeScript parity (#88) Parallel execution fork/join — Phases 1–3: Java engine, TypeScript parity, viewer/sim UI (#88) Sep 5, 2026
EricWittmann and others added 4 commits September 5, 2026 19:53
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.
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.

Parallel execution: fork/join (concurrent branches)

1 participant