Skip to content

[codex] Defer ping watchdog during Multi-Flex joins#3570

Merged
ten9876 merged 1 commit into
aethersdr:mainfrom
rfoust:codex/multiflex-ping-grace
Jun 14, 2026
Merged

[codex] Defer ping watchdog during Multi-Flex joins#3570
ten9876 merged 1 commit into
aethersdr:mainfrom
rfoust:codex/multiflex-ping-grace

Conversation

@rfoust

@rfoust rfoust commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes a Multi-Flex reconnect false-positive where AetherSDR could force-disconnect after 5 unanswered pings while another SmartSDR client was joining and the radio was replaying status/stream ownership. The ping watchdog now records recent foreign client ... connected status messages and grants one 5-second grace period if the missed-ping threshold overlaps that client-connect burst. This keeps the normal watchdog behavior unchanged outside the Multi-Flex connect window.

Constitution principle honored

Principle VIII — Evidence Over Assertion. The fix is based on logs showing the prior failure path (5 consecutive pings unanswered — forcing disconnect) immediately after SmartSDR connected, and was verified with a reproduction log where the watchdog reached 5 misses but deferred instead of disconnecting.

Test plan

  • Local build passes (cmake --build build --parallel)
  • Behavior verified on a real radio
  • Existing tests pass (CI)
  • Reproduction steps documented if user-reported bug

Reproduction verification:

  • Start AetherSDR with 4 panadapters and 5 slices.
  • Start SmartSDR from another computer and let it restore multiple panadapters/slices.
  • Confirm AetherSDR remains connected and keeps its own waterfall/audio streams.

Observed in aethersdr-20260614-001547.log:

  • SmartSDR connected as 0x106E3651.
  • AetherSDR logged noted Multi-Flex client connect for ping grace.
  • The watchdog reached misses: 5.
  • AetherSDR logged deferring ping disconnect after recent Multi-Flex client connect ... grace_ms: 5000.
  • No forced disconnect followed.
  • AetherSDR kept owned remote_audio_rx 0x04000008 and ignored SmartSDR's remote_audio_rx 0x04000009.

Checklist

  • Commits are signed (docs/COMMIT-SIGNING.md)
  • No new flat-key AppSettings calls — use nested-JSON-under-one-key (Principle V)
  • All meter UI uses MeterSmoother (Principle II)
  • Documentation updated if user-visible behavior changed
  • Security-sensitive changes reference a GHSA if applicable

@rfoust rfoust marked this pull request as ready for review June 14, 2026 04:27
@rfoust rfoust requested a review from a team as a code owner June 14, 2026 04:27
Copilot AI review requested due to automatic review settings June 14, 2026 04:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts RadioModel’s TCP ping watchdog to avoid false disconnects during Multi-Flex join bursts, where the radio may temporarily delay ping replies while replaying status/stream ownership to another newly connected client.

Changes:

  • Track the timestamp of recent foreign client ... connected status messages.
  • Add a single 5-second grace window that defers the forced-disconnect decision if the missed-ping threshold coincides with a recent Multi-Flex client-connect burst.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/models/RadioModel.h Adds state and constants to support a Multi-Flex-specific ping grace period.
src/models/RadioModel.cpp Implements the grace-window logic in the ping watchdog and records foreign client-connect timestamps from status messages.

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, @rfoust — it's a tidy, well-scoped fix backed by a real reproduction log. I traced the logic against RadioModel.cpp and it holds up. All 6 CI checks are green.

What I verified

  • Grace state is reset on (re)connect — both m_lastMultiFlexClientConnectMs and m_multiFlexPingGraceUntilMs are cleared in startNetworkMonitor(), so a stale timestamp can't carry across sessions.
  • The arming site is correctly gated — the m_lastMultiFlexClientConnectMs write sits inside the connected branch of onStatusReceived() and is guarded by handle != clientHandle(), so our own connect echo doesn't trigger it.
  • The grace is bounded for a single connect burst — detection window is (missThreshold + 1) * interval (~6 s at the 1 s ping cadence) measured from the connect, and grace itself is 5 s; once the connect is older than the window, the normal forceDisconnect() path runs. So a genuinely-dead link after a join still disconnects, just ~5 s later. Good.
  • sendCmd("ping") is kept alive during the deferral — so a recovered link resets m_pingMissCount via pingRttMeasured and the watchdog returns to normal. The now >= m_lastMultiFlexClientConnectMs clock-rewind guard is a nice defensive touch.

One minor observation (non-blocking)

The PR describes "one 5-second grace period," but the mechanism actually grants grace per foreign client-connect event, not once globally. If the radio replays multiple client … connected status messages (e.g. several SmartSDR clients joining, or repeated status replays), each refreshes m_lastMultiFlexClientConnectMs and can re-arm the 5 s window. In practice this is fine — and arguably what you'd want, since each real join deserves grace — but it does mean deferral can extend past a single 5 s window during a sustained connect storm. Worth a one-line comment noting the per-event semantics so a future reader doesn't assume it's strictly one-shot. No change required.

Nice work — the defensive resets and the bounded-window design are exactly right for a watchdog override.


🤖 aethersdr-agent · cost: $2.9577 · model: claude-opus-4-8

@ten9876 ten9876 merged commit 9610203 into aethersdr:main Jun 14, 2026
6 checks passed
G6PWY-Chris pushed a commit to G6PWY-Chris/AetherSDR that referenced this pull request Jun 22, 2026
Fixes a Multi-Flex reconnect false-positive: the 5-miss TCP ping watchdog was force-disconnecting while another SmartSDR client joined and the radio replayed status/stream ownership. Records foreign 'client ... connected' status timestamps and grants a bounded 5s grace when the missed-ping window overlaps the connect burst. Watchdog stays safe-by-bound (grace expires; a genuinely dead radio still disconnects ~5s later), state reset on reconnect, own-echo excluded. Verified on a real radio via reproduction log (Principle VIII).

Co-authored-by: rfoust <rfoust@users.noreply.github.com>
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.

3 participants