Skip to content

db: restore unique partial index on user.npub with preflight dedup#93

Closed
escapedcat wants to merge 1 commit into
masterfrom
feature/user-npub-unique
Closed

db: restore unique partial index on user.npub with preflight dedup#93
escapedcat wants to merge 1 commit into
masterfrom
feature/user-npub-unique

Conversation

@escapedcat
Copy link
Copy Markdown
Collaborator

Migration 101 originally added this index as part of the Nostr-auth work (PR #89), but it was reverted in be18b50 to avoid a merge conflict with the multi-vendor import PR — the maintainer noted on the PR thread that the constraint would land in a follow-up.

This is that follow-up.

The endpoint handler in src/rest/v4/nostr.rs is already written to treat a user.npub UNIQUE violation as the lost-race recovery path for create_or_recover. Without the index, that branch is dormant and two simultaneous first-time Nostr sign-ins for the same pubkey can produce two rows.

Pre-flight (per CodeRabbit's original concern on PR #89): between the endpoint going live on 2026-05-10 and this migration landing, duplicate-npub rows are possible. For each duplicate group, keep the oldest row's npub link and NULL out the rest. Losing rows retain all other state (saved items, existing tokens) — they just lose the Nostr identity link, so the user's next Nostr sign-in lands deterministically on the winning row.

Schema bootstrap (schema.sql) updated to match.

Note: src/rest/v4/nostr.rs::unknown_npub_concurrent_inserts_create_exactly_one_user passes today for the wrong reason — :memory: SQLite gives each connection its own private DB, so the two "concurrent" inserts never share state. Worth rewriting in a separate change to actually exercise the race the index now prevents.

Migration 101 originally added this index as part of the Nostr-auth
work (PR #89), but it was reverted in be18b50 to avoid a merge
conflict with the multi-vendor import PR — the maintainer noted on
the PR thread that the constraint would land in a follow-up.

This is that follow-up.

The endpoint handler in src/rest/v4/nostr.rs is already written to
treat a user.npub UNIQUE violation as the lost-race recovery path
for create_or_recover. Without the index, that branch is dormant
and two simultaneous first-time Nostr sign-ins for the same pubkey
can produce two rows.

Pre-flight (per CodeRabbit's original concern on PR #89): between
the endpoint going live on 2026-05-10 and this migration landing,
duplicate-npub rows are possible. For each duplicate group, keep
the oldest row's npub link and NULL out the rest. Losing rows
retain all other state (saved items, existing tokens) — they just
lose the Nostr identity link, so the user's next Nostr sign-in
lands deterministically on the winning row.

Schema bootstrap (schema.sql) updated to match.

Note: src/rest/v4/nostr.rs::unknown_npub_concurrent_inserts_create_exactly_one_user
passes today for the wrong reason — :memory: SQLite gives each
connection its own private DB, so the two "concurrent" inserts
never share state. Worth rewriting in a separate change to actually
exercise the race the index now prevents.
@escapedcat escapedcat closed this May 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant