fix: QRZ download marked every paper-QSL QSO as QRZ-confirmed

Reported: after a confirmation download they all turn to Y.

The test accepted qsl_rcvd = Y as a confirmation. That field is the operator's
OWN paper-QSL flag, which they uploaded to QRZ in the first place — so QRZ handed
it back and OpsLog read it as QRZ's answer. On a log full of paper cards that is
most of the log, which is exactly what was seen.

Only QRZ's own statement counts now: app_qrzlog_status = C, or the ADIF field
qrzcom_qso_download_status = Y that QRZ sets for it. LoTW and eQSL confirmations
are explicitly not accepted either — they are other services' answers, and the
column says QRZ.

This status feeds award slots, so a false Y is a QSO counted as confirmed when it
is not. That asymmetry is why the rule is narrow rather than generous, and the
test lists the negatives as deliberately as the positives.

The changelog warns that earlier downloads may already have set the column
wrongly — the fix stops it happening again but does not undo it.
This commit is contained in:
2026-07-29 17:59:04 +02:00
parent 482f81fe45
commit 284a7a18c7
3 changed files with 68 additions and 13 deletions
+17 -11
View File
@@ -10068,21 +10068,27 @@ func (a *App) runDownloadConfirmations(svc extsvc.Service, cfg extsvc.ExternalSe
}
// qrzRecordConfirmed reports whether a QRZ FETCH ADIF record represents a
// confirmed QSO. QRZ's confirmation marker isn't clearly documented, so we
// accept the likely candidates; the download's one-time field dump lets us
// pin the exact field against real data and tighten this if needed.
// QSO confirmed BY QRZ.COM.
//
// It used to accept qsl_rcvd = Y as well, and that was wrong: qsl_rcvd is the
// operator's own PAPER QSL flag, which they uploaded to QRZ themselves. Any QSO
// with a paper card was therefore marked QRZ-confirmed on download — reported as
// "they all turn to Y" (2026-07-29), and on a log full of paper QSLs that is
// most of it.
//
// A QRZ confirmation is QRZ's own statement, and only two fields carry it:
//
// app_qrzlog_status = C QRZ's confirmed marker on the record
// qrzcom_qso_download_status = Y the ADIF field QRZ sets for it
//
// Anything else is a claim from some other source and must not be read as a QRZ
// confirmation — this status feeds award slots, so a false Y is a QSO counted as
// confirmed when it is not.
func qrzRecordConfirmed(rec adif.Record) bool {
if strings.EqualFold(rec["qsl_rcvd"], "Y") {
return true
}
if strings.EqualFold(rec["qrzcom_qso_download_status"], "Y") {
return true
}
switch strings.ToUpper(strings.TrimSpace(rec["app_qrzlog_status"])) {
case "C", "Y":
return true
}
return false
return strings.EqualFold(strings.TrimSpace(rec["app_qrzlog_status"]), "C")
}
// enrichContactedFromCty fills a QSO's contacted-station country/DXCC/zones