auradefi 0.1.1
PyPI GitHub

MemoryLedger

auradefi.ledger.backends.memory · source

Dict-backed LedgerPort with hard per-tenant isolation.

Constructed empty with no arguments: MemoryLedger(), no tenants, every per-tenant seq counter starting from 0 (first write gets 1).

Every method validates tenant_id first: anything that is not a non-empty, non-whitespace str raises auradefi.errors.TenantIsolationError. One tenant's ids are indistinguishable from nonexistent ids for every other tenant.

__init__

__init__(self) -> None

upsert

upsert(self, tenant_id: str, txns: Sequence[LedgerTransaction]) -> list[SyncEvent]

Insert or update txns in one tenant's store.

New or payload-changed transactions are stored with the tenant's next last_modified_seq (monotonic, starting at 1) and emit ADDED events ordered by ascending seq. Payload-identical incoming transactions emit NO event and bump NO seq (idempotence), unless the STORED row is removed, in which case the transaction is resurrected: stored with removed=False, a bumped seq, and an ADDED event (SPEC §6.4: re-added is first-class). Incoming bookkeeping fields are never adopted. Duplicate ids within txns raise auradefi.errors.ValidationError before any write.

Parameters

tenant_idrequired, str

none

txnsrequired, Sequence[LedgerTransaction]

none

Raises

ValidationError

sync

sync(self, tenant_id: str, cursor: str | None = None, limit: int = 100) -> SyncPage

Page of changes since cursor, ascending last-modified seq.

Emits one event per stored transaction with last_modified_seq > decode_cursor(cursor), REMOVED when the stored row is removed, else ADDED, up to limit. next_cursor is encode_cursor of the last event's seq, or of the decoded input when the page is empty. has_more is True iff events beyond this page remain. A malformed cursor raises auradefi.errors.CursorError; a limit below 1 raises auradefi.errors.ValidationError (a page that can hold nothing can never drain, so paging would loop forever). Clients page until has_more is False before persisting next_cursor.

Parameters

tenant_idrequired, str

none

cursoroptional, str | None, default None

none

limitoptional, int, default 100

none

Raises

CursorError, ValidationError

get

get(self, tenant_id: str, txn_id: str) -> LedgerTransaction

Fetch one transaction from this tenant's store.

Raises auradefi.errors.NotFoundError when the id does not exist in THIS tenant's store. Another tenant's transaction is indistinguishable from a missing one.

Parameters

tenant_idrequired, str

none

txn_idrequired, str

none

Raises

NotFoundError

mark_removed

mark_removed(self, tenant_id: str, txn_ids: Sequence[str]) -> list[SyncEvent]

Mark transactions removed (reorg semantics), one tenant.

Sets removed=True with a bumped seq and emits REMOVED events ordered by ascending seq. An unknown id raises auradefi.errors.NotFoundError before any write; an already-removed id is a no-op emitting no event and bumping no seq.

Parameters

tenant_idrequired, str

none

txn_idsrequired, Sequence[str]

none

Raises

NotFoundError

apply_reorg

apply_reorg(self, tenant_id: str, plan: ReorgPlan) -> list[SyncEvent]

Apply a ReorgPlan: mark_removed then upsert.

Returns the composed events (REMOVED first, then ADDED) ordered by ascending seq. SPEC §6.4: a chain reorg is removed + re-added, first-class. Duplicate ids within plan.add raise auradefi.errors.ValidationError BEFORE any write, so a bad plan never leaves the tenant half-reorged.

Parameters

tenant_idrequired, str

none

planrequired, ReorgPlan

none

Raises

ValidationError