fix(hy3): route H1/H2 DQ detail to the matching slot for a prelim+finals double-DQ - #30
Open
fsalum wants to merge 2 commits into
Open
fix(hy3): route H1/H2 DQ detail to the matching slot for a prelim+finals double-DQ#30fsalum wants to merge 2 commits into
fsalum wants to merge 2 commits into
Conversation
The E1/F1 distance field (6 chars) can contain non-integer values — e.g. "2.4" for 2.4 miles in open-water meets. safe_cast(int, "2.4") raised ValueError and fell back to int() = 0, permanently losing the value. Type Event.distance as float and parse it with safe_cast(float, ...) so these distances survive. Integer distances now come through as floats (100 -> 100.0); this is an API-compatible data change, so callers reading distance as an int should coerce. Blank/non-numeric fields still yield 0.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A swim disqualified in both prelims and finals of the same event resolves
to a single entry carrying both prelim_dq_info and finals_dq_info. h1_parser
resolved the detail line to a slot by fixed finals -> swimoff -> prelim
priority and asserted the chosen slot's stored code equalled the H1's code.
Records arrive finals-first, so a prelim H1 was checked against the already
populated finals slot: when the two DQ infractions differ (common in IM and
championship formats) the codes mismatch and h1_parser raised
AssertionError("DQ Codes should match in the H1 line"), aborting the reason
string. When the two slots happened to share a code no assertion fired but
the reason was still attached to the wrong slot.
Resolve instead to the slot whose stored DQ code matches the H1's own code,
preferring an unfilled slot so the two H1s of a same-code double-DQ fill
their own slots in file order. No-op when no populated, unfilled slot's code
matches — the same graceful degrade the no-slot case already used; the DQ
status and code are recorded by the E2/F2 result line regardless.
h2_parser used the identical finals-first resolution with no assertion, so
H2 detail text was silently mis-attributed in the same double-DQ case. H2
cannot match on its own code (it is the stroke/leg infraction, not the
slot's DisqualificationCode), so h1_parser now records the slot it resolved
and h2_parser attaches its detail to that same slot, falling back to the
first populated slot when no H1 preceded it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
h1_parserraisesAssertionError("DQ Codes should match in the H1 line")onany swim disqualified in both prelims and finals of the same event for
different infractions — a common case in IM events and championship
prelims/finals formats.
Such a swim's prelim and finals arrive as separate
E1/E2records that resolveto one shared
EventEntrycarrying bothprelim_dq_infoandfinals_dq_info.h1_parserresolves the H1 detail line to a slot by fixedfinals -> swimoff -> prelimpriority, takes the first populated slot, andthen asserts that slot's stored DQ code equals the H1's own code. Records arrive
finals-first, so by the time the prelim's H1 is parsed the finals slot is
already populated with a different code:
The assertion aborts the H1 line and the prelim DQ's human-readable reason
string is lost.
Two related latent defects sit behind the visible assertion:
but finals-first resolution still attaches the reason to the wrong slot (both
H1s land on finals).
h2_parseruses the identical finals-first resolution with no assertion atall, so H2 detail text is silently mis-attributed in the same double-DQ case.
Fix
h1_parsernow resolves to the slot whose stored DQ code matches the H1'sown code, preferring a slot not yet filled so the two H1s of a same-code
double-DQ fill their own slots in file order. When no populated, unfilled slot's
code matches, it degrades to a no-op — the same graceful behavior the existing
no-slot guard already used (the DQ status and code are recorded by the E2/F2
result line regardless, so only the reason string is ever at stake). The
assertis removed.h2_parsercannot match on its own code — an H2's 2-char code is the specificstroke/leg infraction (e.g.
2L), not the slot'sDisqualificationCode(e.g.the relay-leg code
6A). Soh1_parserrecords the slot it resolved (in theoptsdict threaded through every line parser) andh2_parserattaches itsdetail to that same slot, falling back to the first populated slot when no H1
preceded it.
Tests
Added to
tests/hy3/line_parsers/test_h_dq_parsers.py:(previously raised);
6A) still attaches;All existing DQ-parser tests continue to pass.