Adversarial review of the auth/registration surface (findings tracked
privately). Backend half:
- F2: npub-native register no longer binds an npub onto an existing
wallet row on a seed_fingerprint match alone (unauthenticated account
takeover). get_or_create_user_by_nostr_pubkey fails closed (409);
linking an npub goes through the authenticated /auth/nostr/link flow.
Integration test rewritten to assert the refuse-and-409 contract.
- F3: `all`-mode gate verifies payment is settled (non-consuming) BEFORE
consuming the single-use invite, so a still-confirming payment can't
permanently burn the invite. verify_payment_settled split out.
- F4: username availability is pre-checked before any gate token is
consumed; collisions return 409, not 500 — a taken username no longer
burns a paid invoice / invite.
- F6: nostr_register now persists the submitted chain keys, so
receive-by-username and restore self-verification work for npub wallets.
- F10: the pay-to-register not-yet-settled response carries a stable
PAYMENT_PENDING code so polling clients don't parse a free-text string.
Validated against Postgres: full suite 283 passed / 0 failed.