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
+16 -1
View File
@@ -375,6 +375,17 @@ _NAMED_HEADER_RE = re.compile(rf"^{_TYPE_ID_FRAGMENT}\s*:?\s*(.*)$")
# one), nothing else anchors this match, so an optional colon would
# false-positive on an ordinary clue-continuation line's leading word.
_BARE_NAME_HEADER_RE = re.compile(r"^([A-Za-z][A-Za-z0-9]*)\s*:\s*(.*)$")
# Even requiring the colon isn't quite enough: a prose lead-in word right
# before a genuinely useful follow-up line ("Important: TEAR Shell first,
# then HE Shell.") false-positives the same way -- confirmed live against
# a real taking-fire message, where "Important:" got read as a brand new
# named entity ("Target#Important"), stealing the actual report's own
# "Answer by <time>" deadline into that bogus entry instead of the real
# one. None of these read as an actual thing being spotted/named, only
# ever as a prose interjection.
_BARE_NAME_HEADER_BLOCKLIST = {
"important", "note", "warning", "attention", "caution", "alert", "reminder", "priority",
}
# Ad-hoc enemy installations are named in plain English rather than given a
# Type#N id ("Enemy Signal Station:", "Bearing 034 from Enemy Signal
@@ -908,7 +919,11 @@ def parse_intel_blocks(text: str) -> list[dict]:
# 'Target'), not a Reference Point, a named thing giving its own
# clues is being spotted, not a fixed landmark spotters aim off
# of, same reasoning as the "Target is at-" calibration line.
bare_m = next((m for c in candidates if (m := _BARE_NAME_HEADER_RE.match(c))), None)
bare_m = next(
(m for c in candidates if (m := _BARE_NAME_HEADER_RE.match(c))
and m.group(1).lower() not in _BARE_NAME_HEADER_BLOCKLIST),
None,
)
if bare_m:
flush()
name = bare_m.group(1)