The direct answer

A stable snapshot does not serialize two aggregate capacity decisions. For the selected all-Serializable profile, retain confirmed serialization failures and reconsider the entire transaction’s business decision on a bounded fresh attempt. Never replay only a stale final write or classify an unknown commit as an abort.

Ask whether the combined decision can occur in a serial order

A fictional AI service maintains internal capacity metadata in two rows. Each worker checks the total and changes only its own row. Both workers use a database transaction, yet that fact alone does not establish that their combined decisions preserve the intended limit.

This worksheet selects fixed trusted PostgreSQL 18 read-check-write logic, exclusively owned transaction boundaries and database-local metadata only. It accepts no generated SQL, custom functions or external side effects. The existing budget guide still requires shared atomic admission; this page examines what an isolation label does and does not supply for one particular aggregate check.

All relevant writers, admitted operations and serial business rules must be independently established. A transaction that is wrong when run alone does not become correct by choosing a stricter isolation level.

Separate a stable view from serial execution

PostgreSQL 18’s isolation chapter explains that Repeatable Read provides a stable view but permits serialization anomalies. Serializable emulates serial execution for committed transactions and monitors dependencies that can trigger serialization failures. Its guarantees require the application’s serial logic to be correct; a read result from a later-aborted transaction cannot be treated as accepted evidence.

Our selected write profile is separate from the existing ordinary read-view worksheet. Its Repeatable Read choice remains unchanged for that declared purpose. Here the question is whether concurrent decisions over several rows can both be admitted, not whether two content reads describe one revision.

No installed server, effective session mode, query implementation or transaction owner was inspected. Those remain actual prerequisites, with unknowns blocking a real operation. This article supplies no isolation-setting statement or alternative locking recipe.

Place both reads before either distinct-row write

Invent capacity pool P-A with a limit of one unit and row values A=0 and B=0. Each transaction’s trusted rule is to admit one unit only if the total plus one does not exceed the limit. T-A changes only row A; T-B changes only row B. There is no separate shared gate or database constraint enforcing the aggregate in this paper profile.

Original declared schedule — PROPOSED_UNRUN
StepT-AT-B
1. Before either writer changes dataReads A=0, B=0; total0.Reads A=0, B=0; total0.
2. Each applies the fixed ruleOwn proposal fits the observed limit.Own proposal fits the observed limit.
3. Separate targetsChanges A to1.Changes B to1.
4. Hypothetical both-commit outcomeCombined A=1, B=1; total2 violates limit1.

This is a conditional application of the documented anomaly allowance, not a captured database result. The two writes target different rows, so avoiding a same-row write collision does not itself protect the total. Additional constraints, locks or changed operations would be another profile requiring its own review.

No serial order of this declared correct check admits both units: whichever transaction runs second would see the first accepted unit and decline. Under the selected all-Serializable plan, do not require both attempts to succeed or promise which one receives an error. Keep supported failure and commit evidence separate.

Retry the decision rather than its final write

The PostgreSQL 18 failure-handling chapter identifies serialization failures by SQLSTATE 40001. It requires retrying the complete transaction, including application logic choosing statements and values. PostgreSQL provides no automatic retry facility guaranteeing correctness, and retry does not guarantee completion.

For this worksheet, only a supported, confirmed serialization-failure disposition is eligible for a separately authorized bounded retry review. Require the actual adapter to establish the failed outer transaction’s disposition and the new attempt’s ownership. A timeout or lost commit response is not that confirmed abort.

Suppose a later complete attempt sees that the other unit was committed. Its new total is one, so the original rule declines the additional unit. Carrying an old “eligible” Boolean into the new attempt, or repeating only the write chosen from that Boolean, would skip the business decision the retry must reconsider.

Our application policy also requires a declared attempt and resource budget. This is a stricter operational boundary, not a documented automatic scheduler. Budget exhaustion holds the workflow; no sleep loop, reduced isolation or different lock key is offered as a recovery path.

Keep an invariant-and-attempt receipt

Original protected receipt — PROPOSED_UNRUN
FieldEvidence needed
Business scopeP-A, complete relevant state, limit revision and correct serial admission rule.
ParticipantsAll invariant-relevant transactions and supported effective selected profile.
Attempt associationExclusive session, owned outer transaction and fresh read/decision/write association.
OutcomeSupported commit, confirmed serialization failure or unresolved result, kept distinct.
Retry and later useComplete reconsideration, remaining work budget, current rights and independent downstream authority.

The conditional positive records only an admitted database-local capacity change after supported actual commit and every independent prerequisite. It does not authorize a model call, job lease, payment or message. A database reservation and a later external effect remain different boundaries.

The outer-transaction worksheet remains effective: a helper’s normal return or completed savepoint is not the missing main-transaction outcome. This guide supplies no driver or pool implementation.

Review eight inert decisions and the remaining limits

All eight cards PROPOSED_UNRUN
Invented conditionProposed disposition
1. Every prerequisite, fresh decision and supported commit holdConditionally record only the bounded local reservation.
2. The Repeatable Read paper schedule admits both rowsRecognize the possible broken aggregate; one transaction per worker was insufficient.
3. A confirmed selected serialization failure occursReview only a bounded complete-transaction retry.
4. A fresh attempt observes full capacityDecline under the unchanged business rule.
5. The old eligibility decision is reusedReject incomplete reconsideration.
6. A relevant writer bypasses the profile or ruleHold the claimed invariant.
7. Commit result is lost instead of a confirmed abortPreserve uncertainty; no automatic replay classification.
8. Rights, actual mode, outer ownership or work budget is unknownWithhold the affected operation independently.

Actual business logic, participant coverage, numeric bounds, supported database/adapter behavior, transaction outcome evidence, retry resources and current rights are unknown or unimplemented here. They block a real positive. No fairness, guaranteed completion, global integrity, crash persistence or exactly-once external effect is established.

No SQL, connection, row, schema, transaction, lock, error object, database, runtime fixture, API or model operation was constructed or executed. Boundary is prelaunch with planned request checks; its synthetic policy evidence does not implement this capacity coordinator.

Primary sources

Official references supporting the guidance. Examples in this guide are synthetic and are not reports of a production incident.

  1. PostgreSQL 18 — Transaction Isolation
  2. PostgreSQL 18 — Serialization Failure Handling