qet-mcp: count duplicate labels per plant and location

qet_check reported -F1 as a duplicate master when one sits in +UV1 and one
in +UV2, although they are two devices: the place is part of the name, as
the %M/%LM label formulas show it and as IEC 81346 tools treat it. Group
the two duplicate-label checks by label and the effective place, the
element's own plant/location or else its folio's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DaTweety
2026-10-17 21:51:57 +02:00
parent 8c5a16d50e
commit f325b8001e
2 changed files with 34 additions and 6 deletions
+18 -6
View File
@@ -2772,22 +2772,34 @@ def tool_element_search(directory: str, query: str = "", link_type: str | None =
# either would bury the real findings.
# - "simple" elements are checked for duplicates too but only as a warning:
# industrial.qet reuses V1..V6 across folios on purpose.
#
# A label names one device per place: the same "-F1" in two distribution
# boards (+UV1-F1, +UV2-F1) is two devices, as in IEC 81346 / EPLAN. The
# place is the element's own plant/location, else its folio's -- what the
# label formulas %M/%LM show. element_nomenclature_view carries only the
# element's, so these two checks read the tables.
_LABELS_PER_PLACE_SQL = (
"SELECT ei.label AS label, "
"COALESCE(NULLIF(ei.plant,''), di.plant, '') AS plant, "
"COALESCE(NULLIF(ei.location,''), di.locmach, '') AS location, COUNT(*) AS n "
"FROM element_info ei JOIN element e ON ei.element_uuid = e.uuid "
"JOIN diagram_info di ON di.diagram_uuid = e.diagram_uuid "
"WHERE COALESCE(ei.label,'') <> '' AND e.type = '{type}' "
"AND COALESCE(LOWER(TRIM(ei.exclude_from_bom)), '') NOT IN ('true', '1', 'yes', 'on') "
"GROUP BY ei.label, 2, 3 HAVING n > 1 ORDER BY n DESC, ei.label")
CHECKS = {
"duplicate_master_labels": {
"severity": "error",
"note": "Two master elements with the same label are ambiguous in every "
"report that keys on it (BOM, cross-references, wiring list).",
"sql": "SELECT label, COUNT(*) AS n FROM element_nomenclature_view "
"WHERE COALESCE(label,'') <> '' AND element_type = 'master' "
"GROUP BY label HAVING n > 1 ORDER BY n DESC, label",
"sql": _LABELS_PER_PLACE_SQL.format(type="master"),
},
"duplicate_simple_labels": {
"severity": "warning",
"note": "Legitimate when a label is reused on purpose across folios "
"(industrial.qet does); worth a look otherwise.",
"sql": "SELECT label, COUNT(*) AS n FROM element_nomenclature_view "
"WHERE COALESCE(label,'') <> '' AND element_type = 'simple' "
"GROUP BY label HAVING n > 1 ORDER BY n DESC, label",
"sql": _LABELS_PER_PLACE_SQL.format(type="simple"),
},
"unlabelled_masters": {
"severity": "warning",
+16
View File
@@ -5828,6 +5828,22 @@ class Integration(unittest.TestCase):
line = [l for l in (out["stdout"] + out["stderr"]).splitlines() if l.startswith("DB ")][0]
self.assertEqual(json.loads(line[3:]), [{"wire_number": "W1"}])
def test_duplicate_labels_are_counted_per_location(self):
"""-F1 in two distribution boards is two devices: the folio's
location (+UV1, +UV2) is part of the name, as %LM shows it. KM1 on
+UV1 and +UV2 is fine, a second KM1 on +UV2 is the finding."""
base = self.sb.new(folios=3)
ops = []
for folio, ort in enumerate(("UV1", "UV2", "UV2")):
ops += [{"op": "set_folio", "folio": folio, "property": "locmach", "value": ort},
{"op": "add_element", "id": f"k{folio}", "folio": folio, "path": COIL,
"x": 100, "y": 100},
{"op": "set_label", "folio": folio, "element": f"$k{folio}", "label": "KM1"}]
r = self.ok(self.sb.edit(base, ops))
found = {f["check"]: f for f in m.tool_check(BINARY, r["output"])["findings"]}
self.assertEqual(found["duplicate_master_labels"]["rows"],
[{"label": "KM1", "plant": "", "location": "UV2", "n": 2}])
def test_check_fires_on_a_project_with_known_defects(self):
"""Newly placed elements store NULL where a loaded file stores '', and
`col = ''` matches only the second: the first version of these checks