$ mvn -pl cqrs test -Dtest=AsyncProfileStalenessWindowTest (async-projection profile -- AsyncOrderSummaryProjection active; @Async hands the same write off to a separate thread instead of running it inline. A throwaway warm-up POST runs first and is not measured: the first HTTP request against a freshly started test context pays Hikari/Hibernate first-use costs that have nothing to do with this profile's actual behaviour -- measuring that cold first request directly made POST /orders look like it took ~370ms even in this profile, which would have buried the exact thing the test exists to show.) 2026-10-04T02:27:31.206+05:30 INFO 17346 --- [cqrs] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:cqrs-write user=SA 2026-10-04T02:27:32.304+05:30 INFO 17346 --- [cqrs] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-2 - Added connection conn10: url=jdbc:h2:mem:cqrs-read user=SA POST /orders (async profile) took 14 ms, orderId=8451a829-7ef6-4d19-b839-2d9ce5885437 Immediately after POST returned (inside the staleness window), GET /order-summaries/8451a829-7ef6-4d19-b839-2d9ce5885437 -> status=404 NOT_FOUND, body=null After waiting for the projection (outside the staleness window), GET /order-summaries/8451a829-7ef6-4d19-b839-2d9ce5885437 -> status=200 OK, body=OrderSummary[orderId=8451a829-7ef6-4d19-b839-2d9ce5885437, customerName=Dev, itemCount=1, totalCents=8999, status=PLACED, updatedAt=2026-10-03T20:57:33.971972Z] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 This is the trade-off in one transcript, warmed-up and measured honestly. The identical command, in the identical module, against the identical 300ms simulated write cost, took 14ms here instead of 670ms -- because the projection's write moved to another thread and the HTTP response stopped waiting for it. The price is the 404 on the very next line: a client that queries in that window, a few dozen milliseconds wide in this run, gets a "not found" for an order that was just placed successfully. Only after the test waits (Awaitility, polling every 50ms, up to 2 seconds) does the same GET return 200 with the order correctly summarized. Neither profile is "more correct" than the other; they are the same correctness guarantee, paid for at a different point in the request.