Agent reason: an agent traces a figure back to what produced it by reading
the journal, but it must never read the file. books.journal_history is the
one way: each line in order with its seq, time, type, a sentence saying what
it did to what, its subject and the entry it belongs to, filtered by
after_seq, type (exact, or a group like entry.) and subject (entry:12,
invoice:3, bill:3, account:10, party:5, asset:2), paged with more, with the
torn tails set aside on open listed beside them. It reads the verified
journal through read_journal_and_format, so a damaged chain is an error, not
a story.
The sentences come from ledger-store's describe.rs, which quotes only
identifiers, dates, amounts and the short names a person typed: never a
setting's value (settings.set names its keys) and never a full TIN (masked,
B-26). Every event type the store writes has a sentence (tested against
EVENT_TYPES). The tool is read-only (books:read); the books://journal/{seq}
and books://entries/{id} resources read through it.
Departure from the plan: the viewer's own sentences (its describe arms in
ledger-gui, which carry icons, routes and today's party and account names)
stay where they are; moving a thousand lines of egui text behind a
formatting trait was not worth the risk to the viewer's tests, so the server
has the shared describer and the viewer keeps its own.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
56 lines
2.0 KiB
Rust
56 lines
2.0 KiB
Rust
//! `ledger-store`: durable persistence for the books.
|
|
//!
|
|
//! Three pieces, one job — keep the books safe:
|
|
//!
|
|
//! * [`journal`] — the source of truth. An append-only, hash-chained JSONL
|
|
//! journal. Every state change is an immutable fact, fsync'd on append.
|
|
//! * [`blob`] — the bytes. Content-addressed (SHA-256), immutable,
|
|
//! deduplicated receipt and document storage.
|
|
//! * [`Store`] — the SQLite projection plus the write path. SQLite is the
|
|
//! query engine and is disposable by design: [`Store::rebuild`] drops it
|
|
//! and replays the journal. [`Store::verify`] replays the journal into a
|
|
//! fresh engine and diffs its reports against both the live ledger and
|
|
//! the projection.
|
|
//!
|
|
//! The write path is singular: **validate → journal → mutate → apply**.
|
|
//! Journal first means a failed write leaves nothing behind; a failed
|
|
//! SQLite apply leaves the journal ahead, and the next open heals it via
|
|
//! `last_applied_seq`. There is exactly one writer: `Store` is `!Sync` by
|
|
//! construction (it owns a `rusqlite::Connection`).
|
|
|
|
pub mod access;
|
|
pub mod auth;
|
|
pub mod backup;
|
|
pub mod blob;
|
|
pub mod chain;
|
|
pub mod describe;
|
|
pub mod error;
|
|
pub mod exports;
|
|
pub mod form1099;
|
|
pub mod format;
|
|
pub mod journal;
|
|
pub mod meta;
|
|
pub mod ops;
|
|
pub mod passphrase;
|
|
pub mod reconcilable;
|
|
#[cfg(test)]
|
|
mod refuse;
|
|
pub mod root;
|
|
pub mod saving;
|
|
pub mod schema;
|
|
pub mod snapshot;
|
|
pub mod store;
|
|
pub mod uploads;
|
|
|
|
pub use blob::BlobStore;
|
|
pub use error::StoreError;
|
|
pub use format::{FormatUpgrade, JournalFormat, SUPPORTED_JOURNAL_FORMAT};
|
|
pub use journal::{GENESIS_PREV, JournalLine, JournalWriter};
|
|
pub use snapshot::{DiskCheck, Snapshot};
|
|
pub use store::{
|
|
Attachment, BillPreview, DepreciationRun, DisposalPreview, EntryRow, EventRow, Extraction,
|
|
ExtractionStatus, InvoicePreview, JOURNAL_FILE, LEGACY_DB_FILE, LOCK_FILE, MAX_RECURRING_RUN,
|
|
PayrollLineInput, PreviewPosting, Reconciliation, Statement, Store, Subject, VerifyReport,
|
|
WriteOffEvidence, database_in_use, db_file, db_file_for, is_database_file,
|
|
};
|