mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 11:48:24 +00:00
There are three states, and two of them were collapsed:
| we have | effective list |
|------------------------|---------------------------------------|
| no event for the user | app defaults — we do not know |
| an event, empty list | **empty** — they told us: nothing |
| an event with relays | those relays |
Every `WithBackup` helper keyed its fallback on the list being *empty* rather
than the event being *absent*, because `readRelaysNorm()`/`writeRelaysNorm()`
end in `.ifEmpty { null }` and the indexer/search helpers wrote
`?.ifEmpty { null } ?: DEFAULTS` outright. So a user who publishes a kind:10002
carrying only write relays silently acquired `Constants.bootstrapInbox` as their
*inbox* list, and a deliberately empty search or indexer list was replaced by
ours. That is the app overriding an explicit choice.
Only `normalizeNIP65AllRelayListWithBackup` was correct, and only by accident:
`relays()` has no `ifEmpty`, so its `?:` could fire only for a missing event.
The rule is now one named, tested primitive rather than an expression
open-coded at four call sites — three of which got it wrong the same way:
relayListOrDefaultsWhenUnknown(event, defaults) { it.readRelaysNorm()?.toSet() }
`Account.indexRelays()` loses its `.ifEmpty { DefaultIndexerRelayList }` too;
it re-applied the substitution a layer up and would have undone the fix.
Two things deliberately left alone. The `Precached` variants keep substituting
defaults: they read only *already decrypted* tags, so empty there can mean "not
decrypted yet" — an unbounded window for a NIP-46 signer — rather than "the user
chose nothing", and the primitive's KDoc records that as a non-goal. And the
`NoDefaults` flows keep returning `emptySet()` for both cases, since their job is
to show what the user published.
Note for callers: the indexer and search flows previously documented themselves
as **never empty** and that contract is gone. A user who publishes an empty
kind:10007 now gets no search relays, which is what their event says. The same
applies to NIP-65 write relays, where the old fallback meant posts went to six
hardcoded relays; if a safety net is wanted there it belongs at the publish site
as a visible decision, not as a silent list substitution.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKYGEp22uGSzWrBDg8fAQ9