Let the walk and the completeness check read one rule

A box the walk between the entry boxes steps over cannot be typed in, so it
must not hold the contact back either. `EntryFields.IsComplete` counted every
box marked required, while `MoveFocus` stepped over the ones the contest does
not ask this station for, so a contest with a box for some stations only
could lock the operator out of his own log.

The seven contests the scoring audit named do not do that any more —
`bae40bb` gave each of them the boxes N1MM shows, and fifteen reproductions
across all seven and both station types log cleanly — but the rule they broke
was still there to break again. Completeness now takes the same
applicability rule the cursor uses, and `OperatingPosition` answers it in one
place for the entry window, the ESM window and logging alike.

The audit is marked up for the three findings that are already fixed and for
item 14, which turns out to be what N1MM does rather than a fault.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
This commit is contained in:
2026-09-10 20:33:30 +00:00
co-authored by Claude Opus 5
parent e56d6096f3
commit 211298e04c
6 changed files with 161 additions and 7 deletions
+8
View File
@@ -24,10 +24,16 @@ Notable examples: all six WAE RTTY instances matched every compared field. Field
1. **P1 — Valid exchanges cannot be logged in seven contest definitions.** [EntryFields.cs](../src/Nonemm.Session/EntryFields.cs), line 90, requires every field marked required. `OperatingPosition.MoveFocus` skips fields according to `Contest.SkipsField`, but `LogContact` and the ESM window still use that unconditional completeness check. In OK/OM DX, a Japanese station sends a serial; the county field is skipped but its emptiness prevents logging. The same problem affects CQ 160, ARRL 10M, REF, Ukrainian DX, YO DX HF and Mexico RTTY. Filling every applicable field produced `IsComplete == false` in all seven reproductions. Completion must use the same applicability rules as cursor movement. Do not fix this by requiring fabricated values in skipped boxes.
**Fixed 2026-09-10.** `bae40bb` gave each of these contests the boxes N1MM shows, and none of them now marks a box required that the walk steps over: fifteen reproductions across all seven contests and both station types log cleanly. `EntryFields.IsComplete` takes the applicability rule as well, so the cursor and the completeness check read the same answer and this cannot come back; see `SkippedFieldTests`.
2. **P1 — Excluded contacts still score.** [ContestLog.cs](../src/Nonemm.Contests/ContestLog.cs), line 48, does not inspect `Qso.IsClaimed`. A CQ WW JA contact with `IsClaimed=false` still received 3 points and two multipliers, producing a score of 6. The edit dialog exposes this flag, statistics filter it, and Cabrillo omits the contact, so the user sees inconsistent results. The local N1MM `Contest.ComputePoints`, line 437, explicitly returns zero for an unclaimed QSO. Apply the exclusion consistently to points and multiplier eligibility, and verify N1MM's duplicate treatment separately.
**Fixed.** `ContestLog.Judge` returns nothing for an unclaimed contact, and `Index` leaves it out of the dupe and multiplier searches; see `ExcludedContactTests`.
3. **P1 — Three Cabrillo exporters replace actual serials with `001`.** [Arrl10Metre.cs](../src/Nonemm.Contests/Rules/Arrl10Metre.cs), line 68; [UkrainianDx.cs](../src/Nonemm.Contests/Rules/UkrainianDx.cs), line 80; [YoDxHf.cs](../src/Nonemm.Contests/Rules/YoDxHf.cs), line 75. Each calls `SentExchangeFor(me)` when formatting a contact. For a DX entrant that method returns the initial serial, not `qso.SentNumber`. All three exported `001` for a QSO whose sent serial was 42. The actual serial must be used where the entrant sends serial numbers. ARRL explicitly requires sequential DX serials in its [10M rules](https://contests.arrl.org/ContestRules/10M-Rules.pdf).
**Fixed.** All three write `qso.SentNumber` where the entrant sends serial numbers.
4. **P1 — All Asian implements the wrong rules for Asian entrants.** [AllAsian.cs](../src/Nonemm.Contests/Rules/AllAsian.cs), lines 37 and 46, multiplies every Asian entrant's band points by three and always uses WPX prefixes. Reproductions: JA-to-JA on 20M scored 3 instead of 0; JA-to-UA9 scored 3 instead of 1; JA-to-K1 produced prefix `K1` instead of country `K`. Asian entrants count DXCC entities, same-entity QSOs do not score, and the threefold factor applies to non-Asian contacts. Both the local N1MM `CAA` implementation and the [2026 JARL rules](https://www.jarl.org/English/4_Library/A-4-3_Contests/aadx_eng.html) distinguish these cases. The existing tests only cover a non-Asian entrant.
5. **P1 — BARTG HF and Sprint are merged into one incompatible definition.** [BartgSprint.cs](../src/Nonemm.Contests/Rules/BartgSprint.cs) uses report, serial and time, and countries/areas per band, but advertises `BARTGRTTYS` and `BARTG-SPRINT`. [N1mmContestNames.cs](../src/Nonemm.Contests/N1mmContestNames.cs) also maps `BARTGSRTTY` to this class. N1MM has separate `CBARTGSpring` and `CBARTGSprint` classes. The January Sprint exchanges a serial only and counts countries/areas once across bands, as specified in the [BARTG Sprint rules](https://bartg.org.uk/wp-content/uploads/2025/05/bartg-sprint-rules-2025-v3.pdf). Split the definitions and preserve each one's identity, exchange, multiplier scope and export format. Agreement on the supplied March HF log does not validate Sprint support.
@@ -50,6 +56,8 @@ Notable examples: all six WAE RTTY instances matched every compared field. Field
14. **P2 — The score window mixes unweighted and weighted multiplier counts.** [ScoreWindow.axaml.cs](../src/Nonemm.App/Windows/ScoreWindow.axaml.cs) sums Boolean flags for each band but uses `Tally.TotalMultipliers` for the total. A single WAE multiplier on 80M appears as 1 in the band row and contributes 4 to the total. QTC rows are also counted in the QSO column even though `Contest.IsContact` identifies them as traffic. Display raw multipliers, weights and QTC counts consistently. This does not by itself change WAE's correctly weighted total score.
**Not a fault; this is what N1MM does.** `ScoreRow.AddContact` adds the weight of a WAE multiplier, four on 80M and so on, to the band row and to the total alike, and `ScoreTally.AddMultiplier` has done the same since `d4d0375`. N1MM counts QTC rows as Qs too — `ValidQs` counts every row that reaches the score — and keeps them readable by splitting each WAE band into a row per kind under `Q/QTC`, which the score window here does as well. Taking the QTC rows out of the QSO column would leave N1MM's numbers behind.
**Coverage and remaining limits.** The 26 built-in families are CQ WW, CQ WPX, ARRL DX, IARU, Sweepstakes, WAE, ARRL RTTY Roundup, NAQP, OK/OM DX CW, YOTA, IOTA, EU DX, CQ 160, Mexico RTTY, REF, BARTG, ARRL 10M, Russian DX RTTY, RDAC, YO DX HF, Oceania, Region 1 Field Day, SARTG, All Asian and general logging. CW/SSB/RTTY variants share classes where the registry supplies a mode. This is a subset of [N1MM's supported contests](https://n1mm.hamdocs.com/manual-supported/contests-list/).
The shared engine correctly centralizes incremental dupe/multiplier checks and performs chronological rebuilds for edits and network inserts. However, test success and matching existing rows do not establish correctness for entrant countries, new-entry field generation, excluded contacts, or bands absent from those logs.