The baseline award was two transactions, not one

FixSecurityService
Shipped
September 7, 2026 at 5:22 AM UTC
Author
Kamo
Commit
9d30f75

`ensureBaselineFor` calls `ensureBaseline` on `this`, and Spring's transaction advice is a PROXY — a self-invocation does not pass through it, so the inner REQUIRES_NEW never applied. Called from the controller, which holds no transaction, the award therefore ran with none: the state row and the unlock row each committed in their own implicit repository transaction. A failure between the two leaves a member holding an achievement they will never be told about — the cabinet says they have it and the queue has nothing to show them, which is the one inconsistency this feature's two-table shape exists to make impossible. Annotating the outer method is the whole fix. The inner call then joins that transaction, which makes the pair atomic and puts the afterCommit publish on the commit that actually matters. MemberCreationService was never affected: that is a cross-bean call, so the proxy applies and REQUIRES_NEW does what it says — a badge that cannot be written must not roll back the member who was just created.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing