A join that fires when ALL currently active incoming branches complete — regardless of how many branches are active. Branch count is determined at runtime, not at design time. Fires once all activated branches (however many were actually started) are done.
A dynamic research orchestrator receives a query and evaluates it against 8 possible specialist domains — machine learning, security, economics, biology, chemistry, physics, law, and ethics. Depending on the query's topic profile, between 2 and 8 domain agents are activated. For a query about AI regulation, 4 agents might activate: ML, law, economics, and ethics. The synthesis node waits for however many agents were actually activated — not a fixed count. If 4 were spawned, it waits for 4; if 7, it waits for 7.
The key insight: the AND-join AND-join requires all N branches to complete, where N is fixed at design time. But when N varies per execution (because a routing condition controls which branches activate), a fixed-N join will either deadlock (waiting for branches that were never started) or fire prematurely (if only activated branches are counted but the join doesn't know the activation count). The generalised AND-join solves this by tracking which branches were actually activated at runtime and waiting for exactly that set.
| Metric | Signal |
|---|---|
| Mean agent activation count | Average number of domain agents activated per query — tracks whether the orchestrator's routing is appropriately selective |
| AND-join fire latency | Time from last branch activation to all completions received — bounded by the slowest activated agent |
| Activation predicate hit rate | Per-domain fraction of queries that activate each agent — reveals underused or overused domains in the orchestrator's routing logic |
| Synthesis quality vs. agent count | Correlation between number of activated agents and output quality score — validates whether more activations produce better reports |
| Node | What it does | What it receives | What it produces |
|---|---|---|---|
| Dynamic Orchestrator | Evaluates the query against each domain's relevance predicate and activates a subset of domain agents via OR-split. Records which agents were activated. | Research query + domain relevance config | K activations (2..8, determined at runtime) |
| Domain Agent A..D | Each activated agent runs a domain-specific research subtask and produces a structured findings object | Query + domain-specific tools and knowledge | Domain findings object |
| Synthesizer (AND-join) | Waits for all activated agents to complete. Fires only once all K completion tokens arrive (K tracked at runtime from the orchestrator's activation record). Merges findings into a unified research report. | Findings from all K activated agents | Unified research report |
| Origin of Value | Where it appears | How it is captured |
|---|---|---|
| Future Cashflow | Research report completeness | Coverage adapts to query complexity — 2 agents for a narrow query, 8 for a broad one. Compute cost scales with query complexity rather than being fixed at the maximum. |
| Governance | Orchestrator activation logic | The relevance predicates that determine which agents activate are the governance layer. Changing these predicates changes which expertise is applied to each query — an editorial policy decision. |
| Conditional Action | Each activated domain agent | Only activated agents consume compute. Non-activated agents cost nothing. This is the primary efficiency advantage over a fixed-N AND-join that always runs all N branches. |
| Risk Exposure | Orchestrator activation record | The AND-join relies on the orchestrator's activation record to know what to wait for. If this record is lost or corrupted (process restart, state loss), the join cannot determine its completion condition. Persistent activation state is required. |
Static vs. generalised AND-join. The standard AND-join fires when all N branches in the workflow diagram complete — a static count. The generalised AND-join fires when all branches that were actually activated in this execution complete — a dynamic count. The difference is invisible in diagrams but critical in implementation: the join needs runtime activation tracking, not just flow token counting.
The orchestrator evaluates all domain predicates and none pass (query is outside all known domains). Zero agents are activated. The AND-join waits for "all activated agents" — but there are none. Depending on implementation, it may fire immediately (correct) or wait indefinitely (incorrect). Fix: the orchestrator must guarantee at least one activation, either by adding a "general purpose" catch-all domain or by routing zero-activation queries to a dedicated fallback path before reaching the join.
The orchestrator activates 5 agents and records this. The process crashes. On recovery, the AND-join loads state from its token count but the activation record is gone. It cannot determine whether to wait for 5 completions or fewer. Fix: write the activation count as part of the join's durable state at the same time as the activation itself. The join reads its expected completion count from its own persisted state, not from the orchestrator's runtime context.
One domain agent's activation is conditional on another agent's partial output (a chain dependency). This late activation happens after the AND-join has already received tokens from the initially-activated agents. The join fires prematurely, before the late-activated agent completes. Fix: all activations must be deterministic from the orchestrator's initial evaluation. Chained or conditional activations that occur after the join has started receiving tokens are incompatible with this pattern — use 30.40 for dynamic extension of the active set.
| Variant | Modification | When to use |
|---|---|---|
| Priority-Weighted AND-Join | Higher-priority agents are dispatched first; the join begins synthesis as soon as these complete, even if low-priority agents are still running | Domain agents have heterogeneous importance; critical domains should not wait for secondary ones |
| Capped Generalised AND-Join | Maximum activation count is capped at K; if more than K predicates pass, K agents are selected by priority ranking | Compute budget must be bounded even when many domains are relevant |
| Incremental Synthesis | The synthesizer produces a preliminary report after each agent completes, updating it as additional agents arrive | Downstream consumers need intermediate results while full synthesis is pending |
| Pattern | Relationship |
|---|---|
| 40.41 Multi-Choice | The natural split counterpart — 20.21 selectively activates branches; 20.28 synchronizes them on completion |
| 40.46 Structured Partial Join | M-of-N variant — use when only a subset of activated branches need to complete before proceeding |
| 60.67 Dynamic Partial Join MI | When branches can be added during execution — not just determined at the start of the run |
| 20.23 Orchestrator-Workers | Higher-level pattern: the orchestrator activates workers dynamically; 20.28 is the join mechanism that synchronizes their completion |