Skip to content

Reset _chorusHubClient in RecheckNetworkStatus to allow re-discovery#381

Closed
imnasnainaec wants to merge 4 commits into
masterfrom
fix/chorushub-client-reset
Closed

Reset _chorusHubClient in RecheckNetworkStatus to allow re-discovery#381
imnasnainaec wants to merge 4 commits into
masterfrom
fix/chorushub-client-reset

Conversation

@imnasnainaec

@imnasnainaec imnasnainaec commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

`RecheckNetworkStatus()` in `SyncStartControl` creates a new worker thread but never clears `_chorusHubClient`. The worker method's guard skips server discovery when the field is non-null, so after the first check the stale client is reused permanently. If the ChorusHub server changes, the new server is never found until the application restarts.

Add `_chorusHubClient = null;` in `RecheckNetworkStatus()` before setting up the new worker. Nulling `_chorusHubClient` alone is sufficient to force re-discovery: the worker's existing `if (_chorusHubClient == null)` guard already calls `FindServerInformation()` and reassigns both `_chorusHubServerInfo` and `_chorusHubClient`.

Also add a null guard in `_useLocalNetworkButton_Click` for `_chorusHubClient` and `_chorusHubServerInfo`. Both run on the UI thread so there is no TOCTOU issue, but there is a ~2s race window between the null assignment and the next timer tick starting the new worker, during which the button remains enabled. The guard is a silent defensive return for that edge case.

Fixes #374

Devin review: https://app.devin.ai/review/sillsdev/chorus/pull/381


This change is Reviewable

…vered

Without the reset, the guard in CheckNetworkStatusAndUpdateUI short-circuited
on the stale client and never re-ran server discovery, so a different ChorusHub
server on the network was not found until the application restarted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imnasnainaec imnasnainaec self-assigned this Jun 22, 2026
@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

Test Results

       8 files  ±0     333 suites  ±0   2h 22m 53s ⏱️ - 14m 48s
   991 tests ±0     935 ✔️ +1    56 💤 ±0  0  - 1 
3 154 runs  ±0  3 031 ✔️ +1  123 💤 ±0  0  - 1 

Results for commit dfcd5da. ± Comparison against base commit 363c8d1.

♻️ This comment has been updated with latest results.

imnasnainaec and others added 2 commits June 22, 2026 17:03
…click

Nulling _chorusHubClient but leaving _chorusHubServerInfo stale is inconsistent
when the intent is full re-discovery. Reset both in RecheckNetworkStatus.

The reset creates a race window (up to 2s until the next timer tick starts the
worker) where the button is still enabled but both fields are null. Guard the
button click handler so a click during that window is a no-op rather than a
NullReferenceException.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Nulling _chorusHubServerInfo on the UI thread while the worker thread reads
it unsynchronized in CheckNetworkStatusAndUpdateUI would cause a
NullReferenceException with no catch to recover. Nulling _chorusHubClient
alone is sufficient: the worker's existing guard re-runs FindServerInformation
and reassigns both fields before creating a new client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imnasnainaec imnasnainaec marked this pull request as ready for review June 22, 2026 21:22
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rmunn

rmunn commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Nulling _chorusHubClient alone is sufficient to force re-discovery: the worker's existing if (_chorusHubClient == null) guard already calls FindServerInformation() and reassigns both _chorusHubServerInfo and _chorusHubClient.

This is incorrect; the AI tool didn't dig deep enough. Setting _chorusHubClient to null without also setting _chorusHubServerInfo to null will simply land in ChorusHubServerInfo.FindServerInformation(), where it will simply return the old _chorusHubServerInfo value.

I'm also a little suspicious of the suggested fix in the first place. Surely the intended behavior of RecheckNetworkStatus is to check if the existing server is still connected, and only look for a new one if the first server has gone away? I don't think clearing the existing _chorusHubClient value is what is intended every time the user opens the "Send/Receive Settings" dialog.

This feels like an AI hallucination to me, solving a problem that doesn't actually exist (and solving it wrong, as well). Is there any indication that this is an actual problem? Or is this a case of an AI tool finding hypothetical problems that don't actually happen?

@imnasnainaec imnasnainaec marked this pull request as draft July 2, 2026 14:05
@imnasnainaec

imnasnainaec commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

You're right — thanks for digging in. FindServerInformation() breaks out of its wait loop immediately when the static ChorusHubServerInfo._chorusHubServerInfo cache is already populated, so after nulling _chorusHubClient the worker just gets the old server info back and wraps it in a new client. A changed hub is still never found. And since the only way to clear that static cache is ClearServerInfoForTests(), this can't be fixed from SyncStartControl at all; a real fix would have to change FindServerInformation() itself, which affects five other call sites and re-introduces the discovery wait on every call.

The null guard in the click handler only existed to patch the race the nulling introduced, so it goes too. Closing this PR; I'll note the rescoping in #374 and close that as well.

(Response by Claude Fable 5.)

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.

_chorusHubClient not reset in RecheckNetworkStatus prevents ChorusHub re-discovery

2 participants