Skip to content
Ledger by RODMEN/A
Menu

Product

What the ledger guarantees, and what enforces it

A guarantee is only worth what enforces it. Each of these is a rule of the database rather than a promise in our code, and each is guarded by a live check that runs against the real service.

Twelve guarantees

Each one names its enforcement and its check

  1. 01

    Every transaction balances

    What leaves one account arrives in another, for each kind of asset in the transaction. A transaction that does not balance is refused before anything is written.

    Enforced by
    the database, at the moment it commits
    Guarded by
    database certification probes
    For engineers: the precise statement

    Debits equal credits per (transaction, asset type), both sides present, 2–100 entries matching the declared count, verified at COMMIT by a deferred constraint trigger. Holds through any path, including direct SQL.

  2. 02

    History cannot be edited

    Entries are permanent. Nobody can change or delete them, including us. A mistake is corrected with a new, visible transaction that reverses it.

    Enforced by
    the database: no edit or delete path exists on the journal
    Guarded by
    database certification probes
    For engineers: the precise statement

    No UPDATE, DELETE or TRUNCATE on entries; transactions only move pending → committed | voided | expired. The API role holds no DELETE anywhere; guard triggers refuse the operation independently of privileges.

  3. 03

    Amounts are exact

    Money, credits and stock are counted in whole minor units, so nothing is ever rounded away. Amounts travel as text, never as approximate numbers.

    Enforced by
    the database column type and a build check that refuses approximate arithmetic on any amount path
    Guarded by
    probe_money_precision
    For engineers: the precise statement

    NUMERIC(38,0) minor units with a per-asset scale 0–12; the API carries amounts as decimal strings; a float on an amount path fails the lint gate.

  4. 04

    An account cannot go below its floor

    Every account declares its floor: zero for a customer wallet, a negative limit for an agreed overdraft. A movement that would breach it is refused, even when many requests race for the same balance.

    Enforced by
    the database: balances are locked in a fixed order before checking, and a constraint is the final wall
    Guarded by
    probe_account_floor, probe_floor_guard, probe_concurrency
    For engineers: the precise statement

    Balance rows locked SELECT … FOR UPDATE in ascending account id (deadlock structurally impossible), a half-second lock timeout → 409 with Retry-After, floor CHECK on account_balances.

  5. 05

    A retried request cannot move money twice

    Every write carries a key you choose. If your connection drops and you send the same request again, you get the original answer back and nothing moves a second time.

    Enforced by
    the ledger write and its receipt committing together, in one database transaction
    Guarded by
    probe_a38_idem_transient, probe_idem_operational_409, probe_idem_takeover_fp, probe_idem_storm_after_clear
    For engineers: the precise statement

    Idempotency-Key per (tenant, endpoint), remembered 7 days; claim → execute and complete in the same transaction → record business failures; lease takeover for crashed owners; UNIQUE(tenant_id, idempotency_key) on transactions.

  6. 06

    One customer can never see another

    Your credential is your boundary. Records that belong to someone else do not exist as far as your requests are concerned, and a request without a valid boundary is refused rather than answered.

    Enforced by
    two independent layers, the second inside the database, failing closed
    Guarded by
    probe_rls_parity, probe_control_plane_rls, probe_money_isolation, probe_sub_tenancy
    For engineers: the precise statement

    Tenant-bounded queries AND row-level security ENABLED + FORCED on every tenant table and partition, set per transaction; missing context errors rather than returning rows; the API role owns no tables and cannot bypass the policy.

  7. 07

    Reserve first, settle later

    A hold sets money or stock aside without moving it. You then complete it or release it; anything you forget is released for you when it expires.

    Enforced by
    the database state machine for transactions
    Guarded by
    probe_expiry_sweep, probe_hold_expiry_replay, probe_frozen_blocks_commit
    For engineers: the precise statement

    pending: true reduces available and leaves posted untouched; commit/void/expire move atomically; a sweeper expires unresolved holds on schedule; a frozen or closed account blocks settlement.

  8. 08

    A temporary failure never counts against you

    If the service itself has a momentary problem, your request key stays usable and the retry does the work. Only a real business refusal is remembered and replayed.

    Enforced by
    the retry protocol
    Guarded by
    probe_a38_idem_transient
    For engineers: the precise statement

    Transient conditions (lock timeout, deadlock retry, statement timeout, any unmapped 5xx) leave the key re-executable; deterministic business failures replay verbatim; anything carrying Retry-After honours a retry.

  9. 09

    A retry gets the original answer, even later

    Checks that depend on the clock run inside the write, so a request you repeat after an hour is answered exactly as it was the first time.

    Enforced by
    the ordering of validation inside the write
    Guarded by
    probe_hold_expiry_replay
    For engineers: the precise statement

    Time-dependent validation runs inside the idempotency engine, never at the boundary; a completed key replays before any check runs.

  10. 10

    Every figure says what unit it is in

    A balance is shown both as you would write it and as a whole number of minor units, on every response, so a display value can never be mistaken for a raw count.

    Enforced by
    the response contract
    Guarded by
    probe_read_contract_parity
    For engineers: the precise statement

    Every money field without a _minor suffix is a display-scale decimal string, on success responses as well as errors; the _minor companion is the integer.

  11. 11

    A bad request gets a clear answer, not a crash

    A request with a wrong or oversized value is refused with a message naming the field. The service never answers a client mistake with an internal error.

    Enforced by
    validation at the boundary and a single error format across every layer
    Guarded by
    probe_input_bounds, probe_json_depth, probe_error_envelope_parity, probe_edge_error_envelope
    For engineers: the precise statement

    Malformed or out-of-domain input returns a 4xx naming the field; no 5xx and no SQLSTATE leaks; the same {"error":{"code"}} envelope from the application, the framework and the edge.

  12. 12

    Busy accounts catch up without skipping anything

    A shared account that every transaction touches is totalled in the background, and the totalling can never leave an entry out.

    Enforced by
    a visibility rule the background worker must respect
    Guarded by
    probe_rollup_visibility, probe_async_pending
    For engineers: the precise statement

    The rollup advances only to a horizon below which no future commit can land; if the horizon is unknowable it refuses to advance; the reconciler uses the same horizon.

The checks named above are part of the live probe suite that runs against the service; the database certification probes are the schema-level suite every migration must pass. How both are run, and what they found, is on the assurance pages.

Free today. Access is provisioned personally by RODMENA.

Tell us what you keep books of and we will set up a tenant, mint your first key and walk you through the tour.