Repository navigation
ADR 0020 Declared compensation
Pavel Ravvich edited this page Oct 22, 2026
·
2 revisions
- Status: Accepted (replaces the rollback bullet of ADR-0019)
- Issue: #339 (the contract and the checks), #340 (the automatic undo)
ADR-0019 made rollback explicit: .onError(Err, toAction(UndoAction)…), no automatic
compensation, no compensate metadata. That keeps every undo reviewed, typed and tested — but it
leaves three gaps:
- Nothing ties an action to its undo, so a new
.onErrorside path or an early failure finish added later can skip an undo silently — the external system (an ATS, a calendar, a payment) keeps a dangling record.agboss checkandagboss describe --jsoncannot see which action undoes which. - Some stops have no path at all:
app.cancel, an uncaught step failure, an uncaught limit, aFailFastsibling child. No side path can be written for them. - A failed join drops its finished branches' values, so an
.onJoinErrorside path cannot undo a finished sibling by hand.
- An
@Actiondeclares its undo:@Action({ compensateWith: UndoAction, committedBy?: CommitAction }). The undo is an ordinary@Action(code, never a model call), not undone itself (no chains), and reads only what the path holds right after the action.committedBynames the action after which nothing undoes it; without it, a finish commits it. -
Explicit where a path can say it: an
.onError/.onJoinErrorside path after an open undoable action that ends at a finish must run its undo actions, newest first — checked at assembly ([flow.uncompensated-action],[flow.compensation-out-of-order]); withcommittedBy, every path from the action runs the committer or the undo ([flow.uncommitted-action], an error: leavingcommittedByout says "the finish commits"). -
Automatic only where no path can say it (#340): the execution ends without a finish — a
cancel, an uncaught failure or limit, an aborted child — or a join fails after some branches
finished. Then the framework runs the open actions' undo actions itself, newest first, each
bounded by
compensationTimeout; a failing undo does not stop the rest, and the execution fails withCompensationFailedError(the original error ascause). - A child workflow is the unit of work: its finish commits its own actions; an aborted child undoes its open ones before its error reaches the parent.
- Rule groups
action.*andflow.*; nosaga.*, no public name with "saga".
- Easier: an undo is declared once, next to the action, and every side path is proven to run it;
agboss describeshowscompensateWith … · committedBy …per action; a cancel or an uncaught failure no longer leaves side effects behind (#340); an undo interrupted by a stop, a crash or a lost lease is finished by the instance that takes the tree over, the undos done skipped (#340 PR 4: the reserved tree keys@agboss/unwinding,@agboss/compensated/<key>). - Harder: one more contract to keep — an undo must be safe to run twice (it gets an idempotency
key; a failed or interrupted undo runs again on the next holder) and read only what was on the
path right after its action. A root's record is written only after its undo ended, and a cancel
that ran the undo itself rejects with
CompensationFailedErrorwhen an undo failed. - Out of scope: the side effects of an agent's tool calls (agents get no
compensateWith), and quorums (they launch agents only). - Rejected: metadata only, without an automatic undo (leaves cancels and uncaught failures with side effects); an automatic undo everywhere (implicit, two ways to say one thing); records moving up to the root (a parent's side path would undo actions whose inputs are not in its scope).
AGBoss
- Home
- Delivery Pipeline
- Architecture
- Configuration
- Environments
- Workflow — the paths
- Path scope
- Workflow as a step
- Parallel — quorums and arbiters
- Routing patterns
- Rollback — declared compensation
- Routers
- Guards
- CLI — agboss
- App — @Application and createApp
- Several instances
- Execution history
- Mesh Hub — agboss hub
- Health checks
- Context and Authorization
- Testing
- The test split
- Suites and Comparisons
- Eval suites — @EvalSuite
- Components
- Naming
- Standard DTOs
- Examples: job-scout, flow-patterns
- Agents — the loop
- Model providers
- Tools
- Knowledge bases (RAG)
- A2A — agent to agent
- FinOps
- Tracing
- Observability
- Terns and evaluation
- Profiles and comparisons
- Pauses — pending, resume by id
- Pause seam
- Decisions (ADR)