The Settlement Journal
Balanced-entry money movement in integer micro-units — zero-sum enforced by the database, append-only by construction, reversible only by compensation.
Most systems treat money integrity as a convention: the code is careful, the tests are good, and everyone hopes. The settlement journal makes it a property of the storage itself. Every committed transaction is a set of balanced entries in integer micro-units that nets to zero per currency — and the database refuses, at commit time, any transaction that does not.
debitbuyer · acme-57 250 000creditworker · closer-oak+54 387 500creditplatform · fee+2 862 500netevery committed transaction balances0reversewarranty · work failed review · day 14entries mirroredThe model
Classic double-entry, tenant-scoped, in int64 micros (1,000,000 µ = 1 unit;
floats never appear):
Prop
Type
Three layers of enforcement
The posting engine cannot express an imbalance. Pure constructors build each transaction's legs from the settlement event; a transaction that fails zero-sum validation never leaves the domain layer. Zero legs are omitted, not zero-valued.
The database enforces it again at commit. Deferred constraint triggers on both the transaction header and the entries reject an unbalanced set, a single-legged transaction, and the empty-transaction hole — even against a future writer that bypasses the Go engine entirely. Composite foreign keys make a cross-tenant or cross-currency entry structurally impossible, and row-level security is forced, so even the table owner cannot read across tenants.
Append-only, forever. Update and delete are rejected by trigger on transactions, entries, and idempotency claims. There is no correction — only a new compensating transaction: a release reverses a hold, a claw-back reverses a commit, and the ledger's history is the audit trail.
Posting rules
A settlement moves through states, and each transition posts one balanced transaction. Reversal is never an edit — it is a new compensating posting:
One capture of a single unit of work, as the entries actually land — the sum is what the database checks at commit:
| Leg | Direction | Micros |
|---|---|---|
| Buyer wallet | debit | −57 250 000 |
| Worker payable | credit | +54 387 500 |
| Platform fee | credit | +2 862 500 |
| Net per currency | 0 |
Each settlement event posts one balanced transaction:
pending → heldReserve the gross from the buyer's wallet into held funds when a winner is committed with a hold.
held → committedDrain held funds into the seller's payable and the platform fee. Guarded by a versioned state transition — a capture and a release racing for the same hold produce exactly one winner.
chargeThe single-step charge path, keyed per unit of work and party — a decision that charges two recipients produces two independent settlements, never a collision.
warranty returnA Warranty return posts the reversing entries and stamps the settlement reversed — once. A second reversal attempt is a typed state error, not a double refund.
Idempotency with teeth
Every posting carries a key derived from the event's stable identity — never a per-call UUID — plus a fingerprint of its economic content. A replay converges on the original transaction. A reused key whose fingerprint differs — same event id, different money — fails loudly as a conflict. And the tenant-context guard means a caller that forgets its tenant scope gets an error, not a silent no-op against an invisible row.
Rolling out beside the ledger
The journal does not replace the existing ledger — it co-writes beside it, atomically. With the settlement flag on, a charge writes its legacy ledger row and its balanced journal transaction in one database transaction: both commit or neither does. Data the journal cannot faithfully express — an amount that rounds to zero micros, a malformed currency — skips the journal with a logged reason and never fails the charge. Reconciliation compares specific account movements against the ledger, transaction by transaction, before anything reads from the journal as truth.
Committed journal transactions flow into the work's Receipt as settlement evidence — linked after commit, best-effort, converging on retries — so what moved and what was proven reference each other without either being able to corrupt the other.
Off by default behind settlement.journal_enabled, with per-tenant
enablement for staged rollout. The flag gates only the co-write — flag-off
behavior is byte-identical to the pre-journal system.
Where to go deeper
Commerce & pricing
Per-recipient pricing and budgets, returns with credits, and compliance reporting over routed decisions.
Stripe integration & invoicing
The money-movement layer — the always-on billing summary that points at the Stripe portal, plus the experimental recipient-wallet plugin and metered-usage invoicing worker.