fix(qso-answerer): D-CALLER-020 — partner re-transmitting own CQ no longer false-aborts QSO#73
Conversation
…onger false-aborts QSO QsoAnswererService.HandleWaitReportAsync and QsoCallerService.HandleWaitRr73Async treated any message from the partner not addressed to us as "partner is working another station" and aborted immediately — including the partner simply re-transmitting their own CQ because they hadn't decoded us yet, which is the normal, expected state early in a retry sequence, not evidence they moved on. Real-hardware field test (logs/openswfz-20260714T171230Z.log, EA1FUB) caught this: one retry fired correctly, then the partner's own CQ decode ended the QSO outright. Narrow the abort condition to exclude dest == "CQ" (case-insensitive) in both services, falling through instead to the existing "no matching message" retry/watchdog backstop — the same one that already handles genuine silence. Genuine third-party addressing (dest is a different real callsign) still aborts immediately, unchanged. Added unit tests to both service test suites exercising the exact retry-exhaustion cycle pattern with the partner's own CQ substituted for silence, proving both the no-abort behaviour and that the retry backstop still eventually gives up. Existing 6.6/5.9 genuine-third-party tests and the 460 retry-exhaustion test pass unmodified. Per dev-task §5, also added qa/d-caller-020-working-cq-false-abort-verify/ — a standalone tool that synthesises and decodes real FT8 audio (qa/rr-study/synth_wav.py + the real Ft8Decoder/libft8 P/Invoke) and drives the real, unmodified QsoAnswererService/QsoCallerService with it, closing the gap unit tests alone left (hand-authored DecodeResult strings never actually round-tripped through real FT8 packing). Verified PASS with the fix, and a deliberate control run with the fix reverted reproduces the exact regression on both services (see live-reports/). Full suite 1145/1145, dotnet build -c Release 0 warnings/0 errors. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
QA sign-off. Reviewed the actual diff, not just the commit message. Fix matches the dev-task exactly — narrows the abort condition in both Tests: new coverage drives the full retry-exhaustion cycle proving both halves — partner's own CQ no longer aborts, and the existing retry-count backstop still eventually gives up on genuine silence (no infinite-retry regression introduced). Existing Live verification exceeds the dev-task's own bar — the harness re-synthesises and re-decodes real FT8 audio through the actual CI green on all three platforms, mergeable. Approving to merge as-is. |
Summary
QsoAnswererService.HandleWaitReportAsyncandQsoCallerService.HandleWaitRr73Asyncaborted the QSO the instant they decoded any message from the partner not addressed to us — including the partner simply re-transmitting their own CQ (dest == "CQ") because they hadn't decoded us yet, which is normal early in a retry sequence, not evidence they've moved on.logs/openswfz-20260714T171230Z.log, EA1FUB): one retry fired correctly, then the partner's own CQ re-decode ended the QSO outright ("timing was impeccable, but the application just decided to end the whole qso").dest.Equals("CQ", OrdinalIgnoreCase)from the abort condition in both services; falls through to the existing "no matching message" retry/watchdog backstop instead. Genuine third-party addressing (a different real callsign) still aborts immediately, unchanged.mainbefore that merge.Test plan
QsoAnswererServiceTests: partner re-transmitting own CQ inWaitReportdoes not abort; drives the same retry-exhaustion cycle pattern as the existing silence-based test to confirm the retry backstop still eventually gives up (AC-1, AC-5).QsoCallerServiceTests: same forWaitRr73(AC-3).6.6(WaitReport_PartnerWorksOther_AbortsToIdle) and5.9(WaitRr73_PartnerWorkingOther_Aborts) genuine-third-party tests pass unmodified (AC-2, AC-4).WaitReport_NoResponse_RetriesThenAborts(line 460) retry-exhaustion test passes unmodified (AC-5).dotnet build OpenWSFZ.slnx -c Release— 0 warnings, 0 errors (AC-6).qa/d-caller-020-working-cq-false-abort-verify/, a standalone tool that genuinely synthesises + decodes real FT8 audio (qa/rr-study/synth_wav.py+ the realFt8Decoder/libft8 P/Invoke) and drives the real, unmodifiedQsoAnswererService/QsoCallerServicewith it — stronger than unit tests, which never round-trip through real FT8 packing. Verified PASS with the fix; a deliberate control run with the fix reverted reproduces the exact regression on both services (seelive-reports/).🤖 Generated with Claude Code