Skip to content

Desktop: complete the QSO when a partner signs off with RR73#587

Merged
patrickrb merged 1 commit into
devfrom
optio/task-271a4a98-a924-433b-9a5a-bf38b84ea15b
Jul 15, 2026
Merged

Desktop: complete the QSO when a partner signs off with RR73#587
patrickrb merged 1 commit into
devfrom
optio/task-271a4a98-a924-433b-9a5a-bf38b84ea15b

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

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/RRR sign-offs closed a QSO. This is a functional bug affecting normal FT8 QSO flow (Category 2).

Root cause

classify() in desktop/src-tauri/src/qso.rs checked the message's grid field before matching the RR73/RRR/73 sign-offs:

if !msg.grid.is_empty() { return Content::Grid(msg.grid.clone()); }
// ...sign-off match came after...

"RR73" is a valid 4-char Maidenhead-shaped token (R,R in A..R + two digits), so looks_like_grid("RR73") is true and the decoder copies it into the grid field (dsp/decoder.rs:285). classify() therefore returned Content::Grid("RR73") for a standard sign-off. In process_rx, the TxStage::RReport arm only handles Content::Rr73 | Content::Rrr | Content::Bye73; a Grid fell through to _ => {}, so the engine kept resending our R-report and the QSO never advanced to complete().

Fix

Match the RR73/RRR/73 sign-offs on the trimmed extra text before the grid check in classify(). Minimal reorder, no behavior change for genuine grid reports (a real locator like FN42 still classifies as Content::Grid). looks_like_grid is intentionally left untouched — the map/distance code relies on its shape test and rejects RR73 separately.

Testing

Verified by compiling qso.rs standalone (the full Tauri crate needs webkit/dbus system libs unavailable here) via rustc --test with a zig linker, stubbing only serde and the two dependency structs:

  • With the fix: all 8 qso tests pass.
  • Against the pre-fix 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 — direct classify() unit test (RR73→Rr73, FN42→Grid).
  • rr73_with_decoder_grid_still_completes_qso — full RReport→complete flow with the realistic grid == "RR73" the live decoder emits.

Also corrected the two existing RR73 fixtures, which passed grid == "" (never happens live) and so masked the bug, to grid == "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.swift classify, decoder FT8Decoder.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

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

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.42857% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 29.42%. Comparing base (647b12e) to head (0068c02).

Files with missing lines Patch % Lines
desktop/src-tauri/src/qso.rs 96.42% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             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              
Flag Coverage Δ
desktop 61.02% <96.42%> (+0.18%) ⬆️
native 9.93% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
desktop/src-tauri/src/qso.rs 87.50% <96.42%> (+0.53%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

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() so RR73/RRR/73 sign-offs are matched before treating msg.grid as a grid report.
  • Updates existing RR73-related fixtures to reflect live decoder behavior (grid == "RR73").
  • Adds regression tests to ensure RR73 is not classified as Content::Grid and that the QSO completes from TxStage::RReport with decoder-realistic inputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@patrickrb
patrickrb merged commit ff272aa into dev Jul 15, 2026
20 checks passed
@patrickrb
patrickrb deleted the optio/task-271a4a98-a924-433b-9a5a-bf38b84ea15b branch July 15, 2026 13:10
@patrickrb patrickrb mentioned this pull request Jul 20, 2026
4 tasks
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.

2 participants