Skip to main content
The ledger is the record of effect: which accounts an action moved money between, and by how much. It is double-entry, append-only, and balanced by construction. Where the journal says “a $5,000 payment was recorded”, the ledger says “$5,000 left Cash and $5,000 came off Indemnity Payable”.

What a Ledger Row Carries

The leg is audit vocabulary and nothing more. It carries no behavior: it is there so a batch of rows can be read back and understood without reconstructing which recipe produced it. A reversal row keeps the leg name of the row it negates — what makes it a reversal is its action type, never its leg.

Every Action Appends One Balanced Batch

An action does not append rows one at a time. It produces a batch, and the batch is checked as a unit before anything is written:

It Balances at Every Date

The amounts sum to exactly zero — and they do so per effective date. A batch spanning two dates must balance at each of them independently, not just overall.

No Zero Rows

Every amount is a nonzero whole number of cents. A row that would post nothing is dropped before the batch is assembled, not written and ignored.

Every Account Resolves

Every account posted to must exist and belong to this company. There is no such thing as an account that exists but cannot be posted to.

Every Row Names Its Action

Each row is stamped with the journal row the batch was assembled for. A row that names a different action fails the batch.
If any of these fails, nothing commits — not the ledger rows, not the journal row, not the projection. The whole action is refused as an internal error, because a batch that does not balance is a bug in the engine, never something a user typed.
An empty batch is legal, and normal. Re-linking an invoice to a different event, approving one, or voiding one that had nothing posted all append a journal row and no ledger rows at all — the act is recorded, but no money moved.

Signs, Concretely

Direction — whether money is flowing into or out of the business — is never carried by the sign of a ledger amount. The sign carries debit or credit, in the ordinary accounting sense. Which way money is actually moving is only interpretable once you also know whether the account being posted to is debit-normal or credit-normal: So a positive amount is a credit either way, but a credit to Cash means money left the business, while a credit to a Payable means the business now owes more. The same sign, opposite stories — the account is what disambiguates them.
This is why the balancing invariant works at all. Every action’s rows sum to zero, and yet each row means something different, because the meaning lives in the pairing of sign and account, not in the sign alone.
An expense invoice of $800 for legal fees on an Operating type posts two rows: They sum to zero. Paying it posts the opposite side of the liability against Cash.
This sign convention is internal to the ledger, and is not the convention on screen or in exports. Screens show unsigned magnitudes with direction in color; exports take a sign from the configured reference frame. See Reference Frames.

Effective Date Is Not Entry Date

Every row carries both:
  • Effective date — the accounting date. On an invoice’s postings this is its invoice date; on a payment, the payment date.
  • Created at — when the row was actually written, taken from the action.
These are independent on purpose, and that independence buys three distinct things.

Backdating

Recording a March payment in April posts it effective in March, where it belongs, while the audit trail still shows it was entered in April.

Future Dating

A row can be posted with an effective date that has not arrived yet.

Point-in-Time Reads

Because every row is dated and none is ever amended, the books can be read as they stood on any date.

Future Dating

Money can be recorded before it influences the books. An invoice raised now to collect policy premium on the first of next month posts effective on that date: it is a real record from the moment it is entered, visible and auditable, but it does not appear in this period’s figures. This is what makes scheduled and anticipated money expressible without a separate “pending” concept. There is one kind of record, and its effective date decides when it counts.

Point-in-Time Reads

Nothing in the truth tier is ever amended or removed, and every row carries the date it is effective for. Together those two properties make a question like “what did Financials look like on 31 December?” answerable exactly: read every ledger row effective on or before that date and ignore the rest. A correction entered in February does not retroactively change what December looked like — it is a new row with its own effective date. Whether it lands in December or February is a property of that date, and the reconstruction respects it either way.
This is only true because the ledger is append-only. A model that updated rows in place could report today’s balances, but could never reliably reproduce yesterday’s — the old values would be gone.

Date Corrections Need No Special Case

Changing an invoice’s date does not rewrite the old rows: the postings are reversed at the old date and reposted at the new one, because the effective date is part of what identifies a posting. Both dates balance independently, and a point-in-time read of either date stays correct.

Integer Cents, One Book

Every amount is a whole number of cents, in a single book. No figure in Financials is ever a floating-point number at any point in its life, so no total ever drifts by a penny and no rounding rule has to be agreed on. A batch either sums to zero exactly or it is rejected.