doubleentry 0.8.0

An immutable, tamper-evident double-entry bookkeeping engine: one pure rule core, exact integer money, identity derived from the idempotency key, and one append-only RFC 6962 Merkle log with inclusion, consistency and sealed-balance proofs and C2SP checkpoints, in memory (sync) or over SQLite and PostgreSQL (async).
Documentation
# Changelog

Notable changes to `doubleentry`, in the format of
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versioned per
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). Every version is
published on crates.io. ⚠️ marks a change to a hash, an encoding or the schema.

## [Unreleased]

## [0.8.0] — 2026-10-16

### ⚠️ Breaking

- A new model, hash, encoding and schema. 0.8 cannot read a 0.7 ledger and there
  is no migration: create a new ledger and re-record the books from their source
  documents. A 0.7 ledger stays readable with 0.7.
- A ledger is one append-only RFC 6962 SHA-256 Merkle log of typed records
  (genesis, account, currency and policy events, periods, entries, clearings,
  seals). One pure rule core decides every write; `Journal` (sync, in memory)
  and `Ledger<S: Store>` (async) call it with the same method names.
- SHA-256 replaces BLAKE3 for every hash.
- `EntryId` is derived from the ledger id and the idempotency key; no UUIDs.
- `Journal::new(LedgerId)` (`P = 2`; `Journal::<P>::with_precision` for other
  scales). The ledger id is the C2SP origin.
- `record(Entry) -> Result<Recorded, Error>` is the only way in; `record_batch`
  is atomic. Builders are infallible and take account paths or handles;
  `validate(&draft)` lists structural violations. `SealContext`, `Entry::seal`,
  `Entry<Balanced>`, `adopt_verified`, `EntryBatch` and `record_validated` are
  gone.
- Master data are dated records: `open`, `register(AccountSpec)`, `set_limit`,
  `set_class`, `close_account`, `reopen_account`; `as_actor` names the writer.
- Periods: `define_period(id, start, end)`, `define_months`, `seal_period`,
  `seal_through`. A period is sealed when a seal record exists.
- Proofs: `prove_entry`, `prove_entry_at`, `prove_consistency(old, new)`,
  `head_at`, `prove_balance(account, currency, layer, period)` →
  `log::SealedBalanceProof`, verified against a head alone.
- `audit()` on both façades replaces `verify_log`, `verify_balanced`,
  `verify_balances` and `verify_seals`.
- One `Error` with nine variants (`Rejected`, `BatchRejected`, `Value`,
  `Amount`, `Query`, `Transparency`, `Integrity`, `Backend`, `Config`) replaces
  every per-module error type; payloads live in `doubleentry::error`.
- `store::Store` replaces `LedgerStore` and `DynLedgerStore`;
  `store::SqlStore::sqlite(url)` / `SqlStore::postgres(url)` replace
  `SqliteStore` and `PostgresStore`. `Ledger::new` creates or opens; one schema,
  `doubleentry/1`, and no migrations.
- `transparency` (C2SP checkpoints, `WitnessSession`, `Policy`, `Verifier`)
  replaces the `witness` module; there is no in-crate witness.
- Report types moved to `doubleentry::report`; `BalanceQuery` stays at the root.
- `amount!`, `currency!` and `date!` are checked at compile time.
- sqlx 0.9; neither store feature enables a TLS stack.

### Added

- 76 rejections with stable numeric codes, grouped by stage
  (`Rejection::code`, `Rejection::stage`, `Error::code`).
- Idempotent retries: the same draft returns the original `Recorded` with
  `replayed == true`; the same key with other content is `KeyConflict` (200).
- Holds on the Pending layer: `Entry::open_hold`, `post_hold` (full or
  partial), `void_hold`, `expire_hold`, `hold`, `holds_due`.
- Balance limits checked inside the write, holds included.
- `Amount<P>` over `i128`: seven `Rounding` modes, `allocate`, `distribute`,
  `checked_mul_ratio`, `display_at`.
