Skip to content

epic: scope propagation, return-path tracking, and context write-through #204

@mdproctor

Description

@mdproctor

Summary

Ensures context flows correctly down through nested execution boundaries and back up via explicit return-path tracking. Introduces CompletionTracker — a unified service that eliminates duplicate fan-in logic across SubCase, MultiInstance WorkItem, Plan step, and FlowWorker step completion.

Consolidation — CompletionTracker

Every spawning completion currently reimplements the same logic: find the spawn record by child ID, check whether the group policy is satisfied, route output to the returnTo target. CompletionTracker unifies this:

interface CompletionTracker {
    // Called at spawn time by every spawning operation
    SpawnHandle track(UUID parentLedgerEntryId,
                      List<UUID> childIds,
                      CompletionPolicy policy,
                      Object returnTo);

    // Called at every completion event
    Optional<GroupResult> recordCompletion(UUID childId, Map<String, Object> output);
    // Returns non-empty when policy satisfied — caller routes GroupResult.output to returnTo
}

enum CompletionPolicy { ALL, M_OF_N, FIRST, ANY }

SubCaseCompletionListener, MultiInstanceCoordinator (quarkus-work), PlanStepHandler, and WorkflowStepCompletion all register with CompletionTracker at spawn time. At completion they call recordCompletion(). The tracker fires when the policy is satisfied.

This also eliminates the EventLog scan at completion time — the tracker holds returnTo directly, so completion listeners no longer need to query EventLog to find the parent. The findByWorkerAndType workaround (#195 fix) is structurally superseded.

Return-path tracking

  • SpawnHandle returned by track() carries: spawnId, returnTo, policy, groupSize
  • Completion routes to the enclosing context (WorkflowContext if inside FlowWorker), not root CaseContext
  • returnTo is recorded at spawn time; never inferred at completion time

Context stack

  • Runtime tracking of active context frames per case execution
  • Each ContextBridge.initialise() pushes a frame; complete() pops it
  • Stack is used by CompletionTracker to resolve returnTo references at completion

Write-through (optional per bridge)

  • ContextBridge.onWrite() — called when a key is written to the bridged context
  • Bridges opt in to immediate EventLog entries for significant intermediate state
  • Default: no write-through (current behaviour)

quarkus-work multi-instance

Part of

#201

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestepicTracks a large body of related work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions