Cesar Rodas ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 2 semanas atrás
..
0001-modified-utxo-signed-postings.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0002-saga-commit-pipeline.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0003-dumb-storage-saga-recovery.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0004-account-policies-overdraft-model.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0005-intent-api-movements-vs-envelopes.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0006-reservation-protocol-posting-lifecycle.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0007-reversal-via-compensating-transfers.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0008-conformance-tested-storage.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0009-monetary-representation-integer-minor-units.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0010-event-stream-vs-transfer-log.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
0011-swappable-money-backing.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
README.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás
template.md ee2e0e2b12 Introduce Kuatia, an append-only, auditable multi-asset ledger há 3 dias atrás

README.md

Architecture Decision Records

Significant, hard-to-reverse design decisions for Kuatia, captured so the why survives. New ADRs follow template.md (MADR-style: context → drivers → considered options with pros/cons → decision outcome → consequences → links). Numbering is sequential; an ADR is never edited to reverse a decision. Instead, a new ADR supersedes it.

Index

ADR Title Status Summary
0001 Modified UTXO: value as signed postings accepted Value is signed postings (negative = "offset positions"), not mutable balances; conservation is structural; balances are projections.
0002 Saga commit pipeline accepted Commit is a compensating saga (reserve → finalize), not a single/distributed transaction: composable, coordinator-free, crash-recoverable.
0003 Dumb storage + durable saga recovery accepted Storage returns affected-row counts and makes no decisions; the saga owns interpretation/idempotency; crash-safety is phase-tracked write-ahead + roll-forward. Refines 0002.
0004 Account policies & overdraft model accepted A closed AccountPolicy enum per account gates negative postings + floor; intent is explicit, illegal states unrepresentable. Refines 0001.
0005 Intent API: movements vs. envelopes accepted Callers express Movement/Transfer intent; resolve() produces the concrete Envelope. UTXO mechanics stay internal; idempotency keys on the resolved id.
0006 Reservation protocol & posting lifecycle accepted Active → PendingInactive → Inactive + a durable ReservationId give lock-free, recoverable, exclusive ownership of inputs. The primitive behind 0002/0003.
0007 Reversal via compensating transfers accepted Undo is an inverse envelope committed through the normal path (never deletion/mutation), preserving the append-only audit log.
0008 Conformance-tested storage accepted One store_tests! suite every backend must pass, with InMemoryStore as the executable reference; enforces the equal count semantics 0003 relies on.
0009 Monetary amounts as integer minor units accepted Cent is an i64 newtype of minor units with only checked arithmetic; scale lives in the presentation-only Amount, not on the stored value or asset. Makes 0001's conservation exact.
0010 Derived event stream vs. transfer log accepted A secondary append-only EventStore feed (outbox-style) for transfer + account-lifecycle events; transfer log stays authoritative. append_event is idempotent on a content key, a scoped exception to 0003.
0011 Swappable integer backing for money, default i64 accepted Cent moves to a kuatia-money crate over a CentBacking trait; the i64↔i128 width is a cargo feature, hidden from the API, stored as text. Refines 0009.

Recommended future ADRs

Real decisions whose rationale lives in the code/docs but is not yet captured as an ADR, roughly in priority order:

  1. Content-addressed transfer ids, and rejecting a sequential hash chain: EnvelopeId = double-SHA-256(canonical bytes) for idempotency
    • tamper evidence, and why a per-transfer hash chain was rejected (a concurrency bottleneck). See the "No Sequential Hash Chain" section of architecture.md.
  2. Pure core / async layer split: a zero-IO, deterministic kuatia-core (validation, selection, hashing; golden-vector testable) vs. the async storage + saga layer.
  3. Rust-generated ids (AutoId), no AUTOINCREMENT/SERIAL: the application owns identity (snowflake-style i64), enabling future sharding without DB coordination.
  4. Append-only, versioned accounts + snapshot pinning: accounts are never modified in place; snapshot hashes guard against TOCTOU between load and apply.
  5. All arithmetic in Rust, never in SQL: no SUM/MAX/etc. on monetary values; the storage layer stays a dumb record keeper.
  6. Book is a transfer-policy scope, not the accounting journal: the naming/modeling decision and why it is easy to conflate (accounting-mapping.md).
  7. Posting proliferation & consolidation: greedy largest-first selection (ADR-0001/0005) fragments balances into ever-smaller change postings; whether and how to consolidate, and what to do with dust, is undecided.
  8. Retention / pruning of Inactive postings and the append-only logs: both the transfer log and the derived event stream (ADR-0010) grow without bound; archival/retention is deferred and currently a conscious omission.
  9. Read/projection consistency model: a balance is a non-transactional sum over Active postings, so a read concurrent with a commit is eventually consistent; the read-side guarantee is implied but never stated.