Implements the mongodb-superpowers-package design: Stable Tasks 1-50 and Advanced Tasks 1-15. The design assumes 19 Stable + 12 Advanced Gradle projects under modules/mongodb*. This repository's fail-closed registry declares exactly 19 leaf identities, so those modules become package boundaries inside the registered leaf :adapter:outbound:persistence-mongo, with the design's module dependency table enforced by ten ArchUnit rules. The mapping and every deviation are recorded in docs/mongodb/repository-adaptation.md. Contract highlights, all enforced by tests rather than convention: - Transaction body retry and commit retry are separate loops. A new session per body attempt; commit-only retry on an unknown commit. The body is never replayed after a commit ambiguity, so a failover cannot become a duplicate. - MongoExecutionOutcome keeps both ambiguous outcomes distinct from success and failure, and MongoFailureContext records only the design-permitted fields. - Failure classification reads server error labels before numeric codes. - BSON representations come from a pinned manifest, never a library default, and a golden type-signature gate fails on any drift. - Index and validator changes go through the manifest and the admin plane; metadata ownership gates every drop. - Every Advanced capability refuses construction unless its flag is enabled. Verified against real servers, not only unit tests. Running the lanes for the first time exposed four defects that a green `check` had hidden: - Four release lanes passed while executing zero tests; the gate now counts executed tests per lane and fails on zero. - The "single replica set" fixture was a standalone, because Testcontainers 2.x needs withReplicaSet(); its test only asserted a connection string. - The three-node fixture was three independent clusters, so no election could occur, and awaitNewPrimary() compared against the post-stop primary. - The migration lease checked modifiedCount, so a same-millisecond refresh read as a lost lease. scripts/verify-mongodb-platform.sh now reports: 9 lanes, 0 skipped, 0 failed, every evidence category produced. scripts/verify-mongodb-advanced.sh reports NOT PROMOTABLE: actual-topology evidence (real sharded cluster, real KMS, real target deployment) is unobtainable here, so it is named rather than assumed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.1 KiB
title, category, severity, owner, last_updated, status
| title | category | severity | owner | last_updated | status |
|---|---|---|---|---|---|
| Runbook — MongoDB unknown transaction commit result | mongodb | P1 | oncall | 2026-08-13 | active |
Runbook: unknown transaction commit result
Design §16, decision D-10, scenario UNKNOWN_TRANSACTION_COMMIT_RESULT.
MongoExecutionOutcome.TRANSACTION_COMMIT_UNKNOWN means the commit may have applied. It is not a
failure and must never be reported to a caller as one. The single worst response is to re-run the
transaction body: if the commit did apply, the body applies a second time.
Symptoms
MongoTransactionCommitUnknownExceptionin logs.- Metric
failureCategory=TRANSACTION_COMMIT_UNKNOWN. - Usually accompanies a primary election — see failover.md.
- Downstream reports of duplicated effects (double charge, double increment) are the symptom of this being handled wrongly, not of the condition itself.
Diagnosis
-
Confirm the platform did the right thing automatically.
MongoTransactionRetryCoordinatorretries the commit only, on the same session, withinMongoRetryBudget. A commit retry against an already-committed transaction is a no-op by design. Most occurrences resolve here and never reach a human. -
If the budget was exhausted, determine the actual state. The commit either applied or it did not; you must find out which, not guess.
- If the transaction body wrote a deterministic marker (an idempotency key, a business id, a
revision), read it back. That is exactly what
MongoCommitReconcilerdoes, and it is the reason the design requires transactions to write one. - If there is no marker: reconstruct from a downstream artefact — an outbox row, an audit record, an external side effect. If nothing exists to compare against, the transaction was not designed to be reconcilable and that is the finding to record.
- If the transaction body wrote a deterministic marker (an idempotency key, a business id, a
revision), read it back. That is exactly what
-
Check whether the body was replayed. Grep for a second execution with the same operation name and correlation id. If the body ran twice, the effects need reversing, and the code path that replayed it is a defect: an ambiguous commit is
COMMIT_ONLYscope (MongoRetryScope.COMMIT_ONLY), neverBODY.
Action
Commit applied. Nothing to do. Record the reconciliation.
Commit did not apply. Re-run the whole operation from the top — a new session, a new body attempt. This is safe precisely because you established the previous attempt left no trace.
Cannot determine. Do not retry. Escalate. A blind retry here is a coin flip between "no effect" and "duplicate effect", and duplicates in a financial or notification path are worse than a delay. Freeze the affected entity if the domain supports it, and hand off with: operation name, correlation id, document id, the time window, and what you checked.
Recurring. More than one an hour means the commit path is racing something structural — a
maxCommitTime shorter than the observed election duration, an oversized transaction, or an
undersized retry budget. Fix the budget or the transaction shape; do not raise the retry count and
call it resolved.
Prevention
- Every transaction body writes a deterministic marker that identifies its own commit.
maxCommitTimeexceeds the observed p99 election duration.- Callers surface the ambiguity to their own callers rather than mapping it to a generic 500 — an ambiguous outcome reported as a failure invites the caller to retry, which is the one thing that must not happen.
- Prefer a single-document atomic operation (D-09). A transaction that exists only to wrap one document write has invented this failure mode for nothing.
Escalation
- Always P1 when the state cannot be determined and the operation has an external effect.
- Page the service owner immediately; the database owner only if elections are the trigger.
Verification
cd src
./gradlew :adapter:outbound:persistence-mongo:mongoFailoverTest --console=plain
MongoFailoverScenario.UNKNOWN_TRANSACTION_COMMIT_RESULT runs this path against a real three-node
set, and the coordinator test asserts the body is never replayed after a commit ambiguity.