fix(gui): SpotHub clear buttons persist, fix counter desync, add console clears (#2022)#3823
Conversation
…ole clears (aethersdr#2022) SpotHub's two Clear buttons wiped only the in-memory SpotTableModel, so on the next dialog open loadLogFiles() re-tailed the on-disk source logs and every spot (and console line) came back. The Spot List counter also went stale after the Display tab's "Clear All", which never touched it, and none of the six source consoles had a Clear button at all. - Capture the cluster/RBN/WSJT-X/POTA/SpotCollector/FreeDV log paths as members and add truncateLogFile() so the Clear handlers can zero them. The Spot List "Clear" zeroes the cluster+RBN spot logs; the Display tab "Clear All" zeroes every source log and empties every console. Spots and console text no longer return after close/reopen. - Promote the Spot List counter to m_spotCountLabel and drive it from rowsInserted/rowsRemoved/modelReset, so it self-corrects no matter which path clears the model (fixes the stale count after "Clear All"). - Add a "Clear" button to each of the six source console tabs that empties the console and zeroes its log file. - Add tooltips to both spot Clear buttons explaining their differing scope, and stable objectNames for automation. Fixes aethersdr#2022
There was a problem hiding this comment.
Thanks @jensenpat — this is a well-diagnosed, tightly-scoped fix. The root-cause writeup matches what's in the code, and I verified the key invariants:
- Spot List "Clear" truncating exactly the cluster + RBN logs is correct.
loadLogFiles()only feedsm_spotModelfromclusterSpots+rbnSpots(DxClusterDialog.cpp:654-660); WSJT-X/POTA/SC/FreeDV are console-display-only. So zeroing those two logs is precisely the set that backs the spot list — nice. - Counter fix is the right shape. Promoting to
m_spotCountLabeland driving it fromrowsInserted/rowsRemoved/modelResetmakes it self-correct regardless of which path mutates the model, which is exactly the "Clear All" desync source. Good. - Conventions are clean (Qt parent-ownership for the buttons, no flat-key
AppSettings, RAII via layout reparenting). CI is green across all six checks.
A couple of notes, neither blocking:
-
Truncating a log while its client is actively connected. The clients keep
m_logFileopen and append each line at the current offset (DxClusterClient.cpp:257-259; opened once withTruncateon connect at :125). An externalQFile::resize(0)doesn't move the open writer's file offset, so if a Clear fires mid-session the next write lands at the old offset and leaves a leading NUL hole rather than a truly empty file. The user-visible outcome is mostly benign — the pre-clear bytes become a zero-filled hole thatparseSpots()won't match on reopen, so old spots still don't return — but you may see stray blank/NUL lines in the reloaded console and some wasted space until the next reconnect re-truncates. Worth a comment acknowledging it, or (if you want it airtight) routing truncation through the owning client so it can also rewind its open handle. Fine to leave as-is given the persistence goal is still met. -
Per-tab console Clear vs. the spot list. Clicking e.g. the Cluster tab's Clear truncates the cluster log (which backs the spot list) but doesn't touch the in-memory
m_spotModel/counter, so the count only changes on the next reopen. That's a reasonable scope boundary for a "clear this console" control — just flagging the slight asymmetry in case it surprises anyone.
The destructive aspect (these Clears now delete on-disk logs) is well-communicated through the tooltips and matches the intent of #2022, so no concern there. Holding scope to the Clear-button behavior and deferring the SpotSettingsDialog dead-code removal is the right call.
Nice work — looks good to me.
🤖 aethersdr-agent · cost: $5.1047 · model: claude-opus-4-8
|
Two files, three bugs, one commit. Well-diagnosed and well-scoped. All three root causes are correct. The dialog is The implementation is the right shape on all three fixes:
Two non-blocking notes worth carrying forward (already flagged by aethersdr-agent):
For future reference (not blocking): Several inline comments carry CI: All six checks green. Pure widget/file logic — no live-radio dependency, fully exercisable by CI. The bridge proof is thorough supplemental verification on top. Constitution: Principle IX (Surface Only What Survives — dead local-capture counter replaced by properly-wired member) and Principle XI (Fixes Are Demonstrated — per-bug verification table with on-disk size checks and persistence-after-restart proof) both honored.
|
NF0T
left a comment
There was a problem hiding this comment.
Root cause correct on all three bugs; fix is correctly scoped to DxClusterDialog.{cpp,h} only. HAVE_WEBSOCKETS guards verified correct; truncateLogFile empty-path guard confirmed; m_spotCountLabel wired to rowsInserted/rowsRemoved/modelReset — covers all mutation paths including the Clear All modelReset that the old local-capture missed. Fixes #2022 in both PR body and commit body. All six CI checks green. Tier 3 only.
Squash subject: fix(gui): SpotHub clear buttons persist, fix counter desync, console clears — Principle XI. (#3823)
Issue
Fixes #2022 — SpotHub's Clear buttons didn't remove spots permanently, the
Spot List counter went stale after "Clear All", and none of the six source
console tabs had a Clear button.
Root cause
The Spot List comes from a dialog-local
SpotTableModel, but the dialog isWA_DeleteOnClose. On every open the constructor schedulesloadLogFiles(),which
tailFile()s the on-disk source logs(
~/…/AetherSDR/spothub/dxcluster.log,rbn.log, …) and repopulates themodel and consoles. Both Clear buttons only wiped the in-memory model, never
the log files — so spots and console text always came back on reopen.
Two further defects: the Spot List counter (
countLabel) was a localcaptured only by the Spot List "Clear" lambda, so the Display tab's "Clear
All" — which resets the model via
m_totalSpotsLabelonly — left it stale.And the six source consoles had no Clear control at all.
Fix (
src/gui/DxClusterDialog.{cpp,h}only)members and add
truncateLogFile(). The Spot List Clear zeroes thecluster + RBN spot logs; the Display tab Clear All zeroes every source
log and empties every console. Spots and console text no longer return
after close/reopen.
m_spotCountLabeland drive it fromrowsInserted/rowsRemoved/modelReset, so it self-corrects nomatter which path clears the model (fixes the stale count after
"Clear All").
the console and zeroes its log file.
and stable
objectNames for automation.SpotSettingsDialogdead-code removal (mentioned in the issue's "additionalfinding") is intentionally out of scope here — it's unrelated to the
Clear-button behavior and belongs in its own change.
How the agent automation bridge proved it
Built with the bridge fidelity improvements applied locally for the proof
only (PR #3819 is not part of this branch — this commit touches only
DxClusterDialog.{cpp,h}). Seededdxcluster.log(4 spots) +rbn.log(3 spots) on disk, launched
AETHER_AUTOMATION=1, and opened SpotHub fromthe closed Settings menu via the bridge's menu-reachability verb
(
invoke "SpotHub..." trigger).dumpTree→spotListCountLabel7 spotsdumpTreeobjectNamesclusterClearBtn,rbnClearBtn,wsjtxClearBtn,scClearBtn,potaClearBtn,freedvClearBtn✓invoke displayClearAllBtn click→dumpTreespotListCountLabel7 spots→0 spotswc -cdxcluster.log/rbn.log146/118 B → 0/0 Binvoke "SpotHub..." trigger,dumpTreespotListCountLabel0 spots(spots did not return)invoke spotListClearBtn click5 spots→0 spots, logs → 0 BRadio never keyed — RX-only proof;
transmitting == falseconfirmed atteardown.
Agent automation bridge — gaps found
dumpTreeserializesobjectName/accessibleName/valuebut nottoolTip, so Bug 5 (the two Cleartooltips) can't be asserted through the bridge; verified by code only.
Proposed: add
toolTipto thedumpTreenode serialization.QLabel(accessibleName "Close window"), whichinvoke … clickcan'ttarget, so the reopen/persistence proof required a full app restart.
Proposed: a
close <target>verb (or synthetic-click support for thecustom title-bar close
QLabel).Otherwise the bridge was sufficient: menu reachability opened the dialog,
invoke clickdrove both Clear buttons, anddumpTreeread the counter andbutton inventory directly.
💻 Generated with Claude Code (Opus 4.8) with architecture by @jensenpat