Where you are. Lesson 10 ended on the worst number this module has printed: loss 1,000 of 1,000. Alder delivered its dollars at nine in the morning, Kiri was shut mid-trade, and the yen due when Tokyo’s books opened never came; the principal now sits in a failed bank’s estate. You know the machinery that made the loss possible - two closed currency zones bridged only by nostro deposits, each leg settling on its own ledger at its own hour - and you know from module 1 that settlement is final, so the paid leg could not be pulled back. This lesson adds the cure. It is not a faster rail and not a better counterparty; it is a rule about ordering, and a small family of settlement designs that enforce it.
The cure for paying first
Sit at Alder’s desk the morning after and list the fixes. Pay later instead of earlier? Then Kiri delivers first and the exposure changes seats: the loss does not disappear, it picks the other victim. Send the instruction faster? The message was never late - the money moved exactly on schedule, and that was the problem. Buy insurance? That prices the loss without removing it. Every fix on the list keeps two settlement instants, and between two instants there is always a gap, and whoever has already settled when the gap opens is the one who loses everything. The only fix that works deletes the gap: refuse to pay first, and require the counterparty to refuse too. Both legs move together, or neither moves at all. Somebody-must-go-first feels like a law of nature. It is not. It is a property of having two commit points, and you have owned a ledger that commits many legs at once since module 1.
The idea in one paragraph
The versus family names the settlement rules that bind the two legs of an exchange into one act: payment versus payment for currency against currency, delivery versus payment for an asset against cash, delivery versus delivery for asset against asset - and free of payment, the honest name for a leg sent with no binding at all. The safe members all keep one promise, both or neither, and they keep it the way module 1’s ledger kept its invariants: every way the exchange can fail is checked before the first account edit, and only then do all the edits run, with nothing between them. There is no instant at which one leg has settled and the other has not, so there is no instant at which a failure can strand a half-trade. The exercise proves the claim the strong way: it re-runs lesson 10’s trade through an atomic settle function and injects a failure at every point on the clock, and the loss reads zero at all of them.
Check everything, then move everything
Lesson 10’s trade had two commit points: the dollar leg at minute 540, the yen leg due at minute 1140, six hundred minutes apart, and Kiri’s failure at minute 700 landed inside the gap. pvp_settle replaces the two instants with one - minute 660 in the exercise, late morning in New York. The choice of instant is arbitrary; what matters is that there is exactly one of it, agreed by both sides, at which the whole trade either happens or does not.
The body of the function is nothing but order. First the validation prelude, every way the trade can fail: if the counterparty has failed, the trade is refused whole - not one of the four account edits happens; if either desk cannot fund its own leg, a LedgerError refuses the trade before anything moves. Only when every check has passed do the edits run: two balanced postings back to back with nothing between them, dollars out of alder-fx-desk into kiri-nostro, yen out of kiri-fx-desk into alder-nostro, then assert_world() on both worlds. Module 1 split pay into submit and settle precisely so that refusal happens before movement; this is that discipline doubled - one prelude standing guard over two ledgers at once.
Wider than the screen; scroll it sideways.
Read the diagram as a reachability claim. From pending there are exactly two exits: every check passes and both legs post at the shared instant, or some check fails and the trade rolls back to untouched balances. The state lesson 10 died in - one leg posted, the other still a promise - has no arrow into it. Lesson 10’s fatal window was six hundred minutes wide; this one is zero minutes wide, because there is no longer a between for a failure to land in.
Four names, one promise
The same binding works for any pair of legs, and the family names the combinations:
| member | leg one | leg two | the binding |
|---|---|---|---|
| payment versus payment (PvP) | one currency | another currency | both or neither |
| delivery versus payment (DvP) | an asset | cash | both or neither |
| delivery versus delivery (DvD) | an asset | another asset | both or neither |
| free of payment (FoP) | an asset | none | none: the leg travels alone |
Three safe members and one honest name for the unbound case. Delivery versus delivery binds two assets swapped against each other - a bond exchanged for a bond, one piece of collateral substituted for another - with the same rule. Free of payment exists because some deliveries genuinely have no second leg: bonds moving between your own custody accounts, collateral pledged while it still belongs to you. Naming the unbound case puts the choice on the settlement instruction itself, where it can be seen and questioned; choosing FoP where money is owed is lesson 10 re-enacted on purpose, and the family gives that mistake a label so it cannot happen by accident.
Delivery versus payment is the family’s busiest member, because it guards every purchase of a security: the buyer’s cash and the seller’s asset are the two legs, and both-or-neither is the reason strangers can trade. In the exercise it is also the easy half, and the ease is the lesson. dvp_settle is one posting with four legs - cash between two deposit lines, a bond between two custody lines - and Ledger.post has applied every leg together, or raised and applied none, since module 1. On one shared ledger, atomicity is not engineered; it is inherited. The harness tries a DvP naming a missing account and all four legs void together, balances exactly as before. Module 4 builds custody properly; today the bond only needs to be on the ledger.
The proof is a sweep
A both-or-neither claim should not rest on one lucky timeline, so the exercise refuses to test just one. The harness sweeps a failure across the whole clock - minutes 0, 300, 540, 660, 700, 900 and 1439 - and re-runs the trade with Kiri dying at each. Every failure at or before the settlement instant lands in the prelude: refused whole. Every failure after it finds the trade already complete and final: settled whole. After each run, two asserts do the real work. The first is the invariant itself - the dollars moved if and only if the yen moved, no state where one leg settled alone. The second prices the outcome: dollars paid minus yen received, converted at the trade’s rate, must equal zero. Seven failure points, seven zeros:
failure at minute 660: refused whole - loss 0
failure at minute 700: settled whole - loss 0 (lesson 10 lost the principal here)
One honesty note, before the sweep looks like a free lunch. Refused whole is not the same as unharmed: Alder still wants its yen, and re-trading tomorrow may cost a worse rate than the one that died. But that is a price-sized risk, the kind lesson 7 taught you to measure inside the spread, not a principal-sized one. The versus family does not make counterparty failure painless; it caps the damage at the size of a re-trade instead of the size of the payment.
Check yourself
1. Move the counterparty check between the two postings and re-run the sweep. Which minutes now fail, and what state has the function produced?
The dollar posting runs, then the check refuses: dollars sit in kiri-nostro while alder-nostro holds no yen - one leg settled alone, lesson 10’s torn state rebuilt inside the function meant to abolish it. Every refused minute, 0 through 660, now trips the both-or-neither assert; the settled minutes still pass, which is what makes the bug nasty: it hides in exactly the failure cases. Order is the entire guarantee - every check before the first edit, module 1’s check-then-apply contract stretched across two ledgers.
2. Failures at minutes 660 and 700 land on opposite sides of the sweep. What state is each trade left in, and why is the loss zero both times?
At 660 the counterparty is dead at the settlement instant, and the prelude counts that as before: refused whole, all four accounts untouched, Alder keeps its dollars. At 700 the trade settled whole forty minutes earlier, and finality means Kiri’s failure cannot reach back into settled money: the yen are already Alder’s. Refused-whole keeps the principal, settled-whole delivers the counter-value; both are complete states. The loss measures the gap between paying and being paid, and the gap never opens.
3. dvp_settle is a single four-leg posting while pvp_settle needs a guarded prelude and two postings. What does the shared ledger give DvP for free, and what does its absence cost PvP?
Atomicity in the write path. One Ledger.post applies every leg together or raises and applies none - module 1’s contract - so the cash and the bond move in the same commit because one book holds both. No book holds both the dollars and the yen, so PvP must manufacture what DvP inherits: a prelude that pre-checks every failure, and a vantage point that can see both ledgers at the same instant. The exercise fakes the vantage point with one Python process; the real world has to build an institution.
4. Free of payment is the family member with no second leg. Why does the family keep it, and when does choosing it re-enact lesson 10?
Because some deliveries genuinely have no counter-leg: securities moving between your own accounts, collateral pledged while it still belongs to you. Naming the unbound case puts the choice on the instruction itself, visible and questionable. The danger is choosing it when money is owed: an FoP delivery against a promised payment is paying first with a label on it, and if the payment never comes the loss is the whole delivery - lesson 10’s principal risk, selected by picking the wrong word from the family.
Do this
Twenty minutes, from module-03-across-borders. Open code/versus_family.py. build_zones is lesson 10’s two closed worlds verbatim - the same stylised trade, 1,000 dollars for 150,000 yen - and the DvP half is already written: dvp_settle, its custody bank, and the refusal test. Your work is the body of pvp_settle, and the whole trick is order. First the prelude: if the counterparty has failed, return False - refused whole; then raise LedgerError if alder-fx-desk cannot fund the dollar leg, and again if kiri-fx-desk cannot fund the yen leg. Only then the four edits: two balanced postings back to back with nothing between them, assert_world() on both worlds, return True.
python3 code/versus_family.py
Green is seven sweep lines - four refused whole, three settled whole, minute 700 carrying its lesson 10 note - then the DvP assertions, ending with the final line verbatim:
the versus family keeps one promise: both legs at one instant or neither leg at all - and the Herstatt loss is zero at every failure point
If the both-or-neither assert fires on the early minutes, an edit ran before a check: you have rebuilt lesson 10’s torn state inside the cure, exactly question 1’s bug. If every line prints refused whole, pvp_settle never reports success - return True after the postings, or the sweep’s last assert will insist on seeing both sides of the instant. The completed version is solutions/versus_family.py; compare after you are green.
What you can now do. You can name the four members of the versus family, and state the one promise its safe members keep: both legs at one instant, or neither leg at all. You can implement the family’s core move - a settle function whose checks all run before its first edit, so its reachable states are exactly refused-whole and settled-whole - and prove it the strongest way this course knows: exhaustive failure injection, loss zero at every point on the clock, including the minute that cost lesson 10 the full principal. And you can say precisely what your proof assumed: one process that sees both ledgers at once, an omniscience no pair of real banks has. Manufacturing that place, at the scale of the world’s currency trade, is the next lesson.