Store
wealthbraid.store.records
¶
Record envelopes, canonical JSON, and content-derived identifiers.
Every fact in a book is a :class:Record: an immutable envelope carrying a
kind, the actor who caused it, the operation it belongs to (if any), and a
kind-specific data payload. Records form a single hash chain: each record's
prev is the identifier of the record before it, and its id is derived
from the SHA-256 digest of its canonical JSON form (everything except id).
Rewriting or reordering any earlier record therefore changes every later
identifier, which :func:wealthbraid.book.verify.verify_book detects.
Record
dataclass
¶
An immutable, content-addressed record in a book's log.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
The content-derived identifier. |
seq |
int
|
The 1-based position of the record in the log. |
prev |
str | None
|
The identifier of the previous record, or |
kind |
RecordKind
|
The record kind. |
recorded_at |
str
|
UTC timestamp (ISO-8601, seconds precision) of the write. |
actor |
str
|
Who caused the record, e.g. |
operation |
str | None
|
The operation this record resulted from, if any. |
data |
Mapping[str, Any]
|
The kind-specific payload. |
v |
int
|
The record schema version. |
body()
¶
create(*, seq, prev, kind, recorded_at, actor, operation, data)
classmethod
¶
Build a record and derive its identifier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seq
|
int
|
The log position. |
required |
prev
|
str | None
|
The previous record's identifier. |
required |
kind
|
RecordKind
|
The record kind. |
required |
recorded_at
|
str
|
The UTC write timestamp. |
required |
actor
|
str
|
The actor string. |
required |
operation
|
str | None
|
The originating operation, if any. |
required |
data
|
Mapping[str, Any]
|
The kind-specific payload. |
required |
Returns:
| Type | Description |
|---|---|
Record
|
The new :class: |
expected_id()
¶
Recompute the identifier this record's content implies.
Returns:
| Type | Description |
|---|---|
str
|
The identifier derived from :meth: |
from_json(raw)
classmethod
¶
Parse a record from its on-disk representation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw
|
Mapping[str, Any]
|
The decoded JSON object. |
required |
Returns:
| Type | Description |
|---|---|
Record
|
The parsed :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If required fields are missing or the kind is unknown. |
to_json()
¶
RecordKind
¶
canonical_json(value)
¶
Serialise a JSON-compatible value canonically.
Keys are sorted, separators carry no whitespace, and non-ASCII text is kept verbatim, so equal values always produce byte-identical output.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
A JSON-compatible value (no floats should appear in records). |
required |
Returns:
| Type | Description |
|---|---|
str
|
The canonical JSON text. |
compute_id(kind, body)
¶
Derive a record identifier from its kind and envelope body.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kind
|
RecordKind
|
The record kind, which supplies the prefix. |
required |
body
|
Mapping[str, Any]
|
The envelope without its |
required |
Returns:
| Type | Description |
|---|---|
str
|
An identifier such as |
wealthbraid.store.store
¶
The on-disk, append-only record log and content-addressed evidence store.
Layout of a book directory::
wealthbraid.toml settings (see wealthbraid.book.config)
records/2026/09.jsonl append-only log segments, one record per line
records/HEAD anchor: sequence number and id of the newest record
evidence/sha256/ab/abcdef… immutable evidence blobs named by digest
.wealthbraid/ local, regenerable state (lock file); git-ignored
Records are only ever appended. A write takes an exclusive lock, computes the
new records' identifiers against the current head of the chain, and appends all
of them in a single write followed by fsync, then updates the head anchor.
The anchor lets verification notice records deleted from the end of the log,
which the hash chain alone cannot. Nothing in this module can modify or delete
an existing record or evidence blob.
PendingAppend
¶
Records staged for a single atomic append to the log.
__init__(store, head, recorded_at)
¶
Bind a pending append to the head it extends.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
RecordStore
|
The owning store. |
required |
head
|
Record | None
|
The current last record, or |
required |
recorded_at
|
str
|
The timestamp shared by every record in this append. |
required |
add(kind, data, *, actor, operation=None)
¶
Stage a record; its identifier is available immediately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kind
|
RecordKind
|
The record kind. |
required |
data
|
Mapping[str, Any]
|
The kind-specific payload. |
required |
actor
|
str
|
The actor string. |
required |
operation
|
str | None
|
The originating operation, if any. |
None
|
Returns:
| Type | Description |
|---|---|
Record
|
The staged :class: |
RecordStore
¶
Append-only access to a book's record log and evidence blobs.
anchor_path
property
¶
evidence_dir
property
¶
Return the directory holding evidence blobs.
Returns:
| Type | Description |
|---|---|
Path
|
The |
records_dir
property
¶
Return the directory holding log segments.
Returns:
| Type | Description |
|---|---|
Path
|
The |
__init__(root, *, clock=utc_now)
¶
begin(*, recorded_at=None)
¶
Start collecting records to append against the current head.
The caller must hold :meth:lock until :meth:PendingAppend.commit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
recorded_at
|
str | None
|
The timestamp for the staged records; defaults to now. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
PendingAppend
|
class: |
evidence_path(sha256)
¶
head()
¶
Return the last record in the log, if any.
Returns:
| Type | Description |
|---|---|
Record | None
|
The most recent record, or |
iter_records()
¶
Yield every record in log order.
Yields:
| Type | Description |
|---|---|
Record
|
Parsed records, without identifier or chain verification. |
Raises:
| Type | Description |
|---|---|
IntegrityError
|
If a line is not valid JSON or not a valid record. |
lock()
¶
Hold the book's exclusive write lock.
Yields:
| Type | Description |
|---|---|
None
|
Nothing; the lock is held for the duration of the block. |
A lock left behind by a process that no longer exists is recovered automatically. On release, the lock file is removed only if it still names this process.
Raises:
| Type | Description |
|---|---|
ConflictError
|
If another live process holds the lock. |
put_evidence(content)
¶
Store an evidence blob by digest; storing the same bytes twice is a no-op.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
bytes
|
The raw file content. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The SHA-256 digest of |
Raises:
| Type | Description |
|---|---|
IntegrityError
|
If a different blob already occupies the digest's path. |