Skip to content

iOS: classify RR73 sign-off before grid so answered QSOs complete and log#596

Open
patrickrb wants to merge 1 commit into
devfrom
optio/task-666f0ede-5f8e-4d4d-a82a-b73b83e90d61
Open

iOS: classify RR73 sign-off before grid so answered QSOs complete and log#596
patrickrb wants to merge 1 commit into
devfrom
optio/task-666f0ede-5f8e-4d4d-a82a-b73b83e90d61

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Root cause

QsoEngine.classify (ios/FT8AFKit/Sources/FT8Engine/QsoEngine.swift) checked the decoded message's grid field before the RR73/RRR/73 sign-off switch:

if !msg.grid.isEmpty { return .grid(msg.grid) }   // ran first
switch extra { case "RR73": return .rr73; ... }

"RR73" is a valid 4-char Maidenhead-shaped token (R,R fall in the A..R field range; 7,3 are digits), so looksLikeGrid("RR73") is true and the decoder copies it into the grid field (FT8Decoder.buildMessage: if looksLikeGrid(m.extra) { m.grid = m.extra }). A partner's standard closing "RR73" therefore reaches the engine with both extra == "RR73" and grid == "RR73", and classify returned Content.grid("RR73") instead of .rr73.

In processRx, the .rReport stage only completes on .rr73/.rrr/.bye73 content; a .grid hits default: break and returns nil. So the auto-sequencer never completed the QSO, retransmitted our R-report forever, and never logged the contact — for essentially every answered QSO, since RR73 is the most common FT8 sign-off.

Fix

Match the sign-offs before the grid check, so a sign-off is never mistaken for a grid report. This mirrors the two reference ports, which already order it this way:

  • desktop desktop/src-tauri/src/qso.rs — sign-off switch first, with a comment describing this exact regression.
  • Android GeneralVariables — classifies a token as a grid only when it matches the Maidenhead shape and != "RR73".

iOS was the 1-of-3 divergent port. looksLikeGrid is untouched (the map/distance code relies on its shape test), and behavior is byte-identical for every non-sign-off input (genuine grids, reports, R-reports).

Testing

  • Added testRr73WithDecoderGridStillCompletesQso (ported from desktop rr73_with_decoder_grid_still_completes_qso), which feeds the RR73 slot with grid == "RR73" exactly as the decoder emits it live. Fails pre-fix ("RR73 sign-off must complete the QSO"), passes after — verified by reverting only the source reorder. A companion assertion confirms a genuine 4-char grid reply still advances the CQ initiator to send a report.
  • The pre-existing testAnswererFullSequenceLogsQso masked the bug by feeding the RR73 slot with grid == "" (not what the decoder emits).
  • swift test on the FT8AFKit package: 132/132 green (built on Linux; the Kit is Foundation-only).

Risk

Low. Localized reordering of two lines in one classification function; no DSP, protocol, or interop change. The .bye73 finish path and all other stages are untouched. iOS app-target wiring (LiveEngine) is unchanged; only the Kit engine logic is affected.

🤖 Generated with Claude Code

… log

`QsoEngine.classify` checked the decoded message's `grid` field before the
RR73/RRR/73 sign-off switch. "RR73" is a valid 4-char Maidenhead-shaped token
(R,R in A..R + two digits), so the decoder copies it into `grid`
(`looksLikeGrid("RR73")` is true) — meaning a partner's standard final "RR73"
arrives at the engine with both `extra == "RR73"` and `grid == "RR73"`.
Checking grid first classified it as `Content.grid`, which falls through the
`.rReport` stage's `default: break`: the auto-sequencer never completed the
QSO, retransmitted our R-report forever, and never logged the contact — for
essentially every answered QSO, since RR73 is the most common FT8 sign-off.

Both reference ports already guard this: desktop `qso.rs` matches the sign-offs
before the grid check (with a comment describing this exact regression), and
Android `GeneralVariables` excludes "RR73" from its grid classification. The iOS
port was the divergent one; this reorders classify to match, without touching
`looksLikeGrid` (the map/distance code relies on its shape test).

Added `testRr73WithDecoderGridStillCompletesQso` (ported from desktop
`rr73_with_decoder_grid_still_completes_qso`), which feeds the RR73 slot with
`grid == "RR73"` exactly as the decoder emits it live; it fails pre-fix
("RR73 sign-off must complete the QSO") and passes after. A companion
assertion confirms a genuine 4-char grid reply still advances the CQ
initiator to send a report. FT8AFKit `swift test` 132/132 green on Linux.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.

1 participant