Expand description
PostgreSQL schema contract and transaction orchestration for Syrup Rail.
Production service construction must not expose or invoke a migrator; host applications materialize versioned install artifacts as immutable migrations.
§syrup-rail-postgres
syrup-rail-postgres provides Syrup Rail’s canonical provider-neutral ledger,
SQLx operations, and high-level subscription billing service. Version 0.5
supports PostgreSQL 18 only and uses schema v4.
[dependencies]
syrup-rail = "0.5.0"
syrup-rail-postgres = "0.5.0"New hosts install schema/v4/install.sql through their normal migration
system. Existing schema-v3 hosts separately commit
schema/v4/prepare_from_v3.sql and schema/v4/validate_from_v3.sql, run
schema/v4/index_from_v3.sql outside a transaction, and finally commit
schema/v4/upgrade_from_v3.sql while following the versioned cutover guide.
Schemas v1, v2, and v3 are immutable. The detailed versioned guides explain
the required lock, maintenance, and rehearsal boundaries.
After the host applies its migration and before it serves billing traffic, verify the runtime catalog:
syrup_rail_postgres::assert_runtime_schema_v4_compatible(pool).await?;During REINDEX CONCURRENTLY, PostgreSQL exposes the command, phase, and
target details only to the maintenance role and statistics-privileged roles.
The runtime assertion tolerates _ccnew and _ccold shadows only when those
visible progress details and the backend’s relation locks agree, then rechecks
the evidence before committing. Run maintenance and startup validation as the
same database role when startup must remain available during a reindex; a
cross-role observer fails closed. Drop stale invalid shadows left by failed
maintenance before serving billing traffic.
SubscriptionBillingService is the primary mutation facade. Hosts supply
offer locking, gateway resolution, abuse admission, and a transaction
coordinator that locks the authorized billing subject first and appends every
typed BillingEvent to the host outbox on the same connection. The packaged
host_integration example includes concrete service wiring and a versioned,
redacted host-owned event-envelope mapping. It separates first-write metadata
from the replay-stable value and demonstrates the complete atomic
insert/conflict-read/raw-structural-comparison/typed-reconstruction path on the
same transaction. Version 1 owns its nested enum labels instead of delegating
them to core display methods. The example keeps subject identifiers and
payload values out of Debug output; its card payload uses the core canonical
brand vocabulary and never copies an unknown provider string into the host
event.
The service requires a live gateway account by default. A host exercising a
dedicated test environment can call
with_required_gateway_account_mode(GatewayAccountMode::Test) to require an
exact test account instead. That setting permits test-mode mutations but still
rejects an observed live account before submission; bind it only to trusted
deployment configuration. A single NMI account can therefore be used only for
a carefully serialized staging/live cutover, but NMI mode lookup and sale are
separate requests and a Merchant Portal user can change the same account-wide
switch out of process. Use separate NMI test and production merchant accounts
when test/live isolation matters. The service performs an early account-mode
query before final admission and a mandatory second query immediately before
provider submission. The second query narrows the race window and makes the
safety check structural for supported low-level submitters; it cannot make two
NMI requests atomic. Initial enrollments and prepared host-charge replays change
from query → mutation to query → query → mutation, roughly 50% more provider
requests for those flows. Renewals, recoveries, payment-method replacements,
and fresh host charges already performed a final readiness query, so their
request counts do not increase. A transient failure of the new final query
occurs after durable admission, but the provider mutation endpoint was not
contacted. Resumable enrollment, recovery, payment-method replacement, and
host-charge attempts are therefore atomically restored to prepared state and
can retry with the same command and idempotency key. Automatic renewal retains
terminal not-submitted handling because its scheduler does not resume prepared
attempts.
Approved enrollments also persist the required mode on the subscription.
Renewal dispatches expose it for host routing, and renewal, recovery, and
payment-method replacement reservations reject a service configured for the
other mode before creating new provider work. A mode-specific scheduler should
use due_renewals_page_for_mode; the returned cursor records that mode and
rejects cross-mode reuse. Its dedicated mode-leading index filters before the
bounded SQL page limit. The unfiltered
due_renewals_page remains available to a central router that owns both modes.
Entitlement queries and guards default to live paid subscriptions; test workers
select Test, while trusted administrative tooling can opt into both modes
with across_gateway_account_modes. Current-subscription, portal, and history
projections remain mode-neutral, so a host that mixes modes must enforce its
own trusted production access partition around those reads.
Supported low-level provider submission functions consume an opaque
ModeVerifiedGateway created by verify_gateway_account_mode; they do not
accept a raw gateway. The value captures early readiness and the expected mode,
then revalidates that mode when consumed. A successful test-mode capability
still executes the real NMI API request, whose processing is controlled by
NMI’s account-wide TEST mode.
All matching reservation constructors require the trusted account mode
explicitly rather than defaulting to live.
When a transient final mode query restores a host charge for same-key retry,
HostChargeTargetStore::ensure_submission_admitted is invoked again for that
attempt.
Hosts must make that callback repeat-safe and reserve one-shot paid/failed
business effects for apply_transition.
Terminal host-charge replay and prepared replay owned by the other deployment
mode resolve by idempotency before HostChargeTargetStore::preflight_target.
A same-mode prepared replay invokes the snapshot callback again so a changed
target charge becomes an idempotency conflict before gateway I/O.
Errors returned by host transaction, event, charge-target, and operator-review
callbacks remain opaque through ordinary formatting and the standard
Error::source() chain. A host can deliberately recover its original callback
error only by classifying the outer service error, destructuring an owned
callback-error variant, and consuming that wrapper with into_source() in a
protected diagnostic path.
GatewayReadiness can be returned after a token-free attempt was committed.
At that boundary, transient unavailability leaves the attempt pending for the
same-key retry, while determinate readiness failures first persist their exact
terminal resolution. Replaying the same command and idempotency key returns or
resumes the canonical attempt before host admission or gateway I/O; an error is
not permission to substitute a new key.
§Reconciliation phase order
The host owns the reconciliation scheduler. For each account returned by
reconciliation_gateway_accounts, run the local-only cleanup phases before
calling claim_exact_reconciliation_attempts:
fail_stale_unsubmitted_payment_method_replacements;fail_stale_unsubmitted_subscription_charges;fail_stale_unsubmitted_subscription_enrollments; andfail_stale_unsubmitted_host_chargeswhen host charges are configured.
The host-charge phase also requires the host’s HostChargeTargetStore; it
releases the host-owned target and fails the canonical attempt in one database
transaction. Local cleanup never contacts the gateway. The cleanup functions
are safe to repeat, and the bounded phases should run on every scheduled pass
so locked work or a backlog is retried later. Exact provider queries are only
for attempts whose submitted_at proves that submission began.
fail_stale_unsubmitted_host_charges returns failed and skipped counts. A
StaleTarget, Unchanged, concurrent change, or contended-row outcome leaves
the target and financial attempt state untouched, increments skipped, and
does not prevent later candidates from progressing. Candidate selection uses
the attempt’s updated_at as a durable scheduling claim, so previously skipped
rows sort behind unclaimed work and become retryable after the claim interval.
The host callback should record the target-specific incident for operator
follow-up; the account scheduler can continue its remaining local and exact
reconciliation phases.
An existing 0.2.0 host must add the subscription-charge phase, plus the
host-charge phase when host charges are configured, to its reconciliation loop
when upgrading to 0.3.0. Omitting them leaves abandoned local
rows for foreground reads or later cleanup even though exact reconciliation
correctly excludes never-submitted attempts. The existing enrollment phase also
repairs never-submitted initial attempts that 0.2.0 may already have parked as
review_required. The schema-v3 cutover separately preserves historical
combined attempt names as canonical first-name values and adds lossless
last-name persistence for new attempts.
Customer billing portal/history queries, stable due-renewal pagination, and other lower-level transaction-local operations remain available for hosts that need to compose them into a larger application transaction. The protected-write guard described below deliberately owns its top-level transaction instead. Authentication, authorization, migrations, job queues, and event transport remain host-owned.
Protected product writes use two ownership-enforced phases. Start an
EntitlementWriteTransaction from the pool and use its connection for any
preparatory host writes; that pending value has no commit operation.
require_entitlement_for_update returns an
AdmittedEntitlementWriteTransaction only when current paid or granted access
is admitted and keeps the relevant locks held for the host mutation. Completed
denials and SQL failures await rollback, while cancellation queues rollback of
the owned transaction, including any earlier host writes. Perform and commit
the host-owned protected mutation only through the admitted value, and finish
any nested savepoint before consuming that value with commit or rollback.
This package is proprietary software distributed under the terms in the
packaged LICENSE file.
Structs§
- Admitted
Entitlement Write Transaction - A top-level transaction that passed entitlement admission.
- Admitted
Host Charge - Admitted
Subscription Enrollment - One committed final-admission result that authorizes exactly one immediate provider submission by consuming this value.
- Admitted
Subscription Payment Method Replacement - One committed final-admission result authorizing exactly one immediate Customer Vault mutation.
- Admitted
Subscription Recovery - One committed final-admission result authorizing exactly one immediate subscription-recovery submission.
- Admitted
Subscription Renewal - One committed final-admission result authorizing exactly one immediate automatic recurring charge.
- Billing
Event Write Error - Value-redacted failure returned while appending a host outbox event.
- Billing
Transaction Error - Value-redacted failure returned by the host transaction coordinator.
- Entitlement
Write Transaction - A top-level PostgreSQL transaction awaiting entitlement admission.
- External
Reversal Host Store Error - Value-redacted failure returned by the host’s reversal target store.
- Gateway
Lifecycle Quarantine Alert - Gateway
Lifecycle Quarantine Resolution Record - Gateway
Lifecycle Quarantine Review Record - Gateway
Lifecycle Reconciliation Summary - Host
Charge Ledger Admission Query - Host
Charge Submission Admission - Host
Charge Target Error - Value-redacted failure returned by the host charge-target store.
- Host
Charge Target Reservation - Manual
Attempt Failure Host Store Error - Value-redacted failure returned by the host’s manual-failure store.
- Mode
Verified Gateway - Opaque readiness capability for a resolved gateway and required account mode.
- Processor
Charge Classification Summary - Stale
Host Charge Cleanup Summary - Outcome of one bounded stale host-charge cleanup page.
- Subscription
Billing Service - High-level provider-neutral billing facade for authorized host commands.
- Subscription
Enrollment Offer Context - Stable identity and lifecycle context for locking an enrollment offer.
Enums§
- Billing
Transaction Subject State - Durable availability of the host recipient locked for a billing event.
- Compensating
Processor Charge Outcome - Entitlement
Guard Error - Entitlement
Query Error - Exact
Query Observation - External
Reversal Attestation Outcome - External
Reversal Host Transition Outcome - Gateway
Account Mode Verification Error - Why a resolved gateway could not be authorized for a provider submission.
- Gateway
Lifecycle Apply Outcome - Gateway
Lifecycle Quarantine Resolution Outcome - Gateway
Lifecycle Reconciliation Error - Gateway
Mutation Cooldown Scope - Canonical cooldown level that stopped a gateway mutation before submission.
- Host
Charge Admission Outcome - Host
Charge Application Error - Host
Charge Ledger Admission - Host
Charge Ledger Admission Error - Host
Charge Ledger Admission Mode - Host
Charge Preflight Outcome - Host
Charge Provider Result - Host
Charge Reservation Decision - Host
Charge Reservation Outcome - Host
Charge Store Error - Host
Charge Submission Decision - Host
Charge Submission Outcome - Manual
Attempt Failure Host Transition Outcome - Operator
Review Error - Payment
Attempt Store Error - Processor
Charge Observation Outcome - Processor
Charge Store Error - Renewal
Store Error - Schema
Conformance Error - Why a host database does not satisfy a canonical schema contract.
- Subscription
Billing Portal Query Error - Error returned while loading a customer-facing billing portal projection.
- Subscription
Billing Service Error - Failure returned by the high-level subscription billing facade.
- Subscription
Billing Service Error Disposition - A stable, conservative operational category for a
SubscriptionBillingServiceError. - Subscription
Cancellation Error - Subscription
Discount Operation Error - Subscription
Enrollment Admission Outcome - Subscription
Enrollment Application Error - Subscription
Enrollment Offer Stage - The lifecycle boundary at which enrollment terms are locked.
- Subscription
Enrollment Provider Result - Subscription
Grant Mutation Error - Subscription
Payment Method Replacement Admission Outcome - Subscription
Payment Method Replacement Provider Result - Subscription
Recovery Admission Outcome - Subscription
Recovery Provider Result - Subscription
Renewal Admission Outcome - Subscription
Renewal Provider Result
Constants§
- SUPPORTED_
POSTGRES_ MAJOR_ VERSION - The only PostgreSQL major version supported by this crate and schema contract.
Traits§
- Billing
Transaction - One host-owned transaction and its typed event projection capability.
- Billing
Transaction Coordinator - Host-prepared transaction whose subject authorization lock is acquired before any shared billing lock.
- External
Reversal Host Store - Host
Charge Target Store - Host-owned target extension composed into shared ledger transactions.
- Manual
Attempt Failure Host Store - Subscription
Offer Store
Functions§
- activate_
gateway_ configuration - Activates an exact gateway configuration without touching cooldown state.
- admit_
host_ charge_ submission - admit_
host_ charge_ submission_ in_ transaction - admit_
subscription_ enrollment_ submission - Owns and commits final enrollment admission before exposing a one-shot
submission capability. A rolled-back transaction can never yield the
capability consumed by
submit_admitted_subscription_enrollment. - admit_
subscription_ enrollment_ submission_ in_ transaction - Revalidates a prepared initial attempt and durably admits its one provider mutation.
- admit_
subscription_ payment_ method_ replacement - Commits final payment-method replacement admission before exposing its one-shot Customer Vault capability.
- admit_
subscription_ payment_ method_ replacement_ in_ transaction - Revalidates the exact subscription baseline and commits one-shot Customer Vault admission. Semantic drift terminalizes the prepared attempt.
- admit_
subscription_ recovery_ submission - Commits final recovery admission before exposing its one-shot capability.
- admit_
subscription_ recovery_ submission_ in_ transaction - Revalidates the exact locked snapshot and commits one-shot provider admission. Every semantic rejection terminalizes the prepared attempt.
- admit_
subscription_ renewal_ submission - Commits final automatic-renewal admission and captures the exact stored credential.
- admit_
subscription_ renewal_ submission_ in_ transaction - Revalidates one exact renewal snapshot and commits one-shot submission admission.
- apply_
exact_ query_ observation - Applies one authoritative negative exact-query observation.
- apply_
gateway_ lifecycle_ evidence - Applies one lifecycle observation.
- apply_
host_ charge_ gateway_ outcome - apply_
reconciled_ host_ charge_ gateway_ outcome - apply_
reconciled_ subscription_ enrollment_ gateway_ outcome - Applies an already-observed provider outcome to an exact durable enrollment attempt.
- apply_
reconciled_ subscription_ payment_ method_ replacement_ gateway_ outcome - apply_
reconciled_ subscription_ recovery_ gateway_ outcome - Re-enters the same recovery application authority from durable evidence and never resolves a live gateway or submits another mutation.
- apply_
reconciled_ subscription_ renewal_ gateway_ outcome - apply_
staged_ gateway_ lifecycle_ evidence - apply_
subscription_ enrollment_ gateway_ outcome - Applies one initial-enrollment gateway outcome to the durable billing ledger.
- apply_
subscription_ payment_ method_ replacement_ gateway_ outcome - apply_
subscription_ recovery_ gateway_ outcome - Applies one recovery outcome through the canonical charge ledger and host billing transaction.
- apply_
subscription_ renewal_ gateway_ outcome - assert_
runtime_ schema_ v4_ compatible - Asserts that a host database is compatible with the canonical schema-v4 contract before the host accepts billing work.
- attempt_
review_ page - attest_
external_ reversal - billing_
deletion_ blockers - Reports the canonical financial rows that prevent host account deletion.
- cancel_
subscription_ in_ transaction - Cancels one exact scope/subscriber/plan subscription inside the caller’s transaction.
- claim_
exact_ reconciliation_ attempts - Claims one bounded, account-scoped batch for authoritative exact queries.
- claim_
gateway_ lifecycle_ quarantine_ alert - claim_
subscription_ discount - claim_
subscription_ discount_ in_ transaction - classify_
pending_ processor_ charges - Classifies one bounded batch of durable pending processor charges.
- clear_
subscription_ discount - clear_
subscription_ discount_ in_ transaction - create_
subscription_ discount_ code - create_
subscription_ discount_ code_ in_ transaction - Creates an active durable code after validating its terms against the
locked current offer. The returned value is the administrative record; use
validate_subscription_discount_code_in_transactionto obtain a quote. - create_
subscription_ grant - Creates a grant inside the caller’s transaction.
- disable_
subscription_ discount_ code - disable_
subscription_ discount_ code_ in_ transaction - Disables an administrative record even when its historical terms are no longer quoteable against the host’s current offer.
- due_
renewals - Returns the first deterministic, provider-neutral renewal dispatch page.
- due_
renewals_ for_ mode - Returns the first deterministic renewal page for one deployment mode.
- due_
renewals_ page - Returns one deterministic page of renewal work due in a stable scan.
- due_
renewals_ page_ for_ mode - Returns one deterministic page of renewal work for one deployment mode.
- entitlement
- Loads one exact scope/subscriber/plan entitlement from a single database snapshot.
- fail_
review_ required_ attempt - fail_
stale_ unsubmitted_ host_ charges - Fails one bounded account-scoped batch of stale local host charges.
- fail_
stale_ unsubmitted_ payment_ method_ replacements - Fails one bounded batch of stale payment-method replacements for an account.
- fail_
stale_ unsubmitted_ subscription_ charges - Fails one bounded batch of stale local renewal and recovery attempts.
- fail_
stale_ unsubmitted_ subscription_ enrollments - Expires every stale prepared enrollment for one account.
- find_
payment_ attempt_ by_ id_ in_ transaction - Loads an attempt by its exact scope and durable identity without locking it.
- gateway_
lifecycle_ quarantine_ review_ page - gateway_
lifecycle_ reconciliation_ start - host_
charge_ ledger_ admission - list_
subscription_ discount_ codes - list_
subscription_ discount_ codes_ in_ transaction - Lists durable administrative records without reinterpreting them against
the current offer. Quote eligibility is intentionally owned by
validate_subscription_discount_code_in_transaction. - lock_
payment_ attempt_ by_ idempotency_ in_ transaction - Locks the exact owner-scoped idempotency row for replay or mutation.
- mark_
subscription_ discount_ claim_ applied_ in_ transaction - observe_
processor_ charge_ in_ transaction - preflight_
host_ charge_ in_ transaction - preflight_
subscription_ enrollment_ in_ transaction - Resolves subscriber-wide enrollment idempotency before host admission.
- preflight_
subscription_ payment_ method_ replacement_ in_ transaction - Resolves payment-method replacement idempotency before host admission.
- preflight_
subscription_ recovery_ in_ transaction - Resolves subscriber-wide recovery idempotency before host admission.
- processor_
charge_ review_ page - reconcile_
gateway_ transaction_ reports - reconciliation_
gateway_ accounts - Returns every registered gateway account in deterministic locator order.
- record_
gateway_ lifecycle_ quarantines - register_
gateway_ account - Registers canonical gateway metadata on the caller’s connection.
- renewal_
attempt_ state - Computes the one shared renewal/recovery period ledger state.
- require_
entitlement_ for_ update - Locks and revalidates one exact entitlement inside a top-level transaction.
- reserve_
host_ charge_ in_ transaction - reserve_
subscription_ enrollment_ in_ transaction - Reserves or resumes one exact-plan initial enrollment inside the caller’s transaction.
- reserve_
subscription_ payment_ method_ replacement_ in_ transaction - Locks the exact subscription baseline and reserves a token-free replacement attempt before Customer Vault I/O.
- reserve_
subscription_ recovery_ in_ transaction - Locks the canonical subscription, derives the exact due-period request, and inserts a token-free recovery attempt in one transaction.
- reserve_
subscription_ renewal_ in_ transaction - Locks one exact due subscription and inserts its automatic-renewal attempt.
- resolve_
gateway_ lifecycle_ quarantine - revoke_
subscription_ grant - Revokes an exact grant inside the caller’s transaction.
- save_
gateway_ lifecycle_ reconciliation_ cursor - saved_
subscription_ discount_ claim - saved_
subscription_ discount_ claim_ in_ transaction - scrub_
subscriber_ billing_ data - Removes the canonical mutable billing PII for one subscriber.
- stage_
gateway_ lifecycle_ evidence - store_
compensating_ processor_ charge - submit_
admitted_ host_ charge - submit_
admitted_ subscription_ enrollment - Performs the one provider sale authorized by a committed final admission, then applies or durably parks its result.
- submit_
admitted_ subscription_ payment_ method_ replacement - Performs the one Customer Vault mutation authorized by committed admission.
- submit_
admitted_ subscription_ recovery - Performs the one provider sale authorized by committed recovery admission, then applies or durably parks its result without holding a database lock across provider I/O.
- submit_
admitted_ subscription_ renewal - Performs the one recurring sale authorized by committed renewal admission.
- subscription_
billing_ portal - Loads a provider-neutral customer billing portal from one PostgreSQL snapshot.
- subscription_
payment_ history_ page - Returns one strict descending page of exact-plan subscription payment history.
- transition_
processor_ charge_ in_ transaction - update_
subscription_ discount_ code - update_
subscription_ discount_ code_ in_ transaction - Updates a durable administrative record. Active records are validated against the locked current offer. Disabled records remain administrable without requiring their historical terms to be quoteable today.
- validate_
subscription_ discount_ code - validate_
subscription_ discount_ code_ in_ transaction - verify_
gateway_ account_ mode - Queries the real provider account and mints one readiness capability only when its observed mode exactly matches the trusted required mode. Consuming the capability for submission performs another account-mode query.