Skip to content

Book

wealthbraid.book.book

The :class:Book facade: the only way records enter a book.

Every mutation is an operation. An operation records who proposed it, the inputs and evidence it used, a reasoning summary, a confidence, and the exact records it would add. A proposal is validated against the current book before it is stored, so an agent learns immediately whether its changes could apply.

An operation's changes are written only after a decision:

  • a human approves or rejects it (decide), or
  • policy auto-approves it, which is allowed only when every change is non-sensitive (evidence, notes) and the book allows it.

Approval re-validates against the book as it is now; if the book moved on and the changes no longer apply, nothing is written. Agents can never approve.

Book

A wealthbraid book on disk.

__init__(root, *, clock=utc_now)

Open a book directory.

Parameters:

Name Type Description Default
root Path

The book directory (must contain wealthbraid.toml).

required
clock Callable[[], datetime]

Source of write timestamps; injectable for deterministic tests.

utc_now

add_evidence(content, *, filename, actor, source=None, description=None)

Store a source document and record it as evidence.

Adding identical bytes again returns the existing evidence record.

Parameters:

Name Type Description Default
content bytes

The document bytes.

required
filename str

The original file name.

required
actor str

Who is adding the document.

required
source str | None

Where it came from, e.g. a bank name.

None
description str | None

A free-text description.

None

Returns:

Type Description
tuple[str, OperationState | None]

The evidence record id and the operation that created it (None if it already existed).

Raises:

Type Description
ConflictError

If the book requires approval even for evidence.

decide(operation_id, *, actor, verdict, note=None)

Approve or reject a pending operation.

Parameters:

Name Type Description Default
operation_id str

The operation id.

required
actor str

The deciding human.

required
verdict str

"approve" or "reject".

required
note str | None

An optional note explaining the decision.

None

Returns:

Type Description
OperationState

The operation with its new status.

Raises:

Type Description
PolicyError

If the actor is not a human.

NotFoundError

If the operation does not exist.

ConflictError

If the operation was already decided.

ValidationError

If approved changes no longer apply to the book.

discover(explicit=None, **kwargs) classmethod

Open the book found by :func:~wealthbraid.book.config.find_book.

Parameters:

Name Type Description Default
explicit Path | None

An explicit book path, if given.

None
**kwargs Any

Passed to :class:Book.

{}

Returns:

Type Description
Book

The opened book.

propose(*, actor, tool, summary, changes, reasoning, confidence, evidence=(), inputs=None, approve=False, note=None)

Record an operation, applying it at once when allowed.

Parameters:

Name Type Description Default
actor str

The proposer (human:<name> or agent:<name>).

required
tool str

The operation name, e.g. "categorize".

required
summary str

A one-line description of the proposal.

required
changes Sequence[Mapping[str, Any]]

Proposed records as {"kind", "data", "rationale"?} mappings.

required
reasoning str

Why these changes are proposed.

required
confidence float

The proposer's confidence in [0, 1].

required
evidence Sequence[str]

Evidence record ids supporting the proposal.

()
inputs Mapping[str, Any] | None

The parameters and settings the operation used.

None
approve bool

Approve immediately; only a human proposer may do this.

False
note str | None

The approval note, when approve is set.

None

Returns:

Type Description
OperationState

The stored operation with its resulting status.

Raises:

Type Description
PolicyError

If a non-human asks to approve.

ValidationError

If the proposal is malformed or its changes cannot apply.

state(*, at=None)

Project the book's records into state.

Parameters:

Name Type Description Default
at str | None

Stop after this record id, reproducing the book as it was then.

None

Returns:

Name Type Description
The BookState

class:BookState.

Raises:

Type Description
NotFoundError

If at is not a record in the book.

check_actor(actor)

Validate a caller-supplied actor string.

Parameters:

Name Type Description Default
actor str

The actor, human:<name> or agent:<name>.

required

Returns:

Type Description
str

The actor unchanged.

Raises:

Type Description
PolicyError

If the actor is malformed or claims a reserved system: identity.

parse_data_change(raw, index)

Parse one proposed change.

Parameters:

Name Type Description Default
raw Mapping[str, Any]

The change mapping.

required
index int

Its position, for error messages.

