Sub-scope 06 (mongo) transaction (+retry, +session) — manifest and negative-space probes revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-29T23:59:14+00:00 cwd=/shared/codebase/clean-architecture-backend-template/src === OWNED FILES === 873cb3db4ee900e7638124c59f6091948fbfd0f6 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionExecutor.java 23 23a83b409d3e42360e212b7899f04a96ec5dacce main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionProfile.java 77 9ae3e814bfc78daccebc1b0dce2a3ef953f834f8 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionScope.java 86 1d0b146c9ba9268d8dd7ec8cb6e4c50b4c6bb7f8 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionSession.java 43 d5937274e6f7ac95abf66459dd5b728e5e5d3316 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionSessionFactory.java 15 bef7501ef1742d8114f289f1c44ff1f25f209906 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/ReactiveMongoTransactionExecutor.java 31 ffe70abd80b87c2fb0dd2f69e96cff659f34b026 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/ReactiveMongoTransactionSession.java 38 7cb9136000f9746a9bb33e3c4357148498fb1e0e main/java/dev/caskeleton/adapter/outbound/mongo/transaction/ReactiveMongoTransactionSessionFactory.java 16 5f96fa86ea42eab9306cc73f02feccf7f6683e88 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringMongoTransactionExecutor.java 59 92bda406cc21352893e4b9a839eac8163ea153ae main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringMongoTransactionSessionFactory.java 263 6d96b51eb94a60f92fe251a9b0452430bc0f3b49 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringReactiveMongoTransactionExecutor.java 175 b6ef0091d7849f646e8949b2cfa3da3c21791a8f main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringReactiveMongoTransactionSessionFactory.java 214 dfb46a08cb5d404e721005514cf0f98900da6d8a main/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/MongoCommitReconciler.java 27 b6df5b2ebf39793d5dc8bf38c222e59069b46b9a main/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/MongoRetryBudget.java 80 692a21a115dfa0ea183c625bb5653a96025016b5 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/MongoRetryDecision.java 68 028037fa1a84eea4b12018d906d801aac0d2dd85 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/MongoTransactionRetryCoordinator.java 189 774883c35befc8249cfadc1a7ae5de9c45a6fdbb main/java/dev/caskeleton/adapter/outbound/mongo/transaction/session/MongoCausalSessionContext.java 49 8a25a7c246398a8a1bded005280c6d2c6ca6a290 main/java/dev/caskeleton/adapter/outbound/mongo/transaction/session/MongoCausalSessionExecutor.java 16 795c67ae7615f079513485cd5041ed388215b6ca main/java/dev/caskeleton/adapter/outbound/mongo/transaction/session/ReactiveMongoCausalSessionExecutor.java 69 806d3be20120b8e599ea97a967fb342fc9e8fa4e main/java/dev/caskeleton/adapter/outbound/mongo/transaction/session/SpringMongoCausalSessionExecutor.java 79 0e1323f4abb3933a88d1b6c9fb78457feda4c7be test/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoSessionAcquisitionTest.java 77 30619b8f143dc38c06fa5123f34768823edc58ba test/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionProfileTest.java 55 c56553a2d953a98df8d0d7772a9d33a8084903b7 test/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionScopeTest.java 76 344c75f520992801a82a926afdb29437a6980fef test/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringReactiveMongoTransactionExecutorTest.java 236 22d6be5d8e4222d45e01a631887da99bcccc6616 test/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/CleanupFailureIsReportedTest.java 156 2fde8127fa3874c2a81bb00d2275f645d3d5edaa test/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/MongoTransactionRetryCoordinatorTest.java 220 f49adb300b1efa68e93e3f07e1e993bac13ca6bf test/java/dev/caskeleton/adapter/outbound/mongo/transaction/session/MongoCausalSessionExecutorTest.java 43 production: 20 test: 7 production LOC: 1617 total === 8.1 reachability: transaction beans and cross-package production references === $ grep -n 'Transaction\|CausalSession\|RetryCoordinator' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java exit=1 $ git grep -n 'MongoTransactionExecutor\|MongoTransactionRetryCoordinator\|SpringMongoTransactionSessionFactory\|MongoCausalSessionExecutor\|MongoTransactionScope\|ReactiveMongoTransactionExecutor' -- 'adapter/outbound/persistence-mongo/src/main' | grep -v '/transaction/' exit=1 === 8.1b the transactions flag: what it gates and what it does not compose === $ grep -n 'transactionsEnabled' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoStartupValidator.java 32: private final boolean transactionsEnabled; 43: boolean transactionsEnabled, 50: this.transactionsEnabled = transactionsEnabled; 97: if (transactionsEnabled && !capabilities.isStable(MongoCapability.TRANSACTION)) { exit=0 $ grep -n 'properties.transactions()' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformAutoConfiguration.java 362: properties.transactions(), exit=0 $ grep -n 'boolean transactions' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/autoconfigure/MongoPlatformSettings.java 29: boolean transactions, exit=0 === 8.2 the central rule: body retry and commit retry are separate loops === $ grep -n 'catch (MongoTransactionTransientException transientFailure)' -A 6 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/MongoTransactionRetryCoordinator.java 87: } catch (MongoTransactionTransientException transientFailure) { 88- lastTransient = transientFailure; 89- decisionRecorder.accept( 90- MongoRetryDecision.retryBody(budget.delayBefore(attempt + 1, random))); 91- continue; 92- } 93- return commitWithRetry(session, value, startedAt); exit=0 $ grep -n 'private T commitWithRetry' -A 8 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/retry/MongoTransactionRetryCoordinator.java 145: private T commitWithRetry(MongoTransactionSession session, T value, long startedAt) { 146- MongoTransactionCommitUnknownException lastUnknown = null; 147- for (int commitAttempt = 1; 148- budget.allowsAttempt(commitAttempt, elapsedSince(startedAt)); 149- commitAttempt++) { 150- sleep(budget.delayBefore(commitAttempt, random)); 151- try { 152- session.commit(); 153- return value; exit=0 $ grep -n 'MongoTransactionCommitUnknownException' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringReactiveMongoTransactionExecutor.java 4:import dev.caskeleton.adapter.outbound.mongo.api.error.MongoTransactionCommitUnknownException; 130: failure instanceof MongoTransactionCommitUnknownException 155: MongoTransactionCommitUnknownException.class, 160: new MongoTransactionCommitUnknownException( exit=0 === 8.2b why MongoTransactionManager / TransactionTemplate are not used === $ grep -n 'Deliberately not built on' -A 3 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/SpringMongoTransactionSessionFactory.java 32: *

Deliberately not built on {@code MongoTransactionManager} or {@code TransactionTemplate}. Both 33- * commit implicitly when the callback returns, which collapses body and commit into one step — and 34- * the whole design rests on those two steps failing differently and being retried differently. 35- * exit=0 === 8.3 scope binding: nested bind restores rather than clears === $ grep -n 'Registration bind' -B 8 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionScope.java 46- * Binds operations for the current thread and returns what undoes it. 47- * 48- *

Binding used to be {@code set} and unbinding {@code remove}, which is only correct when 49- * scopes never nest. They do: an outer transaction body that calls a second transactional 50- * component ran an inner bind, and the inner {@code remove} left the outer body with nothing 51- * bound — so every subsequent {@code require()} in the outer body failed, and any code that fell 52- * back to an ordinary template wrote outside the transaction it believed it was in. 53- */ 54: static Registration bind(MongoOperations operations) { exit=0 $ grep -n 'ThreadLocal' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionScope.java adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/session/SpringMongoCausalSessionExecutor.java adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionScope.java:20: private static final ThreadLocal CURRENT = new ThreadLocal<>(); adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/session/SpringMongoCausalSessionExecutor.java:21: private static final ThreadLocal CURRENT = new ThreadLocal<>(); exit=0 === 8.4 profile bounds === $ grep -n 'SERVER_LIFETIME_LIMIT' -A 4 adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionProfile.java 23: public static final Duration SERVER_LIFETIME_LIMIT = Duration.ofSeconds(60); 24- 25- public MongoTransactionProfile { 26- Objects.requireNonNull(consistency, "consistency"); 27- Objects.requireNonNull(timeout, "timeout"); -- 38: if (timeout.compareTo(SERVER_LIFETIME_LIMIT) > 0) { 39- throw new IllegalArgumentException( 40- "a transaction timeout of " 41- + timeout 42- + " exceeds the server's default lifetime limit of " 43: + SERVER_LIFETIME_LIMIT); 44- } 45- if (maxAttempts < 1) { 46- throw new IllegalArgumentException("maxAttempts must be at least 1"); 47- } exit=0 $ grep -n 'STALE_READ_ALLOWED\|staleReadsPossible\|readsFromSecondary' adapter/outbound/persistence-mongo/src/main/java/dev/caskeleton/adapter/outbound/mongo/transaction/MongoTransactionProfile.java 12: * transaction's snapshot, and neither is what the caller who wrote {@code STALE_READ_ALLOWED} 29: if (consistency == MongoConsistencyProfile.STALE_READ_ALLOWED) { 32: + MongoConsistencyProfile.STALE_READ_ALLOWED exit=0