-
concept
Effect Discipline
Hook
the precondition under "discard is cheaper than repairing"
Thesis
Effect discipline classifies every dispatch by which recovery moves its effects leave legal, discard, retry, or compensate; re-dispatch treats discarding a bad run as free, and that is only true if the run had no external side effects.
Laws & fences
- The classes are properties that license moves: pure / read-only and isolated make discard free, idempotent makes retry free while the effect stays in the world, reversible-at-a-cost means compensate then re-dispatch, and irreversible licenses nothing after the fact and gets a gate before the effect.
- The compensation's cost is a property of how contained the effect's footprint is, not of the effect's type; discard is not all-or-nothing, and its unit is the seam.
- Discarding a run means discarding its work, the declared deliverable included, so intended effects get no exemption and must still be staged or overwritable.
- Shared accumulating state drifts toward irreversible, so validation moves before the landing: a discardable dispatch proposes the entry and the validated side promotes it.
When to reach
- Reach for it before a dispatch, because which recovery move you are counting on is picked before the dispatch, not after the return, and the guarantee that move demands has to be in place before the effect lands.
- Skip it for mechanics; git, worktrees, and staging layouts are instances of a guarantee, not the guarantee, and the strategy for achieving isolation is owned by staged-effects.
-
The Contract
-
Foundations
-
Statelessness
-
The Unsent Thunderstorm
Effect discipline is the classification of every dispatch by which recovery moves its effects leave legal. Two things fix the reading: the guarantees you build into the dispatch, and — where an effect lands raw — what path back the world offers. The moves being licensed are discard, retry, and compensate; the classes below are the vocabulary for saying which of them a given dispatch still has.
Re-dispatch (../../verification/validated-seam-redispatch.md) treats discarding
a bad run as free. That is only true if the run had no external side
effects. If the dispatched actor wrote files, called an API, sent a message,
or committed something before producing its off-spec return, the world already
changed — you cannot discard the run, only the text it returned. The
keystone's most novel claim silently requires a discipline of its own.
The classes — properties that license moves
Classify every dispatch by which recovery moves its effects leave legal. The classes are properties that license moves:
Engineered guarantees — properties you build into the dispatch:
- Pure / read-only — the dispatch observes and reports. Discard is free;
nothing landed. (An effectful job can still yield a pure dispatch — the
describe-then-execute route of
../../control-flow/staged-effects.md.) - Idempotent — re-running converges to the same world state (provision-if-absent; the guard rides the load). Retry is free — note this protects the retry, not the discard: the effect stays in the world.
- Isolated — effects land in a staging surface and merge only after
validation. Discard is free — the world never learns the run happened.
Strategy node:
../../control-flow/staged-effects.md.
The guarantees compose: an idempotent write inside an isolated sandbox is fully free — both discard and retry legal.
What the world offers — when an effect lands raw, with no engineered guarantee, the question becomes what path back exists:
- Reversible-at-a-cost — a compensating action exists: delete the stray file, revert the commit, send the correction. Stays on the re-dispatch side: discard is still legal, it just carries the compensation's price tag.
- Irreversible — no path back at all. The class that cannot be
disciplined away; it gets a gate
(
../../control-flow/human-in-the-loop-gate.md) before the effect, not validation after.
The licensing table
| Property | Recovery move it licenses |
|---|---|
| Pure / read-only | Discard free — nothing landed |
| Idempotent | Retry free — the effect stays; discard doesn't erase |
| Isolated | Discard free — staged, never promoted |
| Reversible-at-a-cost | Compensate, then re-dispatch clean |
| Irreversible | None after the fact — confirm before (the gate) |
The seam prices the discard
Reversible-at-a-cost is really reversible at the seam. The compensation's cost is not a property of the effect's type (file write vs. API call) but of how contained its footprint is. A part that fails to integrate does not force unwinding the whole world: repair the mount point, re-dispatch the part. Discard is not all-or-nothing — its unit is the seam. The chain back to the keystone: the contract defines the seam → the seam bounds the blast radius → the blast radius prices the discard. Effects that land at a contracted seam are cheaply compensable almost by construction.
The discard law
Discarding a run means discarding its work — including the declared deliverable. If you throw away an agent, you throw away their work: you do not build on a foundation laid by a run you rejected. So intended effects (the artifact that was the whole point — the config, the release artifact, the context envelope) get no exemption from the discipline: they must still be staged or overwritable so that throwing them away stays possible. Declaration at the seam tells you where the effect landed; the discipline keeps walking away from it legal. The economics underneath: the cost of repair usually exceeds the cost of production — unwinding-instead-of-discarding is a losing default, and "be tactical in how you dispatch" is the designer's lever.
Shared accumulating state
The hard case: state many runs append to (a memory file, a decision log). A discarded run's entry is interleaved with entries you keep; overwrite destroys others' work, and unwinding a common file is messy — this class drifts toward irreversible (version control is a compensator, not a solution). The discipline's answer is to move validation before the landing: a discardable dispatch proposes the entry; the validated side promotes it. Same shape as the isolated class, same shape as the gate — for shared state, effect-first-validate-later is simply the wrong order.
The classes are not a ladder (there is no single ordering axis) and not a partition (a dispatch can hold several at once). They are read for the move they license, never for rank.
The model does not price the compensation, either. Reversible-at-a-cost is one bucket; no finer gradations of cost inside it — the only fine structure it carries is the seam's, not the effect type's.
Nor does the discipline claim every effect can be made recoverable. Irreversible is the class that cannot be disciplined away, which is why its answer is a confirmation placed before the effect rather than any move licensed after it.
And the jurisdiction is classes, seams, and recovery moves — not mechanics.
Git, worktrees, and staging layouts are instances of a guarantee, not the
guarantee; the strategy for achieving isolation is owned by
../../control-flow/staged-effects.md.
Adopting the classes moves one decision earlier: which recovery move you are counting on is picked before the dispatch, not after the return. That is also where the discipline is cheap — you mostly need to know which move you're counting on before you dispatch, and the guarantee that move demands (staging, idempotence, a gate) has to be in place before the effect lands.
The trade: staging infrastructure and the discipline of classifying effects at all — in exchange for keeping discard-and-re-run legal, which is what makes probabilistic components cheap to recover.
The classification was being applied before it was named. Already used
unnamed: config-as-bootstrap's free idempotent setup
(../../persistence/config-as-bootstrap.md) is the idempotent class in disguise
— a pattern that reached for the property, and drew its cheapness from it,
with no word for what it had. The second checkable item is the mapping onto
../../control-flow/staged-effects.md's two routes (class mapping ruled
2026-07-11): each engineered class names the route that produces it.
The Unsent Thunderstorm carries one invalid bulletin payload through all five classes. Its baseline and five single-decision shifts keep discard, retry, compensation, and a pre-effect gate distinct in an executable fixture; the revised explanation passed clarity review on 2026-08-07.
- Precondition of
../the-contract-keystone/the-contract-keystone.md(third premise: the contract makes checking possible, the asymmetry makes it affordable, effect discipline makes the recovery move legal) and of../../verification/validated-seam-redispatch.md. - Operationalized by
../../control-flow/staged-effects.md— one strategy, two routes (class mapping ruled 2026-07-11): sandbox-then-merge engineers the isolated class; describe-then-execute engineers the pure class for an effectful job. - The irreversible class is what the human-in-the-loop gate
(
../../control-flow/human-in-the-loop-gate.md) guards; the plan leg of staged-effects is what the gate inspects. - Durable state (
../../persistence/durable-state.md): a state file is a declared deliverable — and per the discard law it still owes the discipline; the shared-accumulating-state rule above is the interaction. - Supplies the cost-of-error input to the contract census's
verification-weight reading (
../contract-documentation/contract-documentation.md).
Idempotence and transaction classification, with the Saga (Garcia-Molina & Salem, 1987) behind "compensate": an effect reversible only at a cost is a compensating transaction, not a rollback.
The relationships ledger
Evidence-bearing references
Relationships
Every connection keeps the section where it was found. The map above orients; this ledger carries the evidence.
Outbound references 1
-
in-slice · occurrence 1
The Unsent Thunderstorm
one rejected weather bulletin shows when to discard, retry, undo, or stop before acting
Evidence: Evidence · occurrence 1
Inbound references 6
-
in-slice · occurrence 3
The Contract
the precondition under "discard is cheaper than repairing"
Evidence: Model and claims · occurrence 3
-
in-slice · occurrence 3
The Contract
the precondition under "discard is cheaper than repairing"
Evidence: Relationships · occurrence 3
-
in-slice · occurrence 8
Foundations
the precondition under "discard is cheaper than repairing"
Evidence: Model and claims · occurrence 8
-
in-slice · occurrence 6
Foundations
the precondition under "discard is cheaper than repairing"
Evidence: Relationships · occurrence 6
-
in-slice · occurrence 6
Statelessness
the precondition under "discard is cheaper than repairing"
Evidence: Implications · occurrence 6
-
in-slice · occurrence 1
Statelessness
the precondition under "discard is cheaper than repairing"
Evidence: Relationships · occurrence 1
↑ back to the top ← the survey
Node effect-discipline · corpus 31de4cb · Catalog revision 35263c4c415da742953d0462804fb14424e2244dae4c63efd27e468988de70ab