- Shipped
- September 5, 2026 at 6:53 PM UTC
- Author
- Kamo
- Commit
- ed8db28
MemberRightsAppliedService carried @RetryOnDbConflict on its WRITE entry points only. The class therefore read as covered while the two methods the authenticated surface actually calls stood bare, and a catalog-version bump kept reaching users through them. On 2026-09-05 it reached them at the worst possible place — the sign-in screen, which showed: Login failed: JDBC exception executing SQL [select d1_0.id,d1_0.email, d1_0.mailbox_id,o1_0.id,... from depts d1_0 left join (orgs o1_0 left join org_mtg o1_1 ...)] [ERROR: schema version mismatch for table **************** expected 160, got 158] The path is create***Id -> **************** which loads the member and then dereferences TeamMember.department. That dereference is LAZY, so it is a SELECT of its own, and it is the statement the bump lands on. It runs before the session is minted, so the whole sign-in fails rather than degrading — the member is simply told the login failed, with several hundred columns of generated SQL for company. computeMemberRights is the same story one endpoint over. SessionRefreshController polls it on a short interval for every signed-in client, which made it the most frequent victim in the same window: 12 of the 70 conflicts logged fleet-wide over six hours came through it. Both overloads of each are annotated. The by-id overloads reach the by-entity ones through self-invocation, which bypasses the proxy, so an attempt is still three attempts and not nine. Not a retry around **************** which would have covered the same failure in one line. That method mints a session, issues an MFA token, stamps last-login and publishes availability; none of that rolls back with the transaction, so running it twice is exactly what @RetryOnDbConflict's own documentation says not to do. The reads are pure, which is why the retry belongs on them. The test asserts through a real Spring proxy rather than calling the helper directly: an annotation that is present but not applied looks identical to one that is working. Removing the four annotations fails both tests with the CannotAcquireLockException from the report. 2778 tests green.