Kuatia provides double-entry-style safety using a UTXO-style model. Value is held as signed postings, and every committed transfer must satisfy per-asset conservation. The accounting goal is the same as classical bookkeeping; the mechanical model is different:
| Classical double-entry | Kuatia |
|---|---|
Σ debits = Σ credits |
sum(consumed) == sum(created) per asset |
This page maps classical accounting vocabulary onto Kuatia's types and clears up the terms that are easy to conflate.
The most important correction: in classical accounting a journal is the
append-only book of original entry, while a journal entry is one committed
accounting event. In Kuatia, the closest equivalent to the classical journal
is the transfer log; the closest equivalent to a journal entry is a committed
Transfer/Envelope. Kuatia's Book is neither. It is a transfer policy
scope, not the accounting journal.
| Classical accounting | Kuatia | Notes |
|---|---|---|
| Journal (book of original entry) | Transfer log, TransferStore of EnvelopeRecords |
Append-only, ordered source of truth for committed transfers. |
| Journal entry (one balanced event) | Committed Transfer (intent) → Envelope (resolved) |
One atomic accounting event. |
| Compound journal entry | Transfer with multiple Movements |
One event touching many accounts/assets. |
| Entry line / leg | Posting effect (often derived from a Movement) |
A concrete account-level value fragment. A Movement is two-sided intent {from, to, asset, amount} that resolves into consumed/created postings, not a 1:1 debit/credit line. |
| Σ debits = Σ credits | Per-asset conservation sum(consumed) == sum(created) |
Enforced in validate_and_plan; ConservationViolation otherwise. |
| Ledger (accounts + running balances) | Accounts + active postings | Balances are projections over Active postings, never stored. |
| Posting a transaction (the verb) | resolve + commit (Transfer → Envelope → apply) |
Confusing collision: in Kuatia a posting is a noun (a value fragment), not the act of recording. |
| Accounting book | no direct equivalent unless modeled separately | Kuatia Book is not this. |
| Transfer policy scope | Book |
Gates which accounts/assets may participate. See below. |
A journal entry is one committed accounting event. In many accounting texts this event is also called a transaction, a word that is overloaded in a ledger library (database transaction, business transaction, atomic transfer), so this doc prefers "committed accounting event."
Double-entry entries are inherently multi-account; that is the entire point. A minimal entry has two legs; a compound entry has more. So a Kuatia transfer touching many accounts is not a mismatch. It is a (compound) journal entry.
Classical compound journal entry:
2026-06-26 Cash sale of goods
Dr Cash ................. 115
Cr Revenue .......... 100
Cr Sales tax payable . 15
The equivalent business effects as a Kuatia transfer, multiple movements committed atomically:
let transfer = TransferBuilder::new()
.book(sales_book)
.pay(customer, revenue, usd, Cent::from(100))
.pay(customer, tax_payable, usd, Cent::from(15))
.build();
// One Transfer → one Envelope → one EnvelopeRecord in the transfer log.
Note: this is not a literal debit/credit translation. It shows the business effects as movements. In a production POS model, cash, revenue, and tax might be separate effects routed through system/offset accounts. (A literal multi-hop
customer → cash → revenuechain inside one transfer would require spending a posting created earlier in the same envelope, which the resolver does not do; it selects from already-committed postings.)
Both are a single balanced event. In the classical entry, Σ Dr (115) = Σ Cr
(115). In Kuatia, the resolved Envelope satisfies per-asset conservation:
sum(consumed) == sum(created) for USD.
Transfer/Envelope vs the transfer logThese differ in grain: one record vs. the collection of all records.
Transfer / Envelope = one record (one journal entry).
Transfer is the intent: { movements: Vec<Movement>, book, user_data,
metadata }. Callers express what should happen, not which postings.Envelope is the resolved form produced by resolve(): { consumes:
Vec<PostingId>, creates: Vec<NewPosting>, account_snapshots, book, … }.
It names the concrete postings to spend and create.commit / commit_envelope) returns a Receipt {
transfer_id } identifying the committed envelope, the EnvelopeId, which
is content-addressed (the double-SHA-256 of the canonical envelope bytes).TransferStore as EnvelopeRecord {
envelope, receipt, created_at }. Each transfer is one entry in it.Transfer/Envelope : transfer log :: one journal entry : the journal.
"The system is trivially auditable by replaying the transfer log" means:
re-apply every EnvelopeRecord in order and you reconstruct all balances.
There is no stored balance that can drift.
Kuatia keeps two distinct append-only sequences. Only the first is the accounting journal.
| Log | Type | Records | Role |
|---|---|---|---|
| Transfer log | TransferStore → EnvelopeRecord |
Full posting-level detail of each committed transfer | The accounting journal, the source of truth for balances. |
| Event log | EventStore → LedgerEvent |
High-level lifecycle notifications | Projections / subscribers; not the journal. |
LedgerEvent { seq, timestamp, kind } carries a monotonic seq and a kind
of TransferCommitted | AccountCreated | AccountFrozen | AccountUnfrozen |
AccountClosed. It tells you that something happened; the transfer log tells
you exactly which postings moved.
Classical ledgers post an entry by mutating each account's running balance. Kuatia is UTXO-style and posting-based, so the mechanism differs while the event grain is identical. Because postings are signed, debit/credit is not the native primitive; resolution works in terms of consuming and creating postings:
Active
postings from the source account, creating a change posting if the selected
postings exceed the amount.Active postings, computed on
demand, never stored.So an entry line maps to a Posting effect, usually derived from a Movement
(two-sided intent) that resolves into one or more postings (a created posting,
consumed postings, and possibly change). The balancing rule is unchanged: per
asset, sum(consumed) == sum(created).
Book fits (and doesn't)Book is the one Kuatia concept with no classical counterpart. It is a
transfer policy scope: it gates which accounts and assets may participate in a
transfer (BookPolicy { allowed_assets, allowed_flags, allowed_accounts }).
It is explicitly not:
Transfer/Envelope),Despite the name, a Kuatia
Bookmust not be confused with an accounting book. The accounting journal is the transfer log;Bookis purely a policy scope.
See the glossary for the Book model and worked examples.
| Classical accounting | Kuatia | Notes |
|---|---|---|
| Journal | Transfer log / TransferStore<EnvelopeRecord> |
Append-only source of truth for committed transfers. |
| Journal entry | Committed Transfer / Envelope |
One atomic accounting event. |
| Entry line / leg | Posting effect |
A concrete account-level value fragment; movements are intent that resolve into postings. |
| Compound journal entry | Transfer with multiple movements |
One event touching many accounts/assets. |
| Σ debits = Σ credits | Per-asset conservation | sum(consumed) == sum(created) per asset. |
| Ledger | Accounts + active postings | Balances are projections over active postings. |
| Posting a transaction (verb) | Resolve + commit | Avoid confusion: Kuatia Posting is a noun. |
| Accounting book | No direct equivalent unless modeled separately | Kuatia Book is not this. |
| Transfer policy scope | Book |
Gates allowed accounts/assets. |
| Proof a txn was recorded | Receipt { transfer_id } |
Content-addressed EnvelopeId. |
| Lifecycle notifications | Event log (LedgerEvent) |
Separate from the transfer log. |
In one line: Kuatia's transfer log is the accounting journal; each committed
envelope is a journal entry; Kuatia's Book is a policy scope, not a journal
or a balance partition.