Fix phantom "Important:" header stealing a taking-fire report's deadline

Turned out to be one bug, not two: "Answer by <time>" phrasing was
already covered by _TAKING_FIRE_TIME_RE ('before|by <time>'). The real
bug was the last-resort bare-"<Name>:" header fallback matching a
same-message "Important:" follow-up line as a brand new named entity
(nothing excluded common prose lead-ins), creating a bogus
Target#Important that stole the deadline into its own requested_time
instead of the real report's. Fixed with a blocklist on that fallback
rule (important/note/warning/attention/caution/alert/reminder/priority).
New regression test, 55 total passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 22:09:15 +02:00
co-authored by Claude Sonnet 5
parent 6a61bffb22
commit 6e34f50b6a
3 changed files with 61 additions and 15 deletions
+30
View File
@@ -383,3 +383,33 @@ def test_infantry_taking_fire_bearing_distance_short_range():
assert coord == Coord("H", 7, 8, 4)
assert shell is Shell.HE
assert requested_time == "10:17:37"
def test_taking_fire_important_followup_line_does_not_steal_the_deadline():
"""A real user-pasted message: a same-report "Important: ... Answer by
<time>" follow-up line was being misread as a brand new named entity
header (the last-resort bare-"<Name>:" fallback matched "Important:"
itself), creating a bogus Target#Important that stole the actual
report's own deadline into that wrong entry instead of the real
StrikeRequest. "Answer by <time>" is also a deadline phrasing
_TAKING_FIRE_TIME_RE already covers (any 'before'/'by <time>') --
once the phantom split stops happening, it resolves correctly with
no extra fix needed."""
text = ("Infantry#4 taking fire!\n"
"Requesting <u><b>TEAR Shell</b></u> first, then <u><b>HE Shell</b></u>,\n"
"at bearing <b>308°</b>, distance <b>1.86km</b> from our position, <b>N2 0:9</b>\n"
"<u>Important:</u> <u><b>TEAR Shell</b></u> first, then <u><b>HE Shell</b></u>.\n"
"Answer by <u>10:30:00</u>")
info = ocr.parse_text(text)
assert (TargetType.UNKNOWN, "Important") not in info.targets
assert (TargetType.INFANTRY, "4") in info.allies
assert (TargetType.INFANTRY, "4") not in info.targets
assert (TargetType.STRIKE_REQUEST, "Infantry4") in info.targets
_, _, coord, shell, requested_time = info.targets[(TargetType.STRIKE_REQUEST, "Infantry4")]
assert requested_time == "10:30:00"
# Known gap, not asserted as fixed here: only the FIRST shell of a
# "X first, then Y" sequence is captured -- see TODO.md.
assert shell is Shell.TEAR