Desktop: complete the QSO when a partner signs off with RR73#587
Merged
Conversation
Root cause: the auto-sequencer's classify() checked the grid field before
matching the RR73/RRR/73 sign-offs. "RR73" is a valid 4-char Maidenhead-shaped
token (R,R in A..R followed by two digits), so the decoder copies it into the
grid field (looks_like_grid("RR73") is true, dsp/decoder.rs). classify() then
returned Content::Grid("RR73") for a standard WSJT-X sign-off, so the RReport
stage in process_rx hit the `_ => {}` arm and the engine retransmitted our
R-report forever — the QSO never completed or logged. Only non-grid-shaped
sign-offs (73, RRR) closed a QSO.
Fix: match the RR73/RRR/73 sign-offs on the trimmed extra text BEFORE the grid
check in classify(). looks_like_grid is left untouched (the map/distance code
relies on its shape test and rejects RR73 separately).
Tests: added rr73_signoff_is_not_classified_as_a_grid (direct classify unit
test) and rr73_with_decoder_grid_still_completes_qso (full RReport->complete
flow with the realistic grid=="RR73" the decoder emits). Also corrected the two
existing RR73 fixtures, which passed grid=="" (never happens live) and so
masked the bug, to grid=="RR73". All four fail against the pre-fix classify and
pass after.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #587 +/- ##
============================================
+ Coverage 29.36% 29.42% +0.06%
Complexity 197 197
============================================
Files 179 179
Lines 24068 24091 +23
Branches 3263 3263
============================================
+ Hits 7067 7089 +22
- Misses 16780 16781 +1
Partials 221 221
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Fixes a desktop auto-sequencer state-machine bug where a partner’s standard FT8 RR73 sign-off was misclassified as a grid (due to RR73 matching the Maidenhead “grid-like” shape), preventing the QSO from ever reaching completion/logging.
Changes:
- Reorders
classify()soRR73/RRR/73sign-offs are matched before treatingmsg.gridas a grid report. - Updates existing RR73-related fixtures to reflect live decoder behavior (
grid == "RR73"). - Adds regression tests to ensure
RR73is not classified asContent::Gridand that the QSO completes fromTxStage::RReportwith decoder-realistic inputs.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The desktop auto-sequencer never completed (or logged) a QSO when the partner signed off with the standard WSJT-X RR73 — it hung retransmitting our R-report indefinitely. Only the non-grid-shaped
73/RRRsign-offs closed a QSO. This is a functional bug affecting normal FT8 QSO flow (Category 2).Root cause
classify()indesktop/src-tauri/src/qso.rschecked the message'sgridfield before matching theRR73/RRR/73sign-offs:"RR73"is a valid 4-char Maidenhead-shaped token (R,RinA..R+ two digits), solooks_like_grid("RR73")istrueand the decoder copies it into thegridfield (dsp/decoder.rs:285).classify()therefore returnedContent::Grid("RR73")for a standard sign-off. Inprocess_rx, theTxStage::RReportarm only handlesContent::Rr73 | Content::Rrr | Content::Bye73; aGridfell through to_ => {}, so the engine kept resending our R-report and the QSO never advanced tocomplete().Fix
Match the
RR73/RRR/73sign-offs on the trimmedextratext before the grid check inclassify(). Minimal reorder, no behavior change for genuine grid reports (a real locator likeFN42still classifies asContent::Grid).looks_like_gridis intentionally left untouched — the map/distance code relies on its shape test and rejectsRR73separately.Testing
Verified by compiling
qso.rsstandalone (the full Tauri crate needs webkit/dbus system libs unavailable here) viarustc --testwith a zig linker, stubbing only serde and the two dependency structs:qsotests pass.classify: the 2 new tests and the 2 de-masked fixtures fail — confirming they capture the bug.New tests:
rr73_signoff_is_not_classified_as_a_grid— directclassify()unit test (RR73→Rr73, FN42→Grid).rr73_with_decoder_grid_still_completes_qso— full RReport→complete flow with the realisticgrid == "RR73"the live decoder emits.Also corrected the two existing RR73 fixtures, which passed
grid == ""(never happens live) and so masked the bug, togrid == "RR73".Risk
Low. Single-function reorder in a pure state machine; genuine grid reports and the R-report/report paths are unchanged. Preserves WSJT-X interoperability (RR73 is the standard sign-off).
Notes / follow-up
The same root bug exists on iOS (
ios/FT8AFKit/Sources/FT8Engine/QsoEngine.swiftclassify, decoderFT8Decoder.swift), where its tests likewise pass RR73 fixtures with an empty grid. Left for a separate focused PR (one platform per PR).🤖 Generated with Claude Code