mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-12 17:23:21 +00:00
A relay's reconnect backoff was process-global and network-blind: the delay earned on one network was still being served out on the next. The only reset signal was OkHttpClient reference identity, which is rebuilt off the metered bit, so it fired for wifi<->cellular and nothing else. Wifi A -> wifi B, a VPN coming up, a captive portal clearing, and metered-wifi -> cellular all left every relay parked on a penalty earned against a network the device had left — up to five minutes of silence on a network that might reach the relay instantly. The transient Off that would have reset things is swallowed by the 200ms debounce in ConnectivityFlow, so it never rescued those cases. Key the decision on ConnectivityStatus.Active.networkId instead, which is the same signal SurgeDns already uses to stale its cache, and treat a genuine network change as a full pool rebuild: every socket is bound to an interface that no longer carries traffic, and needsToReconnect() cannot see that because it only compares the proxy and the timeouts. Also treat a Tor policy flip as a transport change. Flipping a Tor toggle while Tor is already up leaves both OkHttpClient references identical, so a relay whose transport just changed kept waiting out a backoff earned on the other transport. Only TorRelaySettings is compared, not the relay sets that TorRelayEvaluation also carries — those churn while an account's relay lists load (observed firing three times in one cold start), and forgiving the whole pool every time any list updates is far more damage than it repairs. Adds IRelayClient.resetBackoff() (default no-op, so the existing fakes and BleNostrClient are unaffected) rather than reusing ignoreRetryDelays, which only skips the gate for a single attempt and still doubles the stored delay — a relay that failed that one dial came back worse off than before. INostrClient.resetBackoff() is deliberately separate from reconnect(): the latter debounces, so folding this into a coalescing command would let a later request silently drop the reset. The decision table moves into RelayProxyClientConnector.apply() so it can be exercised directly, without a debounce and a shared StateFlow in the way. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>