Skip to content

iOS: don't upload the RR73 sign-off as a locator to PSKReporter - #615

Merged
patrickrb merged 1 commit into
devfrom
optio/task-e09889a5-f2c9-4ef2-b26c-04c1ff30f0e7
Jul 22, 2026
Merged

iOS: don't upload the RR73 sign-off as a locator to PSKReporter#615
patrickrb merged 1 commit into
devfrom
optio/task-e09889a5-f2c9-4ef2-b26c-04c1ff30f0e7

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Summary

The iOS PskReporter.makeSpot reported a decode's senderLocator whenever the decoded grid field was >= 4 characters. The FT8 end-of-QSO roger-73 report "RR73" is a 4-char Maidenhead look-alike (R,R are valid A–R field letters; 7,3 valid digits), so the decoder copies it into grid via looksLikeGrid — and every decoded RR73 was then spotted to the global PSKReporter database as locator "RR73", a phantom Arctic coordinate (83.5°N, 175°E).

This is the iOS side of the same defect fixed on Android in PR #612 (PskReporterSender.reportableLocator).

Root cause

Per the FT8 protocol, "RR73" is packed as the roger-73 report, never as a grid — no compliant transmitter means grid RR73. The rest of the Kit already recognizes this:

  • gridToLatLon (Util.swift:63) returns nil for "RR73"/"RR" to avoid a phantom map pin.
  • QsoEngine classifies an incoming "RR73" as the .rr73 sequencer stage (QsoEngine.swift:348-358).

PskReporter.makeSpot (PskReporter.swift:65) was the one consumer that used a naive length check instead, so it leaked RR73 into the shared spot DB — polluting an ecosystem resource and breaking WSJT-X interop.

Fix

Extracted a pure reportableLocator(_:) helper that requires a >= 4 char locator and rejects the "RR73" sign-off (case-insensitive), and gated makeSpot's senderLocator on it. Well-formed grids (FN42, IO91wm, …) are unaffected — byte-identical spots.

Testing performed

  • Added PskReporterTests cases: reportableLocator accepts real grids, rejects short tokens ("", "FN", "RR") and the RR73 sign-off (RR73/rr73/Rr73); and a makeSpot case asserting an RR73-grid decode is still spotted (the call is real) but with a nil locator.
  • Ran the real XCTest suite for PskReporter.swift in isolation on Linux via SwiftPM: 24 tests pass. Verified red→green — reverting the helper to the old length-only check fails 4 cases.
  • Note: a whole-module swift test on Linux is currently blocked by an unrelated Apple-only import Network in WsjtxUdpService.swift; the Foundation-only PskReporter source + its tests were exercised standalone.

Risk assessment

Very low. Single, focused policy change on a pure function; the only behavioral difference is that a locator equal to "RR73" is now omitted (as it already is everywhere else in the app). No protocol/encoder/DSP changes; well-formed decodes produce identical spots.

🤖 Generated with Claude Code

The FT8 end-of-QSO roger-73 report "RR73" is a 4-char Maidenhead
look-alike (R,R are valid A-R field letters; 7,3 valid digits), so the
decoder copies it into a message's `grid` field via `looksLikeGrid`.
`PskReporter.makeSpot` gated the reported `senderLocator` on a naive
`grid.count >= 4`, so every decoded RR73 was spotted to the global
PSKReporter database as locator "RR73" — a phantom Arctic coordinate
(83.5N, 175E) that pollutes a shared ecosystem resource and breaks
WSJT-X interop (no protocol-compliant transmitter ever means grid RR73).

The rest of the Kit already excludes it wherever it classifies a grid
(`gridToLatLon` returns nil; `QsoEngine` maps it to the `.rr73` stage) —
PSKReporter was the one consumer that missed it. This mirrors the Android
fix (PskReporterSender.reportableLocator, PR #612), the iOS side of the
same ecosystem-interop defect.

Fix: extract a pure `reportableLocator(_:)` helper that requires a >= 4
char locator AND rejects the "RR73" sign-off (case-insensitive), and gate
`makeSpot`'s locator on it. Well-formed grids are unaffected.

Tests: PskReporterTests gains reportableLocator cases (accepts real grids,
rejects short tokens and RR73/rr73/Rr73) and a makeSpot case asserting an
RR73-grid decode is still spotted but with a nil locator. Verified
red->green (reverting the helper to the old length-only check fails 4
cases). Whole-module `swift test` on Linux is blocked by an unrelated
Apple-only `import Network` in WsjtxUdpService.swift; the Foundation-only
PskReporter source + its tests were run in isolation via SwiftPM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 36.68%. Comparing base (c1696cb) to head (73d15b2).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##                dev     #615      +/-   ##
============================================
+ Coverage     36.62%   36.68%   +0.06%     
  Complexity      197      197              
============================================
  Files           216      216              
  Lines         26885    26912      +27     
  Branches       3294     3294              
============================================
+ Hits           9847     9874      +27     
  Misses        16811    16811              
  Partials        227      227              
Flag Coverage Δ
ios 96.51% <100.00%> (+0.02%) ⬆️
native 9.93% <ø> (ø)

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

Files with missing lines Coverage Δ
ios/FT8AFKit/Sources/FT8Engine/PskReporter.swift 100.00% <100.00%> (ø)
...8AFKit/Tests/FT8EngineTests/PskReporterTests.swift 100.00% <100.00%> (ø)
🚀 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

This PR fixes an iOS FT8Engine PSKReporter spotting bug where the FT8 end-of-QSO sign-off token “RR73” (a 4-character Maidenhead look-alike) could be uploaded as a senderLocator, polluting PSKReporter with a phantom locator.

Changes:

  • Added a pure helper PskReporter.reportableLocator(_:) to accept locators only when >= 4 characters and not equal to "RR73" (case-insensitive).
  • Updated PskReporter.makeSpot to use reportableLocator(_:) instead of a naive length-only check.
  • Added XCTest coverage for both reportableLocator(_:) and the makeSpot RR73 behavior (spot still generated, but with senderLocator == nil).

Reviewed changes

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

File Description
ios/FT8AFKit/Sources/FT8Engine/PskReporter.swift Centralizes PSKReporter locator policy in reportableLocator(_:) and prevents uploading RR73 as a locator.
ios/FT8AFKit/Tests/FT8EngineTests/PskReporterTests.swift Adds unit tests validating the RR73 exclusion and confirming makeSpot behavior remains correct otherwise.

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

@patrickrb
patrickrb merged commit 8fc3ba2 into dev Jul 22, 2026
18 checks passed
@patrickrb
patrickrb deleted the optio/task-e09889a5-f2c9-4ef2-b26c-04c1ff30f0e7 branch July 22, 2026 21:39
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