Skip to main content
Quiz · 12 questions · ~15 minutes Commit to an answer before opening each one. Several questions have a confident-sounding wrong answer written into the options: those are the questions worth getting wrong now rather than in an interview.
Scoring: 10–12 you can defend the ledger design. 7–9 solid, revisit the ones you missed. Below 7 re-read the ledger before the question bank.

No. assertBalanced requires at least two entries: one entry can never balance.It is the first of three checks, before positivity and before per-currency balance, because it is the cheapest and most fundamental.
No. Balance is computed per currency, independently. EUR has a debit of 100.00 and no credit; USDC has a credit of 108.00 and no debit. Both currencies fail.The plausible wrong answer is “yes, if the rate is right”, and that is exactly the reasoning the design rejects. Offsetting across currencies means adding quantities of different things, and no rate makes that an identity at the moment of posting.A conversion needs four legs, bridged by the FX position accounts.
There is none. Debits equal credits exactly, per currency.This is why money is an integer count of minor units. With floats an epsilon would be unavoidable, and a ledger with an epsilon is not a ledger: “how far off is acceptable?” has no defensible answer and the drift grows with volume.
No: opposite. It raises the asset and lowers the liability.Debits increase assets and expenses; credits increase liabilities, equity and revenue. entrySign() reads the NORMAL_BALANCE table and returns +1n or -1n accordingly.That table exists in exactly one place. Duplicated, the copies eventually disagree and the ledger silently mis-signs balances.
Post a reversing journal, then post the correct one. Never edit, never delete.A BEFORE UPDATE OR DELETE trigger enforces this at the database level: ledger_entry is append-only: post a reversing journal instead.The record of what happened stays separate from the record of what was meant to happen, which is the whole content of an audit trail.
€750. available = posted − reserved, where reserved is the sum of active holds only: released and captured holds do not count.Showing them posted would let them spend money already committed elsewhere.
Nothing. Validation is complete before anything is written.The order is deliberate: balance (pure, no I/O), then account resolution, then overdraft. A rejection leaves no trace: there is no path that writes some entries and then discovers a problem.The property test for this is “rejection is total”: entry count is identical before and after.
Because it is how far below zero an account may go, expressed as a non-positive value. Zero means never overdrawn; a negative value models an intraday credit line.A positive floor would mean an account cannot go below a positive balance, which is a different concept entirely. CHECK (overdraft_floor <= 0) enforces it.Customer accounts are 0. So is liability.in_transit: driving it negative would mean paying out money nobody put in.
No, twice over. The append-only trigger blocks the UPDATE outright. And even via valid inserts, the balance constraint trigger is DEFERRABLE INITIALLY DEFERRED: it runs at COMMIT, so a transaction leaving any journal unbalanced in any currency cannot commit.This is deliberate duplication with the application check. An invariant depending on every future developer using the right class is a convention, and conventions erode.
To revenue.rounding.EUR, as its own entry.divRound returns the rounded value under an explicit mode; divResidual returns the exact leftover so it can be posted. The journal balances and the residual becomes a queryable number.The plausible wrong answer is “it rounds away”, which is an unrecorded transfer of value, executing continuously, that nobody wrote down as policy.
Exactly where they started. Every touched account, to the minor unit.Two properties: if J balances, its reversal balances: flipping every direction preserves the equality. And reverseEntries is an involution: reversing twice returns the original. Both are in the property suite.This is why compensation is safe by construction rather than by careful coding, which matters because the unwind path runs when something has already gone wrong.
No, and this is the most important answer here.Reversals commute, because addition commutes. The final balances are identical either way. Every assertion about balance passes.What breaks is the audit trail: a journal labelled “reverse reserve” containing the settlement entries. A balanced ledger describing something that did not happen.This was found by mutation testing: forward order passed all sixteen tests. Two tests on reversal order and account pairing were added. Balance is necessary but not sufficient. The scenario.

Settlement quiz

Twelve more, on the saga, rails and chains.

Back to the ledger

For anything above that did not land.