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 -1
View File
@@ -253,7 +253,7 @@ public sealed class OperatingPosition
/// has not checked cannot lose an exchange or log nonsense.
public Qso LogContact()
{
if (!Entry.IsComplete)
if (!IsEntryComplete)
{
throw new InvalidOperationException($"the exchange for {Entry.Call} is not complete");
}
@@ -353,6 +353,13 @@ public sealed class OperatingPosition
/// Moves to the next box the operator types in. On top of the report boxes
/// the entry itself steps over, a contest can say a box is not for this
/// station: CQ WW RTTY asks only the US and Canada for a state.
/// True when everything this contest asks for this station has been typed.
/// A box the walk steps over is not asked for, so it does not hold the
/// contact up: `MoveFocus` and this read the same rule.
public bool IsEntryComplete => Entry.IsComplete(Applies);
private bool Applies(ExchangeField field) => !Contest.SkipsField(field, Country());
public void MoveFocus(bool forward)
{
CountryLookup? their = Country();