fix(gui): reopen the connection dialog when startup auto-connect gives up — Principle XI. - #5368
fix(gui): reopen the connection dialog when startup auto-connect gives up — Principle XI.#5368crypticpy wants to merge 2 commits into
Conversation
…s up — Principle XI. MainWindow suppresses its "no saved radio" connection-dialog popup whenever LastConnectedRadioSerial is set, and covers the window with a "Looking for your radio…" overlay instead. When the saved radio then cannot be reached, the bail paths in ConnectionPanel::probeRadio() only call setManualMessage() — writing the reason onto a page behind a dialog that never opens. The operator is left with a spinner that never resolves and no offered route back into the connection UI; recovering requires knowing that Settings -> Connect to Radio... exists. Reproduced on an Icom whose network password was not persisted: every launch re-entered the same dead end. ConnectionPanel now reports a startup bail upward as startupConnectUnavailable, and MainWindow clears the overlay, shows the reason, and opens the dialog. - m_startupProbe is latched rather than assigned: the Icom keychain read re-enters probeRadio() without restoreSavedFamily, and that second pass is still the same startup attempt. Cleared on a proven connect and by onManualConnectClicked(). - Interactive and automation probes stay silent — their operator is already reading the manual page, and popping the dialog would replace the specific message with a status line. - showConnectionDialog(), not toggleConnectionDialog(): toggling would hide a dialog the operator opened while the probe was still in flight. Covers the three credential/config bails reachable from startup: missing Icom user name, no saved Icom password, and an unavailable saved source path. A *wrong* saved password fails inside the RS-BA1 session rather than in probeRadio() and is not addressed here — follow-up. Regression test startup_autoconnect_lockout_test pins the contract MainWindow relies on. Two mutations verified: dropping the report call fails 3 checks (the lockout returns); dropping the startup-only guard fails 2 (interactive probes wrongly pop the dialog). Suite: 316/318 pass, 1 skipped. The 2 failures (bridge_docs_check, hl2_state_restore_test) reproduce unchanged on clean main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015HjpgedubkqsxhbYrsTzMR
ten9876
left a comment
There was a problem hiding this comment.
Issue fit
#5367: a saved radio unreachable at startup left the operator on a permanent "Looking for your radio…" overlay — the connection-dialog popup is suppressed whenever LastConnectedRadioSerial is set, so a bail that only calls setManualMessage() writes onto a page behind a dialog that never opens. The mechanism the PR adds — startupConnectUnavailable handed up to MainWindow, gated on m_startupProbe (latched across the Icom keychain re-entry, cleared on proven connect / manual takeover) — is exactly right, cleanly reasoned, and well-tested (startup_autoconnect_lockout_test pins the startup-reports / interactive-stays-silent contract). The MainWindow handler guards (!m_userDisconnected && !isConnected(), show-not-toggle) are correct.
But the fix is wired into only some of probeRadio's bail paths, and two of the ones it misses are central cases of "saved radio cannot be reached" — the very symptom.
Scope
Three files + test, all on-issue. CHANGELOG.md untouched. Preflight: no sockets, no fake peers.
Blockers
1. Two startup-reachable bails still strand the overlay (both untouched context, so referenced by line rather than anchored inline). reportStartupProbeFailure was added to the source-path-unavailable and Icom-credential bails, but not to:
- DNS resolution failure —
src/gui/ConnectionPanel.cpp:2752("Could not resolve \"%1\"…"): a saved radio addressed by hostname whose name stops resolving (DHCP/DNS change) bails withsetManualMessageonly. - HL2 no-answer —
src/gui/ConnectionPanel.cpp:2795("No Hermes-Lite 2 answered at %1…", theHl2ProbeResult::NoAnswerarm): a saved Hermes-Lite 2 powered off or unreachable at startup bails withsetManualMessageonly.
Both are reached on the restoreSavedFamily startup path (the saved route resolves to a hostname / to HL2), so an operator with a saved HL2 idle at boot, or a saved .local/DNS name that moved, gets the identical stuck overlay #5367 describes. Wrap each in if (!reportStartupProbeFailure(<short reason>)) { setManualMessage(<full reason>, true); } before the return (for HL2, before the shared return covering NoAnswer), and add an HL2-no-answer startup row to the test so completeness is pinned rather than spot-fixed. Any other probeRadio bail reachable under restoreSavedFamily wants the same treatment — worth an audit pass rather than fixing these two by name.
Nits (non-blocking)
- The three
m_startupProbe = falsesites (proven-connect at :1401, manual-takeover at :2499, bail-consumed inreportStartupProbeFailure) are each correct and distinct — a one-line "cleared in three places" note near the member declaration would stop a future reader taking one for redundancy.
What was verified vs read
- Verified by me in the PR head: the three clear-sites are distinct and correct; the Icom-keychain re-entry latch reasoning holds; and — the blocker — the DNS-fail and HL2-no-answer bails call only
setManualMessagewith no upward report, both reachable underrestoreSavedFamily. - Read, not re-run: the MainWindow handler guards and the test's startup/interactive contract (CI hasn't run — a merge gate).
- The automated pass for this PR misfired (it returned #5364's SpectralNR findings) and was discarded; this is a direct manual pass. No bridge session — the stuck-overlay paths are startup-timing GUI state, and the PR's own extracted test is the right coverage vehicle once the two missing bails are wired in.
…e XI. Review of aethersdr#5368 found two probeRadio() bails that still stranded the "Looking for your radio…" overlay: an Icom saved by a hostname that no longer resolves, and a Hermes-Lite 2 that does not answer. Auditing every exit reachable under restoreSavedFamily turned up more of the same shape: the three Flex bails (explicit-bind failure, the 3 s no-response timeout, and a socket error such as connection refused or host not found) and the HL2 probe's own bails (bind, resolve, send, and already-in-use). None of them reported upward, so a saved routed Flex that was powered off at boot had the identical stuck overlay aethersdr#5367 describes. Every bail now calls reportStartupProbeFailure() with a short reason. The helper moves to the private section — nothing outside ConnectionPanel called it — and drops its unused bool return; the manual page keeps its full message in every case so the operator can still read it once the dialog is open. A note on m_startupProbe records why its three clear sites are each distinct. Test: startup_autoconnect_lockout_test gains an HL2 no-answer row that lets the real probe run against TEST-NET-1 and waits out its 600 ms deadline. Mutation-checked: removing the NoAnswer report fails both new assertions. Socket disclosure is in tests.cmake per AGENTS.md — one ephemeral UDP port, one datagram, no peer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhDXan9Qe86EbypHmxzHUy
|
@ten9876 Thanks — both bails wired, and the audit pass you suggested found more of the same shape. Pushed as 58ffe69. Bails now reporting upward (every
The Flex three were the surprise: a saved routed Flex powered off at boot had the identical stuck overlay #5367 describes, since Two small cleanups of my own while in there: Test: Nit: the "cleared in three places, none redundant" note is on the |
Summary
Fixes #5367.
MainWindowsuppresses its "no saved radio" connection-dialog popup wheneverLastConnectedRadioSerialis set, and covers the window with a "Looking for yourradio…" overlay instead. When the saved radio then cannot be reached, the bail
paths in
ConnectionPanel::probeRadio()only callsetManualMessage()— writingthe reason onto a page behind a dialog that never opens.
The operator is left with a spinner that never resolves and no offered route back
into the connection UI; recovering requires knowing that
Settings → Connect to Radio… exists. Reproduced on an Icom whose network password
was not persisted: every launch re-entered the same dead end.
ConnectionPanelnow reports a startup bail upward asstartupConnectUnavailable, andMainWindowclears the overlay, shows thereason, and opens the dialog.
m_startupProbeis latched rather than assigned: the Icom keychain readre-enters
probeRadio()withoutrestoreSavedFamily, and that second pass isstill the same startup attempt. It is cleared on a proven connect and by
onManualConnectClicked().reading the manual page, and popping the dialog would replace the specific
message with a status line.
showConnectionDialog(), nottoggleConnectionDialog(): toggling would hide adialog the operator opened while the probe was still in flight.
Covers the three credential/config bails reachable from startup: missing Icom
user name, no saved Icom password, and an unavailable saved source path. A
wrong saved password fails inside the RS-BA1 session rather than in
probeRadio()and is deliberately not addressed here — noted as follow-up sothe scope stays the reported dead end.
Constitution principle honored
Principle XI — Fixes Are Demonstrated. New regression test
startup_autoconnect_lockout_testpins the contractMainWindowrelies on. Twomutations verified: dropping the report call fails 3 checks (the lockout
returns); dropping the startup-only guard fails 2 (interactive probes wrongly pop
the dialog).
Principle IX — Surface Only What Survives. The failure reason was already
being computed and then discarded behind an overlay; this routes it to a surface
the operator can actually see.
Test plan
cmake --build build) — clean, exit 0end was hit on a real Icom over RS-BA1 whose network password had not been
persisted, which is what prompted the fix
startup_autoconnect_lockout_testpasses. Fulllocal suite shows only the two failures that reproduce unchanged on clean
main(bridge_docs_check,hl2_state_restore_test), neither related toconnection startup
Checklist
docs/COMMIT-SIGNING.md) — GPG, GitHub reportsverified: trueAppSettingscalls — this change adds no settings; itonly reads the existing
LastConnectedRadioSerialcondition already inMainWindowMeterSmoother— N/A, no meter UI is touchedneeded; no document describes the startup overlay's bail behaviour.
CHANGELOG.mddeliberately untouchedthis touches credential flow control only: no credential value is
logged, surfaced, or newly persisted — the dialog shows the same
setManualMessage()reason string that already existedNote on the claim protocol (AGENTS.md §Issue / PR Claim Protocol): assignee
changes are rejected for an account without write access to this repo, so the
Fixes #5367link is the visible claim on the issue timeline instead.