The prior fixes closed the common cases with pre-checks; this closes the
residual races by consuming the single-use gate token(s) AND creating the
user AND persisting keys in ONE transaction, so a failure never burns a
token without an account.
- New Database::create_user_consuming_gates: claims the invite + consumes
the payment invoice + inserts the user + upserts keys inside a tx;
rolls the whole thing back on a username collision (mapped to 409) or a
raced/already-spent token.
- New plan_gate_consume: resolves which tokens to spend WITHOUT consuming
(the payment settled-check stays non-consuming), so `all`-mode verifies
the payment is settled before anything is spent, then both tokens are
consumed atomically at creation.
- extension_register + nostr_register route NEW users through the atomic
path (returning users keep the ordinary backfill path); the npub F2
fail-closed check runs before the tx. Removed the now-dead
enforce_method_gates / enforce_invite / enforce_payment.
- tests/registration_atomicity.rs proves the rollback: a username
collision keeps the invite; an already-spent payment keeps the invite.
Validated against Postgres: full suite 286 passed / 0 failed.