[LegalMind] Non-atomic user/identity creation locks out users on partial failure
In localAuth.ts, createLocalUser() and createIdentity() are separate database operations without a transaction wrapping them. If createIdentity fails after createLocalUser succe...
StateDoneNext ActionClosedOwnerLuciRuntimeClosedAge29d ago
Ticket is done; runtime is closed.·profile claude_opus_1m_medium · cwd /home/lucienne/workspace · uptime 29d 3h · last activity 29d 1h ago
Description
MC-3440
In localAuth.ts, createLocalUser() and createIdentity() are separate database operations without a transaction wrapping them. If createIdentity fails after createLocalUser succeeds (e.g., DB connection error), a user row exists with a password but no identity record. Subsequent registration attempts with the same email permanently fail with 409 'Email already registered', irrecoverably locking the user out. Both operations should run inside a single database transaction so neither persists on partial failure.
File: server/auth/localAuth.ts:266
Complexity: medium
Found by: nightly code review (3a243848 Merge pull request #401 from conrelma/fix/mc-3430-bundle-extra-page-end)
Activity
done
INTERACTIVE
Luci is working...
Details —
Done
· Medium
· Luci
▼
SState
Done
Closed
PPeople
TTiming / Details▼
legalmind-review (scheduled)
LegalMind
29d ago
16d ago
Advanced / Operator evidence
RRouting owner
ROperator console
Ticket is done; runtime is closed.ticket_marked_doneprofile claude_opus_1m_medium · cwd /home/lucienne/workspace · uptime 29d 3h · last activity 29d 1h agoMC is visibility-only. Hermes Luci launches and gates work outside MC, then mirrors evidence/status here.
a68d5121-04ca-4f98-a425-04e0df68f3a4 · luci · claude/anthropic/opus[1m]
WWorkflow
Start Dev Review + QA ▾
Select phases to include:
Agents
Review Gates
Decision
WAT routing: choose an agent, review gate, or decision. Buttons use the live runtime when one is attached.
Luci dispatching this ticket to Larry (background worker via SSH).
luci29d ago
Larry: Planning — reading ticket and codebase contextPROGRESS: Designing — wrapping createLocalUser + createIdentity in a single DB transactionPROGRESS: Building — adding transactional createLocalUserWithIdentity to authStorage and using it in registerNow update localAuth.ts to use the transactional method.PROGRESS: Testing — running typecheck and unit testsMy edits got reverted. Re-applying them.Good, edits in place. Now run typecheck on auth files only.No type errors in auth/. Pre-existing errors elsewhere are unrelated. Now run the test suite.I need to update the existing MC-2856 test (it mocks the now-replaced methods) and add a regression test for MC-3440.Now add a regression test for MC-3440:All 5 tests pass. Let me also run the full auth test suite to ensure no other regression.All 10 auth tests pass. Commit and push.
luci29d ago
Larry: Done — atomic createLocalUserWithIdentity wraps both inserts in a single transactionFixed MC-3440 by introducing `authStorage.createLocalUserWithIdentity()` — wraps the user insert and the local-identity insert in a single `db.transaction()`. Updated `/api/register` in `server/auth/localAuth.ts:266` to use it, so a transient failure on the identity insert now rolls back the user row instead of leaving an orphan that permanently locks the email out with 409. Added regression test `mc3440-register-atomic.test.ts` and updated `mc2856-register-race.test.ts`; all 10 auth tests pass. Branch `feat/mc-3441` (auto-named by env hook) pushed to origin with commit `9ed300b`.
luci29d ago
Completed on Larry:
reading ticket and codebase contextPROGRESS: Designing — wrapping createLocalUser + createIdentity in a single DB transactionPROGRESS: Building — adding transactional createLocalUserWithIdentity to authStorage and using it in registerNow update localAuth.ts to use the transactional method.PROGRESS: Testing — running typecheck and unit testsMy edits got reverted. Re-applying them.Good, edits in place. Now run typecheck on auth files only.No type errors in auth/. Pre-existing errors elsewhere are unrelated. Now run the test suite.I need to update the existing MC-2856 test (it mocks the now-replaced methods) and add a regression test for MC-3440.Now add a regression test for MC-3440:All 5 tests pass. Let me also run the full auth test suite to ensure no other regression.All 10 auth tests pass. Commit and push.
PROGRESS: Done — atomic createLocalUserWithIdentity wraps both inserts in a single transactionFixed MC-3440 by introducing `authStorage.createLocalUserWithIdentity()` — wraps the user insert and the local-identity insert in a single `db.transaction()`. Updated `/api/register` in `server/auth/localAuth.ts:266` to use it, so a transient failure on the identity insert now rolls back the user row instead of leaving an orphan that permanently locks the email out with 409. Added regression test `mc3440-register-atomic.test.ts` and updated `mc2856-register-race.test.ts`; all 10 auth tests pass. Branch `feat/mc-3441` (auto-named by env hook) pushed to origin with commit `9ed300b`.
luci29d ago
Larry: Triggering post-completion code review...
luci29d ago
Code review (Larry reviewer via claude/opus):
the route's MC-2856 mapping depends on it.
MINOR: server/auth/__
tests__/mc3440-register-atomic.test.ts — diff tru
ncated at line 44 of 140 so I couldn't ver
ify the full test body, but the setup mirrors the MC-2856 m
ock shape correctly and the intent (ass
ert atomic method is called, separate `create
Identity` is not) is sound.
VERDICT: PASS
Implementation looks clean. Transaction wraps both inserts; route swapped to atomic method; existing race test updated.
MC-3440 fix review: register route now uses `createLocalUserWithIdentity`, wrapping user + identity inserts in a single transaction so a failed identity insert no longer leaves an orphan user that 409-locks the email.
MINOR: server/auth/storage.ts:211 — the old `createLocalUser` is now unused by route code but still on `IAuthStorage`. Either remove or annotate as deprecated to prevent future misuse. Not blocking.
MINOR: server/auth/storage.ts:235-264 — no try/catch to remap the unique-violation; the route still handles `23505` correctly because Postgres surfaces the constraint error through the transaction promise, but worth a brief inline comment confirming that behavior since the route's MC-2856 mapping depends on it.
MINOR: server/auth/__tests__/mc3440-register-atomic.test.ts — diff truncated at line 44 of 140 so I couldn't verify the full test body, but the setup mirrors the MC-2856 mock shape correctly and the intent (assert atomic method is called, separate `createIdentity` is not) is sound.
VERDICT: PASS
luci29d ago
Larry shipped with clean code review. Auto-dispatching Luci-reviewer (verdict: clean). Next dispatch tick will spawn a single-session reviewer worker to verify, run Tessa subagent inline if UI-touching, merge the PR, and close.
luci29d ago
External runtime/provider failure; auto-retry suppressed.
API Error: Request rejected (429) · The service may be temporarily overloaded, please try again later
luci-operator29d ago
Luci Operator: promoted this assigned `inbox` ticket to `todo` so pickup can run it.