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)
¶
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 ( |
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
|
|
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
¶
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 ( |
required |
tool
|
str
|
The operation name, e.g. |
required |
summary
|
str
|
A one-line description of the proposal. |
required |
changes
|
Sequence[Mapping[str, Any]]
|
Proposed records as |
required |
reasoning
|
str
|
Why these changes are proposed. |
required |
confidence
|
float
|
The proposer's confidence in |
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 |
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)
¶
check_actor(actor)
¶
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: |
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 |
apply(record)
¶
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)
¶
from_records(records)
classmethod
¶
issues_for(record_ids)
¶
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: |
Ledger
|
account declared and every price recorded. |
pending_line_proposals()
¶
sorted_entries()
¶
Return current entry versions in date order (ties by log order).
Returns:
| Type | Description |
|---|---|
list[EntryVersion]
|
The entry versions. |
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
¶
OperationState
dataclass
¶
has_refs(value)
¶
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 |
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: |
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 |
json_schema(kind='operation')
¶
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 |
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. |
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)
¶
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 |
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
|
|
delimiter |
str
|
Field delimiter. |
decimal_comma |
bool
|
Whether amounts use |
commodity |
str | None
|
The statement currency. |
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: |
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
prevlinks 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
¶
VerifyReport
dataclass
¶
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: |