MemoryLedger
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, strnone
txnsrequired, Sequence[LedgerTransaction]none
Raises
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, strnone
cursoroptional, str | None, default Nonenone
limitoptional, int, default 100none
Raises
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, strnone
txn_idrequired, strnone
Raises
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, strnone
txn_idsrequired, Sequence[str]none
Raises
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, strnone
planrequired, ReorgPlannone