mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Remove ErrorPolicy enum (continue/fail_fast/ignore) and the k_of_n/quorum join policies from the parallel handler, leaving only wait_all and first_success. This deletes ~180 lines of conditional logic including FailFast early termination, the ParallelEarlyTermination event, and all related tests and documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
130 lines
6.3 KiB
Text
130 lines
6.3 KiB
Text
---
|
|
title: "Node Outcomes"
|
|
description: "The five stage statuses and the attributes that control them"
|
|
---
|
|
|
|
Every node execution produces an **outcome** containing a status that drives edge routing, retry logic, and goal gate checks. This page defines the five statuses and the attributes that influence them.
|
|
|
|
## The five statuses
|
|
|
|
| Status | Meaning |
|
|
|---|---|
|
|
| `success` | The handler completed normally |
|
|
| `fail` | The handler encountered an unrecoverable error |
|
|
| `partial_success` | The handler did not fully succeed but produced usable results — typically from retries exhausted with `allow_partial=true` |
|
|
| `retry` | The handler wants to re-execute — consumed by the [retry loop](#retry-loop) and never appears in edge conditions |
|
|
| `skipped` | The node was not executed (e.g. a branch not taken in a parallel fan-out) |
|
|
|
|
<Note>
|
|
`retry` is internal to the engine. It triggers re-execution inside the retry loop and is never visible in edge `condition` expressions. The four externally-visible statuses are `success`, `fail`, `partial_success`, and `skipped`.
|
|
</Note>
|
|
|
|
## How handlers produce statuses
|
|
|
|
Each node type has its own rules for which statuses it can return:
|
|
|
|
| Handler | Produces | Conditions |
|
|
|---|---|---|
|
|
| **Command** | `success`, `fail` | `success` when exit code is 0; `fail` otherwise |
|
|
| **Agent / Prompt** | `success`, `fail`, `partial_success`, `retry`, `skipped` | Defaults to `success`. The LLM can set any status via a [routing directive](/agents/outputs#routing-directives) JSON object in its response. Backend errors produce `retry` (if retryable) or `fail`. |
|
|
| **Parallel** | `success`, `partial_success`, `fail` | Depends on the `join_policy`. `wait_all`: `success` if no failures, `partial_success` if some branches failed. `first_success`: `success` if threshold met, else `fail`. |
|
|
| **Human** | `success` | Always succeeds — the user's selection becomes a routing signal via `preferred_label` |
|
|
| **Conditional** | `success` | Always succeeds — routing is handled by the engine's edge selection |
|
|
| **Start / Exit / Wait** | `success` | Always succeed |
|
|
|
|
## Retry loop
|
|
|
|
When a handler returns `retry` status, the engine enters the retry loop. If retry attempts remain (per the node's [retry policy](/execution/failures#retry-policies)), the handler re-executes after a backoff delay. If attempts are exhausted, the final status depends on `allow_partial`:
|
|
|
|
```
|
|
┌─────────────┐
|
|
│ Run handler │
|
|
└──────┬──────┘
|
|
│
|
|
▼
|
|
┌──────────┐ success/fail/
|
|
│ Status? │───partial_success/───▶ Done (use as-is)
|
|
└────┬─────┘ skipped
|
|
│ retry
|
|
▼
|
|
┌──────────────┐ yes ┌──────────────┐
|
|
│ Attempts │─────────▶│ Backoff + │──┐
|
|
│ remain? │ │ re-execute │ │
|
|
└──────┬───────┘ └──────────────┘ │
|
|
│ no │
|
|
▼ ┌──────────┘
|
|
┌──────────────┐ │
|
|
│allow_partial?│ │ (loops back to
|
|
└──────┬───┬───┘ │ "Run handler")
|
|
yes │ │ no │
|
|
▼ ▼
|
|
partial_ fail
|
|
success
|
|
```
|
|
|
|
Handler errors follow the same loop: retryable errors (transient infrastructure) re-execute if attempts remain; non-retryable errors (authentication, bad config) fail immediately without consuming retry attempts.
|
|
|
|
## `allow_partial`
|
|
|
|
When `allow_partial=true` and the retry loop exhausts all attempts on a `retry` status, the outcome is promoted to `partial_success` instead of `fail`. This lets the workflow continue past nodes that could not fully succeed.
|
|
|
|
| Attribute | Type | Default |
|
|
|---|---|---|
|
|
| `allow_partial` | Boolean | `false` |
|
|
|
|
```dot
|
|
implement [
|
|
label="Implement",
|
|
retry_policy="standard",
|
|
allow_partial=true,
|
|
prompt="Implement the feature."
|
|
]
|
|
```
|
|
|
|
In this example, if the agent returns `retry` and all 5 standard-policy attempts are used, the node finishes with `partial_success` rather than failing the run.
|
|
|
|
See [Retry policies](/execution/failures#retry-policies) for the available presets and backoff settings.
|
|
|
|
## `auto_status`
|
|
|
|
When `auto_status=true`, any non-`success` and non-`skipped` status is silently overridden to `success` after the handler completes. This is applied after the retry loop, so retries still happen normally — only the final outcome is overridden.
|
|
|
|
| Attribute | Type | Default |
|
|
|---|---|---|
|
|
| `auto_status` | Boolean | `false` |
|
|
|
|
```dot
|
|
scan [
|
|
label="Scan",
|
|
shape=parallelogram,
|
|
auto_status=true,
|
|
script="find . -name '*.log' | head -20"
|
|
]
|
|
```
|
|
|
|
Use `auto_status` for nodes whose failure should never block the workflow — optional scans, best-effort cleanup steps, or informational commands where the output matters more than the exit code.
|
|
|
|
## Goal gate interaction
|
|
|
|
Nodes marked with `goal_gate=true` are checked when the workflow reaches the exit node. A goal gate is satisfied if its last outcome was `success` **or** `partial_success`. Any other status (`fail`, `skipped`) causes the workflow to fail, even though execution reached the exit.
|
|
|
|
This means `allow_partial=true` on a goal gate node lets the gate pass even if the node exhausted its retries — the promoted `partial_success` counts as passing.
|
|
|
|
See [Goal gates](/execution/failures#goal-gates) for retry target resolution and failure behavior.
|
|
|
|
## Outcome in edge conditions
|
|
|
|
The four externally-visible statuses can be used in edge `condition` expressions via the `outcome` key:
|
|
|
|
```dot
|
|
gate -> deploy [label="Pass", condition="outcome=success"]
|
|
gate -> fix [label="Fix", condition="outcome=fail"]
|
|
gate -> review [label="Partial", condition="outcome=partial_success"]
|
|
gate -> skip [label="Skipped", condition="outcome=skipped"]
|
|
|
|
// Common pattern: treat partial as passing
|
|
gate -> deploy [condition="outcome=success || outcome=partial_success"]
|
|
gate -> fix [condition="outcome=fail"]
|
|
```
|
|
|
|
See [Transitions](/workflows/transitions) for the full edge selection logic and operator reference.
|