* Make location notes robust: durable relay subscriptions, failure decay, auto-recovery
Location notes (and geohash chat / DMs) intermittently stopped showing
events because the Nostr relay layer lost subscriptions and blacklisted
relays:
- Replay active subscriptions on every relay (re)connect. Relays drop
REQs with the socket; previously a drop silently killed the
subscription on that relay for the rest of the session. Durable
subscription intent now also survives disconnect()/resetAllConnections
(background -> foreground).
- Keep failed REQ sends queued instead of dropping them.
- Raise the EOSE fallback from a fixed 2s Timer to a 10s injected
schedule (Tor needs more than 2s), and settle EOSE trackers when a
relay disconnects before answering so initial load doesn't stall.
- Decay "permanently failed" relay markings after a 10-minute cooldown;
previously ~9 minutes of outage (or one DNS hiccup) excluded a relay
until app restart, with nothing resetting it on macOS.
- Make geo relay selection deterministic (distance, then host) so
publishers and subscribers with the same directory agree on relays.
- Post .geoRelayDirectoryDidRefresh after a directory fetch and let
LocationNotesManager auto-resubscribe out of the "no relays" state
instead of requiring a manual retry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Guard subscription activation on connection identity
A REQ send completion from a dead socket could land after
handleDisconnection cleared the relay's subscriptions and re-mark the
subscription active, making the next connection skip the durable replay
and leave that relay silent. Only mark a subscription active if the
completing socket is still the relay's live connection.
Regression test defers send completions in the mock so the stale
completion deterministically interleaves between disconnect and
reconnect.
Addresses Codex review on #1333.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Expand coverage for transport, chat, and media flows
* Stabilize transport and media coverage tests
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Simplifies geonotes architecture by eliminating all background subscriptions:
- Delete LocationNotesCounter.swift (104 lines) and related tests (58 lines)
- Remove background subscription system entirely
- Icon is now constant darker orange (indicates availability, not state)
- Subscription ONLY happens when user explicitly opens the sheet
- Total: ~220 lines of code removed
Privacy Benefits:
- Zero network traffic until user action
- No location leaking to relays via background polling
- User must explicitly opt-in to discover notes
The icon (note.text in orange) simply indicates the feature is available
when location permission is granted. Notes are only fetched when the
sheet is opened, prioritizing privacy over convenience.
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Location notes: fix performance and UI issues
Performance fixes:
- Add Set-based duplicate detection (O(1) vs O(n) lookup)
- Eliminates lag when receiving 200+ notes during EOSE
Correctness fixes:
- Fix optimistic echo timestamp to match signed event timestamp
- Add echo IDs to noteIDs set for consistency
UI improvements:
- Remove duplicate "loading recent notes" text in header
- Simplify toolbar icon color logic for immediate green indication
- Icon now reliably turns green when notes exist in geohash
Tests: All 3 LocationNotes tests passing
* Location notes: add remaining robustness fixes
Additional improvements:
- Align counter/manager limits to 200 (prevents showing count higher than displayable)
- Set loading state before clearing notes to eliminate UI flicker on geohash change
- Add geohash validation for building-level precision (8 valid base32 chars)
- Add defensive 500-note memory cap with automatic trimming
- Clear stale notesGeohash state on sheet dismiss
Tests:
- Fix test geohashes to use valid base32 characters
- All 3 LocationNotes tests passing
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Move LocalizationCatalogTests out of Localization/
SPM is treating all the files under Localization as a resource as per the Package.swift, hence it’s not even building it
* Use a class object vs struct to fix build issue
* Explicitly check that the output is not a l10n key
* Remove skipped test
* fix(test): update LocationNotesManagerTests to expect localization key
The tests were failing because in the test environment, String(localized:) returns
the localization key instead of the actual localized value. Updated the assertions
to expect 'location_notes.error.no_relays' instead of the English translation
'no geo relays available near this location. try again soon.'
* Fix LocationNotesManager test assertions for localization bundle
- Update test assertions to use String(localized:) to match manager behavior in test environment
- Fixes issue where tests expected localized text but manager returns raw keys in SPM test environment
- Both manager and tests now consistently handle localization bundle differences
- Resolves P1 issue: Keep LocationNotes error messages localized
- All 124 tests now pass after clean build
* SPM: process bitchat/Localizable.xcstrings in main target to fix CLI warning; keep tests' Localization resource.