required

Returns:

Type Description
ChangeData

The parsed :class:ChangeData.

Raises:

Type Description
ValidationError

If the change is malformed.

wealthbraid.book.state

The projection: folding the record log into queryable book state.

:class:BookState is a pure function of the record sequence. It never reads files; give it records and it rebuilds accounts, the current version of every entry (following corrections), statement lines and their matches, prices, reconciliations, notes, and the status of every operation. Any record that violates an invariant, including a record whose content no longer matches its id or whose chain link is broken, is kept in the log but excluded from the ledger and reported as an :class:Issue, so a damaged book still loads and can be diagnosed without serving tampered numbers.

AccountState dataclass

The lifecycle of one account.

BookState dataclass

Everything derivable from a record log.

head property

Return the last record folded in.

Returns:

Type Description
Record | None

The head record, or None for an empty book.

apply(record)

Fold one record into the state.

Parameters:

Name Type Description Default
record Record

The next record in chain order.

required

Returns:

Type Description
list[Issue]

The issues this record raised (also appended to :attr:issues).

changed_since(operation)

Return ids of records that changed the book after an operation was proposed.

Proposals, decisions, and applied markers do not change balances by themselves; the records an applied operation produced do.

Parameters:

Name Type Description Default
operation OperationState

The operation.

required

Returns:

Type Description
list[str]

Ids of later content records (empty if the book is as it was).

current_version(record_id)

Follow corrections from any version id to the current one.

Parameters:

Name Type Description Default
record_id str

An entry, statement line, account record, or correction id.

required

Returns:

Type Description
str | None

The current version id, or None if the record was voided or is unknown.

from_records(records) classmethod

Fold records, in order, into a new state.

Parameters:

Name Type Description Default
records Iterable[Record]

The record log in chain order.

required

Returns:

Type Description
BookState

The resulting :class:BookState.

issues_for(record_ids)

Return the issues raised by specific records.

Parameters:

Name Type Description Default
record_ids Iterable[str]

The record ids of interest.

required

Returns:

Type Description
list[Issue]

The matching issues.

ledger(*, start=None, end=None)

Build an engine ledger from current entries within a date range.

Parameters:

Name Type Description Default
start date | None

Include entries on or after this date, if given.

None
end date | None

Include entries on or before this date, if given.

None

Returns:

Type Description
Ledger

A populated :class:~wealthbraid.engine.ledger.Ledger with every

Ledger

account declared and every price recorded.

pending_line_proposals()

Map statement line ids to the pending operations proposing entries for them.

Returns:

Type Description
dict[str, list[str]]

Line id to the ids of pending operations whose entry changes cite it.

sorted_entries()

Return current entry versions in date order (ties by log order).

Returns:

Type Description
list[EntryVersion]

The entry versions.

unmatched_lines()

Return statement line ids not accounted for by any current entry.

Returns:

Type Description
list[str]

Line ids sorted by date then id.

EntryVersion dataclass

The current version of an entry after applying corrections.

Attributes:

Name Type Description
id str

The record id providing this version (an entry or correction).

origin str

The id of the original entry record.

data EntryData

The entry payload.

transaction Transaction

The balanced engine transaction.

history list[str]

Every version id from the original entry to this one.

Issue dataclass

An invariant violation attributed to a record.

Attributes:

Name Type Description
record str

The offending record id.

message str

What is wrong.

OperationState dataclass

An operation and its derived approval status.

id property

Return the operation id.

Returns:

Type Description
str

The operation record id.

results property

Return the ids of records produced by applying the operation.

Returns:

Type Description
list[str]

The result ids (empty unless applied).

sensitive property

Report whether any proposed change needs explicit approval.

Returns:

Type Description
bool

True if a change could alter balances or accounts.

status property

Return pending, rejected, approved (not yet applied), or applied.

Returns:

Type Description
str

The status slug.

has_refs(value)

Report whether a payload carries "$N" references in reference fields.

Parameters:

Name Type Description Default
value Any

A JSON-compatible payload.

required

Returns:

Type Description
bool

True if any reference field holds a "$N" placeholder.

resolve_refs(value, produced)

Replace "$N" placeholders in reference fields with the id of the N-th produced record.

Only the values of :data:REFERENCE_KEYS (and the items of lists held there) are resolved; free text such as descriptions is never rewritten.

Parameters:

Name Type Description Default
value Any

A JSON-compatible payload.

required
produced list[str]

Ids of the records produced so far, in change order.

required

Returns:

Type Description
Any

A copy of value with placeholders resolved.

Raises:

Type Description
ValidationError

If a placeholder points at a change not yet produced.

to_transaction(record_id, data)

Convert an entry payload to an engine transaction.

Parameters:

Name Type Description Default
record_id str

The version id to carry as the transaction id.

required
data EntryData

The entry payload.

required

Returns:

Type Description
Transaction

The unbalanced engine :class:Transaction.

wealthbraid.book.schema

Typed payload schemas for every record kind and for operation proposals.

The schemas validate the data of each record at the boundary: when an agent or a human proposes changes, and again when a book is loaded. Money is always a decimal string ("-12.50"); floats are rejected so rounding error cannot enter the ledger. :func:json_schema exposes the proposal format to agents.

AccountCloseData

Bases: _Model

Close an account; postings after the date are rejected.

AccountOpenData

Bases: _Model

Declare an account from a date onwards.

AppliedData

Bases: _Model

The records an approved operation produced.

ChangeData

Bases: _Model

One proposed record. String values "$N" refer to the id produced by change N.

CorrectionData

Bases: _Model

Supersede the current version of a record with a replacement, or void it.

A correction can target an entry, a statement line, an account.open, or an account.close. The replacement must be a payload of the target's kind; it is validated against that kind when the correction is applied.

DecisionData

Bases: _Model

A human (or policy) verdict on an operation.

EntryData

Bases: _Model

A balanced double-entry accounting transaction.

EvidenceData

Bases: _Model

An imported source document, stored immutably by digest.

LineData

Bases: _Model

One observed statement line extracted from evidence (not yet accounted for).

NoteData

Bases: _Model

An explanation or annotation attached to one or more records.

OperationData

Bases: _Model

A proposed set of changes together with its provenance.

PostingData

Bases: _Model

A single posting with an explicit amount.

PriceData

Bases: _Model

An exchange rate: one unit of base is worth rate units of quote.

ReconciliationData

Bases: _Model

A statement balance checked against the ledger as of a date.

dump_data(model)

Serialise a payload model to canonical JSON-compatible data.

Parameters:

Name Type Description Default
model BaseModel

The payload model.

required

Returns:

Type Description
dict[str, Any]

A JSON-compatible dictionary with dates as ISO strings and no nulls or

dict[str, Any]

empty collections that carry defaults.

format_validation_error(error)

Render a Pydantic validation error as one readable line.

Parameters:

Name Type Description Default
error ValidationError

The Pydantic error.

required

Returns:

Type Description
str

A field: message; field: message summary.

json_schema(kind='operation')

Return the JSON Schema for a record kind's payload.

Parameters:

Name Type Description Default
kind str

A record kind value, e.g. "operation" or "entry".

'operation'

Returns:

Type Description
dict[str, Any]

The JSON Schema dictionary.

Raises:

Type Description
UsageError

If the kind is unknown.

parse_data(kind, data)

Validate and parse a record payload.

Parameters:

Name Type Description Default
kind RecordKind

The record kind.

required
data Any

The raw payload.

required

Returns:

Type Description
Any

The parsed model instance.

Raises:

Type Description
ValidationError

If the payload does not satisfy the kind's schema.

wealthbraid.book.config

Book settings (wealthbraid.toml) and book discovery.

A book is a directory containing wealthbraid.toml. Settings are not part of the append-only log: they only shape future operations, and every operation records the settings it used (import profile, categorization rules) in its inputs, so past results stay reproducible after settings change.

BookConfig dataclass

Parsed wealthbraid.toml settings.

Attributes:

Name Type Description
root Path

The book directory.

name str

A human-friendly book name.

currency str

The reporting commodity.

user str

The local human's name; approvals from the web UI are recorded as human:<user>.

auto_apply bool

Whether operations with only non-sensitive changes are applied without review.

rules tuple[CategorizeRule, ...]

Ordered categorization rules.

profiles dict[str, ImportProfile]

Import profiles by name.

human_actor property

Return the actor string for the local human.

Returns:

Type Description
str

"human:<user>".

CategorizeRule dataclass

Assign a counter account to statement lines whose text matches a pattern.

Attributes:

Name Type Description
pattern str

A case-insensitive regular expression searched in payee and description.

account str

The account to assign.

account_filter str | None

Only apply to lines from this statement account (subtree), if set.

confidence float

The confidence recorded for matches of this rule.

matches(text, line_account)

Report whether the rule applies to a statement line.

Parameters:

Name Type Description Default
text str

The line's payee and description joined together.

required
line_account str

The statement account the line belongs to.

required

Returns:

Type Description
bool

True if the rule applies.

to_json()

Return a JSON-compatible form for recording in operation inputs.

Returns:

Type Description
dict[str, Any]

The rule as a dictionary.

ImportProfile dataclass

Column mapping for a CSV statement format.

Attributes:

Name Type Description
name str

The profile name used on the command line.

account str | None

Default statement account for files of this format.

date str

Header of the date column.

amount str | None

Header of a signed amount column (or use debit/credit).

debit str | None

Header of an outflow column (positive numbers reduce the balance).

credit str | None

Header of an inflow column.

description str | None

Header of the description column.

payee str | None

Header of the payee column.

external_id str | None

Header of a bank reference column.

date_format str | None

strptime format, or None for ISO dates.

delimiter str

Field delimiter.

decimal_comma bool

Whether amounts use , as the decimal separator.

commodity str | None

The statement currency.

to_json()

Return a JSON-compatible form for recording in operation inputs.

Returns:

Type Description
dict[str, Any]

The profile fields that are set.

find_book(start=None, explicit=None)

Locate a book directory.

Precedence: an explicit path, then $WEALTHBRAID_BOOK, then the nearest ancestor of start (default: the working directory) containing wealthbraid.toml.

Parameters:

Name Type Description Default
start Path | None

Where to begin the upward search.

None
explicit Path | None

A path given on the command line.

None

Returns:

Type Description
Path

The book directory.

Raises:

Type Description
NotFoundError

If no book can be found.

init_book(root, *, name, currency, user)

Create a new, empty book.

Parameters:

Name Type Description Default
root Path

The directory to initialise (created if missing).

required
name str

The book name.

required
currency str

The reporting currency.

required
user str

The local human's name.

required

Returns:

Type Description
Path

The book directory.

Raises:

Type Description
UsageError

If a book already exists there or the settings are invalid.

load_config(root)

Load and validate a book's settings.

Parameters:

Name Type Description Default
root Path

The book directory.

required

Returns:

Type Description
BookConfig

The parsed :class:BookConfig.

Raises:

Type Description
NotFoundError

If the settings file does not exist.

UsageError

If the settings are malformed.

wealthbraid.book.verify

Whole-book verification: the audit a human or agent runs to trust a book.

Verification rebuilds everything from the files on disk and checks that:

  • every line parses and every record's id matches its content;
  • sequence numbers are consecutive and each prev links to the record before it;
  • the head anchor names the last record, so records deleted from the end of the log are noticed, and no unexpected files sit under records/;
  • every evidence blob exists and still hashes to its recorded digest, and no blob is stored without an evidence record;
  • the projection raises no invariant issues (balancing, accounts, provenance);
  • no operation was approved without its changes being applied.

Problem dataclass

A verification finding.

Attributes:

Name Type Description
check str

The check that failed (chain, id, evidence, ledger, operation, file).

record str | None

The record concerned, if any.

message str

What is wrong.

VerifyReport dataclass

The outcome of :func:verify_book.

ok property

Report whether the book passed every check.

Returns:

Type Description
bool

True if no problems were found.

verify_book(book)

Run every check against a book.

Parameters:

Name Type Description Default
book Book

The book to verify.

required

Returns:

Name Type Description
The VerifyReport

class:VerifyReport.

verify_records(records)

Check identifiers, sequence numbers, and the hash chain.

Parameters:

Name Type Description Default
records list[Record]

The records in file order.

required

Returns:

Type Description
list[Problem]

The problems found.