bf9d8a5ed3
6 supplementary measures (M410-M420) were silently overwritten by metalworking duplicates in measureByID lookups, so robot-cell electrical patterns resolved to chip-extraction/cleaning fallbacks instead of equipotential bonding, creepage, EMC, or hose-burst protection. Rename supplementary IDs to M475-M480 and rewire 13 affected pattern references in robot_cell + robot_cell_ext. HP1640 (direct contact with live parts, GT 2.2): priority 98->99, drop RequiredEnergyTags gate so it fires in robot cells without an electrical tag, expand mitigations to 5 concrete TRBS 2131 / IEC 60204-1 / EN 61140 measures (basic protection, double insulation, earthing, insulation monitoring, equipotential bonding) — was previously losing to HP1688 even though HP1688 describes a different scenario. HP1688 (touch voltage from potential differences): priority 98->96 so it no longer outranks HP1640 for the direct-contact case; mitigations expanded from M410-only to 4 concrete electrical measures. Add regression tests pinning HP1640 contact-protection resolution and M475 = Potentialausgleich. Existing TestGetProtectiveMeasureLibrary_- UniqueIDs now actually enforces uniqueness (previously masked by last-wins map override). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
2.4 KiB
Go
85 lines
2.4 KiB
Go
package iace
|
|
|
|
import "testing"
|
|
|
|
// TestHP1640_ResolvesToContactProtection pins the GT-2.2 fix: the "direct
|
|
// contact with live parts" pattern must resolve to electrical-contact-protection
|
|
// measures (basic protection, double insulation, earthing, equipotential
|
|
// bonding), not to mechanical fallbacks like chip extraction.
|
|
func TestHP1640_ResolvesToContactProtection(t *testing.T) {
|
|
measureByID := make(map[string]ProtectiveMeasureEntry)
|
|
for _, m := range GetProtectiveMeasureLibrary() {
|
|
measureByID[m.ID] = m
|
|
}
|
|
|
|
patterns := GetRobotCellPatterns()
|
|
var hp1640 *HazardPattern
|
|
for i := range patterns {
|
|
if patterns[i].ID == "HP1640" {
|
|
hp1640 = &patterns[i]
|
|
break
|
|
}
|
|
}
|
|
if hp1640 == nil {
|
|
t.Fatal("HP1640 not found in robot cell patterns")
|
|
}
|
|
|
|
if len(hp1640.SuggestedMeasureIDs) < 3 {
|
|
t.Errorf("HP1640 should suggest at least 3 measures, got %d", len(hp1640.SuggestedMeasureIDs))
|
|
}
|
|
|
|
for _, mid := range hp1640.SuggestedMeasureIDs {
|
|
m, ok := measureByID[mid]
|
|
if !ok {
|
|
t.Errorf("HP1640 references non-existent measure %s", mid)
|
|
continue
|
|
}
|
|
if m.HazardCategory != "electrical" {
|
|
t.Errorf("HP1640 measure %s (%q) has HazardCategory=%s, expected electrical",
|
|
mid, m.Name, m.HazardCategory)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestHP1688_M475IsPotentialausgleich pins the M475 rename: HP1688 (touch
|
|
// voltage from potential differences) must resolve M475 to the equipotential
|
|
// bonding measure, not to the metalworking chip extraction that previously
|
|
// occupied M410 and overwrote the electrical definition.
|
|
func TestHP1688_M475IsPotentialausgleich(t *testing.T) {
|
|
measureByID := make(map[string]ProtectiveMeasureEntry)
|
|
for _, m := range GetProtectiveMeasureLibrary() {
|
|
measureByID[m.ID] = m
|
|
}
|
|
|
|
m, ok := measureByID["M475"]
|
|
if !ok {
|
|
t.Fatal("M475 not defined — supplementary rename did not land")
|
|
}
|
|
if m.HazardCategory != "electrical" {
|
|
t.Errorf("M475 must be HazardCategory=electrical, got %s (%q)", m.HazardCategory, m.Name)
|
|
}
|
|
|
|
patterns := GetRobotCellPatternsExt()
|
|
var hp1688 *HazardPattern
|
|
for i := range patterns {
|
|
if patterns[i].ID == "HP1688" {
|
|
hp1688 = &patterns[i]
|
|
break
|
|
}
|
|
}
|
|
if hp1688 == nil {
|
|
t.Fatal("HP1688 not found in robot cell ext patterns")
|
|
}
|
|
|
|
found := false
|
|
for _, mid := range hp1688.SuggestedMeasureIDs {
|
|
if mid == "M475" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("HP1688 must reference M475 (Potentialausgleich), got %v", hp1688.SuggestedMeasureIDs)
|
|
}
|
|
}
|