@alma-harness/postgres-execution
PostgreSQL operation lineage (spec: durable-operation-lineage). This additive
package depends on the matching core, execution and postgres release; it
reuses the shared scoped transaction, role and statement-timeout helpers.
migrateOperationTreeStore(pool) installs the current execution shape helper and
alma_operation_roots/alma_operation_calls. PostgresOperationTreeStore(pool, ScopedStoreOptions?) implements the neutral OperationTreeStore from execution.
Default transactions SET LOCAL ROLE alma_app and bind org/uid with a 30s timeout.
An explicit null role retains the existing host opt-out from role switching.
Migration needs the same privileged migration connection as postgres; runtime
connections use limited login membership via grantRole. The migrations upgrade a
database last migrated by one of the two previous minor releases, and rerunning
them changes nothing (spec: upgrade-window).
Claim a root once; only its first claimant receives an opaque fence. Reserve stable main/direct/delegate/summary slots before dispatch. Root/child scope, session, policy, caps, sensitivity and deadline must agree. Parent links stay within a root. SQL locks serialize ordinals; a trigger validates root admission and updates membership count atomically. Lost acknowledgements are resolved by scoped reads or equal reservation replay, never a new root execution authority.
A root claim INSERT uniqueness failure permits one read after rollback and connection
release. Only an exactly equal normalized binding returns existing, without a
fence; a closed or expired winner gains no renewed authority. Readback failures,
other SQL errors and COMMIT uncertainty remain errors. Mapped errors retain the
original PostgreSQL cause non-enumerably for trusted diagnostics; do not serialize
that cause into client output or routine logs (spec: operation-tree-claim-readback).
Expired roots cannot reserve even before reconcileExpired(scope) marks them for
reconciliation. The bounded sweep skips locked roots. close stops admission;
it does not mean accounting or delivery completed. listCalls pages by ordinal,
default50/max100, with at most512 members per root. Reads never return the fence
token. Metadata is content-free and retained; no deletion or takeover API exists.
Governed conversation and step runners bind these reservations before egress. Lineage itself creates no billable cost rows.
Scope fence (spec: scope-fence). The tree, session and batch migrations add
the postgres package's fence trigger to alma_operation_roots,
alma_operation_admissions and alma_batch_submissions. A fenced scope's new
root, admission or submission is refused with ScopeFencedError, by any
writer. The fence also authorizes releasing an uncertain admission of its
scope: releaseFenced(scope, { limit }) releases them as the application
role, with the fence's action id as their resolution (spec: scope-erasure). A
scope without a fence is released at once by releaseFailed(scope, rootKey),
as any role, with failedReleaseId(rootKey) (spec: failed-turn-release); by the
operator's resolve; or, once an uncertain admission's deadline is fifteen
minutes past by the database clock, by anyone through releaseExpired(scope, { limit }) with the id derived from its key (spec: expired-turn-release). The
trigger recomputes both derived ids from the key; and for a
recorded event's admission: releaseExpiredEvents(scope, sessionId) releases,
as the application role, one in the conversation-event-v1: namespace that is
past its deadline by the database clock and without an operation root, marking
an active one uncertain first (spec: fenced-event-append). The admission trigger checks all of it, and a CHECK on
alma_operation_roots refuses any root under an event key, so no writer can
release a turn this way (spec: conversation-events). Rerun migrateOperationSessionStore, then
verify the catalog again.
Root financial accounting
migrateOperationAccountingStore composes lineage and governed-cost migrations.
PostgresOperationAccountingStore reads actual governed receipts by registered
call identity and writes only alma_operation_financial_calls and
alma_operation_warnings. A root lock serializes accounting ordinals and totals;
SQL verifies financial associations and exact decision metadata, and inserts
warning evidence atomically. Source cost rows/counters are never incremented.
The source settlement and aggregate are separate transactions. Lost aggregate acknowledgements replay the stored receipt; missing aggregates can be repaired without root dispatch authority, including after closure/expiry. Scoped FKs retain the source governed rows; ordinary cost retention already preserves those rows. Summary counts do not certify completion or external delivery. Out-of-order root accounting uses original session/day amounts; root warnings are immutable evidence, not a notification outbox (spec: root-financial-receipts).
migrateOperationSessionStore(pool) installs scoped session lock rows and immutable
admissions. PostgresOperationSessionStore serializes claims across connections;
a partial unique index permits only one unfinished admission per scoped session.
Deadlines mark uncertainty without granting takeover. Finish requires the original
fence before expiry; its replay remains stable. Operator resolution has a separate
receipt and cannot be replayed as an owner finish.
Normal operations assume alma_app; explicit resolve assumes the separately
configured operatorRole (default alma_retention) with membership required and
FORCE RLS still active. Grant that membership only to the trusted reconciliation
host. Migration accepts matching role/operatorRole. Do not invoke resolution
from a runner, sweeper or timeout handler; the runner's own release is
releaseFailed, under the application role. Admit before root creation; a crash
between those transactions leaves the session occupied until the expired release. Deploy
matching readers and roles before adoption; admission itself includes no automatic retention. See the governed-session-admission spec.
Summaries may have no parent (prelude summaries). Scoped parent FKs and lower-ordinal checks remain.
Conversation request descriptors roundtrip through both admission input and the
nullable root request column. New SQL checks validate closed bounded metadata;
a root UPDATE trigger protects original binding fields while allowing existing
status/count changes. A root without a descriptor stays valid. No fabricated
revisions, content rows or charges are created (spec: conversation-root-binding).
Batch submission ownership
migrateBatchSubmissionStore adds alma_batch_submissions and alma_batch_items;
PostgresBatchSubmissionStore implements the execution package's neutral contract.
The parent insert creates the complete membership through a SQL trigger in the
same transaction. Scoped operation/call/settlement uniqueness and immutable JSON
bindings prevent reassociation. FORCE RLS covers both org and uid; use the ordinary
limited login with alma_app membership and statement-timeout settings. Runtime
gets no delete grants or ownership reset API.
SQL guards reject expired new dispatch, reverse transitions and acceptance without a prior dispatch marker. The clock is sampled after row locks. A late handle stays available under reconciliation; acceptance is not batch completion, accounting or permission to submit again. Scoped reads never expose the original fence token. SQL access remains a trusted host capability, as with existing fenced stores.
not_submitted (spec: batch-not-submitted) is reached only from prepared, never
carries a dispatch marker, acceptance or handle, and no UPDATE leaves it. The
versioned alma_batch_transition_v2() owns the trigger. Without the fence, only two transitions are allowed, and only once the stored deadline has
passed by clock_timestamp() after the row lock: prepared to not_submitted and
dispatching to reconciliation_required. reconcileExpired skips rows another
transaction holds.
A claim INSERT uniqueness failure is read back once after transaction cleanup,
in a fresh scoped transaction. Only an identical complete normalized manifest
returns existing; no fence is recovered and the INSERT is never retried.
Missing or changed bindings still conflict; unrelated errors and lost COMMIT
acknowledgements cannot enable this path (spec: batch-claim-readback).
Mapped batch conflict/state errors retain the original SQL error in non-enumerable
cause, including any constraint/detail supplied by PostgreSQL. These diagnostics
are for trusted inspection only: they may contain scoped identifiers. Do not
serialize causes into client responses or automatically log the entire error.
Install the additive migration before constructing the adapter. Rerunning the current migrations preserves populated records. Input normalization caps manifests at 2 MiB; SQL additionally bounds JSONB text to 4 MiB because its numeric/whitespace encoding differs. All recursive metadata shapes are closed; content must use a separate result store. No automatic retention, provider access, collection, settlement or routine integration is included.
migrateBatchUsageStore composes batch and governed settlement migrations and
adds alma_batch_usage. PostgresBatchUsageStore uses the normal scoped limited
login and timeout options. SQL binds observations to the accepted handle/member,
checks closed evidence, and permits only a one-way association to an existing
matching governed cost. FORCE RLS and scoped FKs protect observations and source
receipt retention; app receives no delete grant. Readers validate complete saved
pricing and receipt consistency, failing on corrupt metadata.
Receipt adoption locks the observation first, then reads its joined receipt in a fresh SQL statement: a statement snapshot taken before a competing adoption must not mix the new association with old joined data. Lost append, settlement and adoption acknowledgements replay the same identities. The adapter never increments spend or invokes a provider. Install the additive migration before new readers; populated repeated upgrades preserve records. See execution's batch usage journal contract; content, valid EOF, collection completion and delivery remain separate. The SQL association guard also computes the frozen batch price, including highest applicable prompt band, cache fallback/one-hour rates and provider search charges. Parity tests compare its amount with core pricing; a matching identity/usage receipt with a different monetary amount cannot make an observation unreadable or resolved.
migrateBatchAccountingStore adds alma_batch_financial_items and
alma_batch_warnings on top of the batch usage migrations.
PostgresBatchAccountingStore uses the same limited scoped connection options.
A batch row lock serializes accounting ordinals and inclusive totals; item and
warning inserts commit atomically. Unique scoped item keys prevent two observations
from contributing twice. SQL checks the adopted observation, source amount,
manifest position and exact decisions/warning set. App grants are SELECT/INSERT
only; scoped FKs protect source observations. Populated upgrade replay is supported.
The adapter never writes monetary counters or cost rows and grants no execution
or channel-delivery authority.
SQL validators and triggers that depend on Alma objects pin their invoker path to
pg_catalog, installation_schema, pg_temp. Install in a trusted schema and rerun
current migrations before backup; old startup SQL may replace function settings.
This preserves CHECK evaluation during pg_restore and prevents caller-path shadows.
Tool selection in nested execution.controls.toolChoice remains part of each immutable call or batch item. Run both migrateOperationTreeStore and migrateBatchSubmissionStore before writing choices. Rerunning both migrations, in either order, keeps existing records and constraint identities. A changed choice conflicts with the original call slot or batch manifest and does not authorize another dispatch.
Session labels
migrateSessionLabelStore(pool) adds alma_session_labels; PostgresSessionLabelStore
implements core's SessionLabelStore under FORCE RLS with the standard scoped
options (spec: session-labels). A CHECK validates the label shape and the
available/erased state; a trigger freezes row identity and creation, allows only
available → erased and makes tombstones terminal. The row with an empty
session ID is the scope seal. alma_app gets SELECT/INSERT/UPDATE, never DELETE.
Every write takes a per-scope advisory lock, so put and erase serialize. The insert trigger takes the same lock, refuses labels in a sealed scope, and refuses to run outside read committed, since an older snapshot would miss a seal committed while it waited.