@alma-harness/execution

中文文档
0.41.0发布于 2026/11/04Apache-2.0TypeScriptES Module零依赖近 30 天下载 3170

Durable execution persistence helpers for Alma.

原始使用文档
文档目录8 节
  1. Usage preservation
  2. Governed financial receipts
  3. Durable operation lineage
  4. Root financial receipts
  5. Durable batch submission
  6. Batch usage journal
  7. Inclusive batch accounting
  8. Scope fence

@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 or the admission is released. Expiry and uncertainty alone do not free a session. 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.

releaseFailed(scope, rootKey) releases one uncertain admission at once, whatever its deadline, with failedReleaseId(rootKey): turn-failed-v1: and the SHA-256 of the key, in hex (spec: failed-turn-release). The conversation runner calls it before it returns reconciliation_required, after marking the admission uncertain, which a turn's fenced appends wait for. The application may call it. An active admission is refused; a released one returns its record when its id is this one, and conflicts otherwise. Custom stores must implement it.

releaseExpiredEvents(scope, sessionId) is the one automatic release (spec: conversation-events): an admission whose key starts with EVENT_ADMISSION_PREFIX, past its deadline, active or reconciliation_required, released with eventReleaseId(key). An active one is released too since an event's append is fenced on its admission (spec: fenced-event-append), so the host needs no reconcileExpired, which would also mark the scope's expired turns uncertain. It never touches a turn's admission, and the application may call it. Custom stores must implement it.

releaseExpired(scope, { limit }) releases, oldest deadline first, the scope's uncertain admissions whose deadline is EXPIRED_RELEASE_MARGIN_MS (fifteen minutes) past by the store's clock, with expiredReleaseId(rootKey): expired-release-v1: and the SHA-256 of the key, in hex (spec: expired-turn-release). The application may call it, and maintenance does. A concurrent release is not an error. Custom stores must implement it.

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).

not_submitted is terminal: dispatch was never granted and never will be, so a host may start a new batch with new identities at no risk of paying twice. Two paths reach it. reconcileExpired(scope, {limit?}) needs no fence and moves, once the stored deadline has passed by the store's clock, prepared to not_submitted and dispatching to reconciliation_required (default50/max100 per call, in deadline then key order). markUncertain on a prepared record records not_submitted; after a dispatch grant it still records uncertainty. Deploy readers that know the state before either writer runs (spec: batch-not-submitted).

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). Optional discard(handle, opts?) deletes a finished batch's copies at the provider and returns discarded, or requests cancellation of a running one and returns pending; absence means the provider's own expiry bounds them (spec: provider-batch-retention).

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).

Scope fence

ScopeFenceStore fences a scope {org, uid} permanently (spec: scope-fence): fence(scope, { actionId, actor }) returns { status, record }, and the first record wins, so a later call returns it as existing. get(scope) reads it. No method lifts a fence. A gated store refuses new authority for a fenced scope with ScopeFencedError, which carries neither content nor the fence's actor. normalizeScopeFenceInput and normalizeScopeFence validate the closed shapes. ./testing exports InMemoryScopeFenceStore(now?), whose synchronous assertOpen(scope) lets an in-memory gate check and insert atomically.

版本与发布记录

@alma-harness/execution 共发布 47 个版本,首次发布于 2026/09/09;过去 12 个月发布了 47 个版本。

版本发布日期距今
0.41.0latest2026/11/043 天前
0.40.02026/10/308 天前
0.39.22026/10/309 天前
0.39.12026/10/299 天前
0.39.02026/10/299 天前
0.38.02026/10/2910 天前

关于 @alma-harness/execution 的常见问题

@alma-harness/execution 是什么?

Durable execution persistence helpers for Alma.

如何安装 @alma-harness/execution?

在项目目录运行 npm install @alma-harness/execution,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@alma-harness/core(^0.41.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@alma-harness/execution 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@alma-harness/execution 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@alma-harness/execution 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@alma-harness/execution 可以商用吗?

@alma-harness/execution 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@alma-harness/execution 的下载量有多少?

根据 npm 官方下载统计,@alma-harness/execution 在 2026/10/06 – 2026/11/04 这 30 天内被下载 3,170 次,日均约 106 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@alma-harness/execution 还在维护吗?

最新版本 0.41.0 发布于 2026/11/04(3 天前);至今共发布 47 个版本,其中过去 12 个月发布了 47 个;首次发布于 2026/09/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。