@alma-harness/execution
v0.12.0
Published
Durable execution persistence helpers for Alma.
Readme
@alma-harness/execution
Backend-neutral execution persistence helpers for Alma. Part of the fixed compatible workspace version group.
Core owns UsageInbox contracts. This package owns closed snapshot validation:
normalizeUsageInboxInput, normalizeUsageInboxRecord, normalizeUsageInboxQuery.
./testing exports the volatile InMemoryUsageInbox(now?) reference, without
vitest. PostgreSQL owns durable SQL and row-level security. Loop owns enforcement.
Usage preservation
Append the original trusted execution snapshot, event id and evidence before journal receive. Exact replay retains first receipt time and never recreates acknowledged work; changed input conflicts even after acknowledgement. A different observation has a different event id, including contradictory evidence for one call. No charge is deduplicated by event id: authoritative call/settlement identity belongs to the journal and accounting store.
list includes immutable history; listPending includes unacknowledged work.
Both use default 50/max 100 pages and an exclusive after: { receivedAt, id }.
Start each reconciliation pass from the beginning; never persist a high-water
checkpoint, which would lose late commits. Paging lets unresolved items stay
pending without hiding later work. Corrupt rows fail loudly; repair is an operator
concern, never silently omitted accounting evidence.
Exactly one logical recovery consumer owns acknowledgement, with potentially competing workers. Acknowledge only after durable recovery/disposition. This is work completion, never proof of charging. Compare the complete execution binding with the authoritative journal and make recovery idempotent before acknowledging. Catch append, journal receive and acknowledgement errors separately. A stale fence cannot authorize acknowledgement, another provider call or invented zero usage.
The inbox stores no prompts, replies, raw errors or SDK objects and changes no journal, financial counter or provider state. Unknown/unpriced evidence stays unresolved. Metadata survives session/result erasure indefinitely; there is no retention or operator-correction API yet. Hosts supply scope inventory and drains.
See durable usage inbox.
Governed financial receipts
GovernedCostSettlementStore adds transactional monetary decisions to the ordinary
cost receipt. financialDecisions uses actual locked pre/post session/day amounts,
strict > thresholds and explicit normalized warn/block policies. Warn decisions
never withhold output here. Ordinary capsCrossed stays warn-only; block evidence
is separate. normalizeGovernedSettlementInput and normalizeGovernedCostReceipt
reject content keys, invalid amounts and inconsistent derived decisions.
InMemoryGovernedCostSettlementStore in ./testing owns one volatile state for
legacy and governed writes. A separately constructed reference owns separate
counters. The PostgreSQL adapter shares its durable counters with the existing
spend/settlement tables. Never run legacy accounting alongside a governed call.
One governed operation is one call: operation/call uniqueness prevents double
accounting under another settlement id. This API is not yet suitable for a
multi-call turn. Replays return original decisions; mode, policy or identity
changes conflict. getGoverned, listGoverned and pendingGoverned include the
full immutable request and decisions. Generic readers retain ordinary receipts.
Use distinct projection consumer IDs by mode, or drain both pending APIs. The
existing acknowledgement removes work only; retrying settlement never recreates it.
Governed receipts persist indefinitely, including after projection acknowledgement
and content erasure. Runner continuation, preflight and operator correction follow.
Financial cap and receipt normalization now comes from core, shared with governed
journal inputs. To advance that journal after settlement, explicitly project the
closed proof: journal.settle(fence, {request: governed.request, receipt: governed.receipt}).
The extra decisions field is intentionally not accepted by the journal boundary.
The volatile governed settlement reference exposes read-only peek(SpendKey) over
its own counters. Pair this with governed runner preflight; a separate memory spend
store does not see governed charges. PostgreSQL's paired adapters share tables.
Durable operation lineage
OperationTreeStore binds main/direct/delegate/summary calls to one scoped root
(spec: durable-operation-lineage). claim returns a fence only once; equal replay
returns a record without authority. reserve snapshots a complete execution under
a stable slot, checks root scope/session/policy/caps/sensitivity/deadline, and
requires a prior same-root parent for non-main calls. Scoped call/settlement IDs
and operation keys cannot belong to two roots. Ordinals start at1 and maxCalls is
1..512; pages default50/max100. close stops new reservations, with idempotent
repeat by the same fence. Expiry refuses admission before or after a bounded
reconcileExpired sweep; no takeover or renewed execution token is issued.
InMemoryOperationTreeStore is exported from /testing without vitest. The durable
adapter is PostgresOperationTreeStore in @alma-harness/postgres-execution.
Records are defensive copies, exclude tokens and contain closed metadata only.
Root closure is not cost settlement, result persistence or delivery. No runner
adopts this prerequisite yet; aggregate accounting follows separately.
Root financial receipts
OperationAccountingStore.record(scope, rootKey, callId) adopts the registered
call's original governed receipt into an inclusive root summary, without invoking
any financial writer. Missing settlements return pending; known receipts must
match reserved identity, policy and saved pricing. get returns bounded warning
evidence and totals; list pages in accounting order, distinct from reservation
order. Each root/cap warning is recorded once, and exact retries return the same
receipt. Per-turn decisions use inclusive root cost; persistent decisions retain
the original financial receipt totals, even if accounted out of order.
The memory reference takes trusted tree/getGoverned capabilities. PostgreSQL uses its own atomic aggregate transaction after the original financial settlement. Repair this boundary by recording the call again, including after root closure or expiry; never dispatch again. Root totals are not additional billable rows. Warning transport and runtime enforcement remain later host/runner responsibilities (spec: root-financial-receipts).
Session admission uses OperationSessionStore and the memory reference
InMemoryOperationSessionStore from execution/testing. Claim before creating
the operation root. The first claimant receives the only fence; equal replay
returns metadata. A different root is busy until the owner finishes cleanly.
Expiry and uncertainty preserve occupancy. Explicit operator resolution requires
external effects and writes reconciled and prior workers quiescent; runners must
never call it automatically. This store alone does not integrate the conversation
loop. See the governed-session-admission spec.
A summary may reserve a root-level call before the first main call, omitting
parentCallId. It is a real metered call and consumes a root ordinal/slot.
Main remains parentless; direct/delegate require prior same-root parents.
Parented summaries retain those same prior-parent checks. Deploy matching readers
before enabling this representation (spec: prelude-summary-lineage).
Roots and admissions optionally bind a closed request descriptor:
{inputRevision, configRevision, resultContractVersion, resultRetentionMs}.
All fields become immutable at first claim; adding/removing it later conflicts.
The host resolves revisions for the complete incoming request and configuration,
including intent/profile/trigger and all prompt/tool/hook/price/limit choices.
Legacy records keep absence. Conversation adoption must require this binding and
reserve final output before loading content. Final output belongs to the scoped
root key in a separate root-result namespace, never a fabricated billable call or
an unchecked step-result key. No result reservation or loop wiring is implemented
by this descriptor alone (spec: conversation-root-binding).
Durable batch submission
BatchSubmissionStore and InMemoryBatchSubmissionStore (execution/testing)
retain a closed, ordered manifest before provider work. Claim returns the only
fence; replay has metadata only. beginDispatch grants dispatch: true once.
Only that response permits a future adopting runner to submit; a lost ACK,
expiry or repeated call never grants another attempt. accept binds the original
provider/model handle once; late evidence retains reconciliation_required and
never renews authority. markUncertain is irreversible and preserves the handle.
Manifest items carry normalized governed batch-tier execution snapshots. They are pricing/identity metadata, not claims in the synchronous ExecutionStore. Recovery of batch item evidence needs a separate adopting protocol; synchronous recovery cannot receive unknown late results after expiry. Use scope/key lookups before any future provider access. Raw handles from callers are not authorization. Configuration revisions must identify immutable host configuration, including provider account selection. The store accepts only a trusted owner's handle observation; it cannot authenticate a provider's receipt by itself.
Claims bind 1..512 items and at most 2 MiB of normalized UTF-8 JSON; a future
submission deadline must be within one hour. This deadline governs submission,
not how long the provider may process a batch. get returns a defensive manifest;
list returns summaries without item arrays, in exclusive ASCII key pages
(default50/max100). Metadata and charge identities remain retained indefinitely.
No provider calls, cancellation, collection, cost writes or routine adoption are
implemented by this storage prerequisite (spec: durable-batch-submission).
SingleDispatchBatchClient is the additive transport seam for the governed
batch runner. It returns independent BatchItemEvidence and content, not legacy
JobResult usage coupled to content success. Every submit invocation is a new
attempt; ownership remains in BatchSubmissionStore. Its once-consumable
submitEvidence iterable exposes OpenAI input_file evidence before accepted.
The host may save the file reference before resuming create; abandonment stops
there. Optional cancel(handle, opts?) requests cancellation once and returns
observed JobProgress; absence means unsupported. An acknowledgement cannot prove
terminal processing. The batch package resolves original scoped handles for
status/cancel and separately adopts collection/accounting (spec 128).
Batch usage journal
BatchUsageStore persists immutable financial observations under scope/batch/id;
InMemoryBatchUsageStore lives in /testing. Append requires the exact accepted
handle and manifest item, including after deadline/uncertainty. The store obtains
the execution snapshot itself. Different observation IDs retain contradictory
metadata; equal replay preserves the original timestamp, and changed input
conflicts. Known evidence admits only batch billing. Unknown/unpriced remains
pending; not_dispatched and content-bearing payloads are rejected.
batchUsageSettlement(record) derives the original governed request when evidence
is known and priceable. Persist first, call settleGoverned idempotently, then
recordSettlement to adopt the actual source receipt. Adoption performs no monetary
write. Multiple matching observations can share that one charge; contradictory
ones cannot replace it. No observation acknowledges provider EOF or output delivery.
List pages default50/max100 in exclusive ASCII observation-ID order. Restart pending drains from the first page to catch late lower IDs. Metadata and adopted receipts survive indefinitely; unknown/unpriced/conflicting observations need explicit reconciliation. No provider access, lease, dispatch token, output store or automatic operator resolution is introduced (spec: durable-batch-usage).
Inclusive batch accounting
BatchAccountingStore adopts an already journaled governed receipt once per
manifest item. InMemoryBatchAccountingStore is the volatile reference. Record
by scoped batch key and observation ID; even alternate-observation replay needs a
matching adopted source. Unknown/unpriced observations remain pending. Only the
original settlement writes money; aggregate receipts never increment counters.
PerTurnUsd compares the inclusive batch total. Persistent session/day decisions keep original source pre/post amounts even when items are adopted out of order. Warn crossings are retained once per cap/batch; block decisions remain evidence for the adopting runner. Record accepts late repair without renewing dispatch.
Get returns bounded original warnings, total and expected/accounted item counts; list pages in accounting order (default50/max100), retaining manifest position separately. All records are defensive and content-free. Financial completeness is not proof of provider EOF, output availability, delivery or resolved contradictory observations (spec: batch-financial-summary).
Usage inbox normalization binds the synchronous Anthropic context-rejection proof to its original provider. Batch usage cannot carry that synchronous attestation (spec: safe-context-rejection-rotation).