- Erasable memos behind a salted commitment (`erase_memo`, `memo_salted`,
  `with_salt_source`).
- Sealed balances: one account-indexed tree per (currency, layer), provable and
  named per account.
- Reads over one `BalanceQuery`: `balance`, `trial_balance`, `statement`,
  `rollup`, `open_items`, `check_assertion(s)`, `entry`, `entry_by_key`.
- `doubleentry::export`: head-pinned flat rows and `export::verify`.
- `store::MemoryStore`, `SqlStore` for SQLite and PostgreSQL
  (`SqlStore::<Postgres>::with_schema`), and the public conformance suite
  (`testing` feature).
- `transparency`: C2SP `signed-note`, `tlog-checkpoint`, `tlog-cosignature`,
  `tlog-witness`, `tlog-policy`, `tlog-proof` and `tlog-tiles`; `checkpoint`,
  `bundle_record`, `bundle_entry`, `bundle_balance`, `tile`, `tile_entries`.
- `Journal::from_log`, `Journal::leaves`, `Ledger::to_journal`.
- `doubleentry::prelude`.
- `tracing` feature: spans per façade operation and per SQL store write.

### Removed

- Modules `account`, `balance`, `canonical`, `checkpoint`, `clearing`,
  `closing`, `dimensions`, `entry`, `hash`, `merkle`, `money`, `period`,
  `posting`, `rollup`, `seal`, `storage`, `witness`.
- The `iceberg` feature and the cold tier, deferred sequencing, pruning,
  balance checkpoints, the seal hash chain, `schema/*.sql` and `migrate`.
- Dependencies `blake3`, `uuid`, `smallvec`, `iceberg`, `arrow-*`, `parquet`.

## [0.7.0] — 2026-08-26

- Account rollups over the path tree.
- ⚠️ One `BalanceQuery` for every balance read; reads fold by booking or value
  date; dimensions can be filtered and reported on.
- ⚠️ Entries balance per currency and layer; balance limits count both layers.
- ⚠️ Proofs read `O(log n)` stored nodes; seals prove the log was only appended
  to; a consistency proof from the empty tree is refused.
- Witness cosigning, `Journal::audit()`, `get_by_key`,
  `Amount::checked_mul_ratio` and `Rounding`.
- Fixed: SQLite parameter binding after a reused placeholder.

## [0.6.0] — 2026-08-17

- `prove_sealed_balance` returns `SealedBalanceOutcome`.
- Added `LedgerStore::all_open_items`.

## [0.5.0] — 2026-08-17

- ⚠️ The account-binding commitment covers only handle and path.
- Sealing a period closes every earlier date.
- Fixed: sealed-balance proofs through a store and after new registrations,
  paged statements and open items, proofs over a pruned log.

## [0.4.0] — 2026-08-15

- ⚠️ Seals commit to tree heads (size and root); the seal hash changed.
- Proofs verify against a `TreeHead`, not a bare root; proofs against an
  archived head; `LedgerStore::head_at`.

## [0.3.0] — 2026-08-14

- ⚠️ The entry hash and the seal hash changed.
- Added account-binding root, balance proofs, `BalanceLimit`, date-based
  balance assertions, period persistence.
- Balances take a prefix size, not an index.

## [0.2.0] — 2026-08-01

- Fixed: an entry's `kind` was hashed but not stored.
- Added `StatementLine::kind`.

## [0.1.0] — 2026-07-28

- Initial release.

[Unreleased]: https://github.com/hupe1980/doubleentry/compare/v0.8.0...HEAD
[0.8.0]: https://github.com/hupe1980/doubleentry/compare/v0.7.0...v0.8.0
[0.7.0]: https://github.com/hupe1980/doubleentry/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/hupe1980/doubleentry/compare/v0.5.0...v0.6.0
[0.5.0]: https://github.com/hupe1980/doubleentry/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/hupe1980/doubleentry/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/hupe1980/doubleentry/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/hupe1980/doubleentry/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/hupe1980/doubleentry/releases/tag/v0.1.0