From fb2953c3243f63d3405e28074fa2e187c598c21f Mon Sep 17 00:00:00 2001 From: Umut CAN Date: Thu, 24 Sep 2026 12:48:56 +0300 Subject: [PATCH] fix(understand): a line number is not an equipment tag parse_tag started a token at the first letter, so '100-P-001', a line number that begins with its size, read as the pump tag P-001. The review of the network engine found this. On a P&ID the phantom tag can capture a valve beside the line as equipment, or collide with the real pump P-001. A token that is the tail of a word beginning with a digit is no longer a tag. The same text still yields T101 in 'LINE 100-P-001 TO T101', and P-001 alone is still a tag. The new test failed before this change; the label, network, describe, scale, cable and plant-pair suites all pass (160 tests). Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd --- engineering/understand/labels.py | 10 ++++++++-- tests/test_understand_labels.py | 10 ++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/engineering/understand/labels.py b/engineering/understand/labels.py index d9a76b8..bc03faa 100644 --- a/engineering/understand/labels.py +++ b/engineering/understand/labels.py @@ -229,9 +229,15 @@ def parse_tag(text: str | None) -> str | None: ``"Т4100"`` (Cyrillic Т) -> ``"T4100"``; ``"pump M41A"`` -> ``"M41A"``; ``"CP-M82"`` stays ``"CP-M82"``. A size label (``DN20``, ``SMS51``), a pressure rating (``PN16``) or an IP code (``IP65``) is not a tag; a token - that keeps a Cyrillic letter without a Latin twin is not one either. + that keeps a Cyrillic letter without a Latin twin is not one either, and + neither is the tail of a word that begins with a digit - a line number + such as ``100-P-001`` names a pipe, not the pump ``P-001``. """ - for match in _TAG_TOKEN.finditer(plain(text)): + source = plain(text) + for match in _TAG_TOKEN.finditer(source): + word_start = max(source.rfind(" ", 0, match.start()), source.rfind("\n", 0, match.start())) + if source[word_start + 1 : match.start()][:1].isdigit(): + continue token = fold_lookalikes(match.group(0)).rstrip(".-") if not _TAG_RE.fullmatch(token): continue diff --git a/tests/test_understand_labels.py b/tests/test_understand_labels.py index 51264b5..b159feb 100644 --- a/tests/test_understand_labels.py +++ b/tests/test_understand_labels.py @@ -163,6 +163,16 @@ def test_text_without_a_tag(): assert parse_tag(None) is None +def test_a_line_number_is_not_an_equipment_tag(): + # A line number starts with its size: read as a tag, '100-P-001' would give + # 'P-001', which can capture a valve beside the line or collide with a real + # pump P-001. A word that begins with a digit holds no tag. + assert parse_tag("100-P-001") is None + assert parse_tag('2"-P-1001-A1') is None + assert parse_tag("LINE 100-P-001 TO T101") == "T101" + assert parse_tag("P-001") == "P-001" # the pump itself is still a tag + + # -- panels and wiring callouts ----------------------------------------------------