Compare commits

...

10 Commits

Author SHA1 Message Date
Benjamin Admin bf9d8a5ed3 fix(iace): resolve M-ID collisions for electrical/pressure patterns
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>
2026-05-16 10:12:55 +02:00
Benjamin Admin d45e08e25f fix: reduce Playwright timeout 180s→60s, increase poll limit 15→25min 2026-05-16 00:47:28 +02:00
Benjamin Admin 3dbf3aa34a feat: HTTP fallback for text extraction when Playwright times out
BMW Impressum/Cookie pages timeout in Playwright (>180s) because the
SPA has many sub-links to follow. But the HTML source already contains
the text (SSR). New fallback: direct HTTP GET + HTML tag stripping.

Order: 1. Consent-tester (Playwright, 180s) → 2. HTTP GET (30s)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 23:16:10 +02:00
Benjamin Admin 77308b783f debug: log CreateMitigation errors 2026-05-15 21:52:04 +02:00
Benjamin Admin 9797234ff6 fix(iace): add abbreviations + action words to genericSafetyTerms
KSS, EMV, ESD, DCS, PLR, SIL, HMI, SPS, RCD, LOTO, PSA are
abbreviations that should NOT trigger the relevance filter.
bersten, platzen, abspringen, spritzen, einatmen, ausrutschen,
herabfallen, durchschlaegen, wegschleudern are action words that
appear in many patterns and don't indicate a specific machine.

Fixes: HP1633-HP1675 (KSS patterns) were filtered out because
"kss" was not in the narrative but also not in genericSafetyTerms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 16:05:20 +02:00
Benjamin Admin 7080eb5f45 fix(iace): boost robot cell priorities 96-99, remove debug code
Robot cell patterns now fire BEFORE generic patterns (Priority 96-99
vs generic 85-95). This ensures pattern-specific SuggestedMeasureIDs
(M420 for KSS, M410 for Potentialausgleich) reach the hazard.

Removed debug fmt.Println statements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 16:01:52 +02:00
Benjamin Admin c93cf2719a debug: trace M420 in Priority-1 loop 2026-05-15 14:56:05 +02:00
Benjamin Admin 7a27dbc01b debug: check M420 in measureByID 2026-05-15 14:53:49 +02:00
Benjamin Admin de35dfce18 debug: add pattern-measure count to init step details 2026-05-15 14:51:26 +02:00
Benjamin Admin 69240faf24 fix(iace): accumulate SuggestedMeasureIDs across dedup'd patterns
When multiple patterns match the same category+zone, the first creates
the hazard and later patterns add their SuggestedMeasureIDs to the
existing hazard. This ensures KSS-specific measures (M420) reach the
hazard even if a generic pattern created it first.

seenCatZone changed from map[string]bool to map[string]uuid.UUID
to track which hazard ID was created for each dedupKey.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 14:45:37 +02:00
8 changed files with 226 additions and 106 deletions
@@ -202,9 +202,9 @@ export function ComplianceCheckTab() {
setActiveCheckId(check_id)
localStorage.setItem(STORAGE_KEY_CHECK_ID, check_id)
// Poll for results (max 15 min = 300 polls x 3s)
// Poll for results (max 25 min = 500 polls x 3s)
let attempts = 0
while (attempts < 300) {
while (attempts < 500) {
await new Promise(r => setTimeout(r, 3000))
const pollRes = await fetch(`/api/sdk/v1/agent/compliance-check?check_id=${check_id}`)
if (!pollRes.ok) { attempts++; continue }
@@ -235,7 +235,7 @@ export function ComplianceCheckTab() {
}
attempts++
}
if (attempts >= 300) {
if (attempts >= 500) {
localStorage.removeItem(STORAGE_KEY_CHECK_ID); setActiveCheckId('')
throw new Error('Zeitlimit ueberschritten (15 Min)')
}
@@ -160,32 +160,35 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
}
created := 0
seenCatZone := make(map[string]bool)
seenCatZone := make(map[string]uuid.UUID) // dedupKey → hazardID
catCount := make(map[string]int)
for _, mp := range matchOutput.MatchedPatterns {
// Narrative relevance filter: skip patterns whose zone/scenario
// mentions machine-specific terms that don't appear in our components
// Narrative relevance filter
if !isPatternRelevant(mp, narrativeText, compNames) {
continue
}
for _, cat := range mp.HazardCats {
// Per-category cap: limit hazards per category based on relevance
maxForCat := categoryHazardCap(cat, len(comps))
if catCount[cat] >= maxForCat {
continue
}
// Dedup by category + normalized zone
zoneKey := normalizeZoneKey(mp.ZoneDE)
if zoneKey == "" {
zoneKey = mp.PatternID
}
dedupKey := cat + ":" + zoneKey
if seenCatZone[dedupKey] {
// If this dedupKey already exists but current pattern has
// SuggestedMeasureIDs, add them to the existing hazard
if existingHzID, exists := seenCatZone[dedupKey]; exists {
if len(mp.SuggestedMeasureIDs) > 0 {
existing := hazardPatternMeasures[existingHzID]
hazardPatternMeasures[existingHzID] = append(existing, mp.SuggestedMeasureIDs...)
}
continue
}
seenCatZone[dedupKey] = true
name := mp.PatternName
if name == "" {
@@ -226,8 +229,8 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
if cerr == nil {
created++
catCount[cat]++
seenCatZone[dedupKey] = hz.ID
hazardIDsByCategory[cat] = append(hazardIDsByCategory[cat], hz.ID)
// Remember this pattern's suggested measures for this hazard
if len(mp.SuggestedMeasureIDs) > 0 {
hazardPatternMeasures[hz.ID] = mp.SuggestedMeasureIDs
}
@@ -289,6 +292,7 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
if !ok {
continue
}
rt := iace.ReductionType(entry.ReductionType)
if rt == "" {
rt = iace.ReductionTypeInformation
@@ -297,7 +301,9 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
HazardID: hazID, ReductionType: rt,
Name: entry.Name, Description: entry.Description,
})
if cerr == nil {
if cerr != nil {
fmt.Printf("MEASURE-ERROR: mid=%s name=%s err=%v\n", mid, entry.Name, cerr)
} else {
created++
added++
usedIDs[mid] = true
@@ -324,7 +330,12 @@ func (h *IACEHandler) InitializeProject(c *gin.Context) {
}
}
}
mitStep = InitStep{Name: "Massnahmen erstellt", Status: "done", Count: created}
patternMeasureCount := 0
for _, mids := range hazardPatternMeasures {
patternMeasureCount += len(mids)
}
mitStep = InitStep{Name: "Massnahmen erstellt", Status: "done", Count: created,
Details: fmt.Sprintf("%d pattern-spezifisch fuer %d Hazards", patternMeasureCount, len(hazardPatternMeasures))}
} else if len(existingMits) > 0 {
mitStep.Details = "Bereits vorhanden"
mitStep.Count = len(existingMits)
@@ -217,6 +217,13 @@ var genericSafetyTerms = map[string]bool{
"leitfaehig": true, "elektrisch": true, "mechanisch": true,
"bedienfeld": true, "display": true, "anzeige": true,
"energie": true, "druck": true, "temperatur": true,
// Abbreviations and synonyms that should not trigger relevance filter
"kss": true, "emv": true, "esd": true, "dcs": true, "plr": true, "sil": true,
"hmi": true, "sps": true, "rcd": true, "loto": true, "psa": true,
// Common action words
"bersten": true, "platzen": true, "abspringen": true, "spritzen": true,
"einatmen": true, "ausrutschen": true, "herabfallen": true,
"durchschlaegen": true, "wegschleudern": true,
// Common structural terms that don't indicate a specific machine
"gesamter": true, "gesamtes": true, "bereichs": true, "stelle": true,
"innen": true, "aussen": true, "transport": true, "seite": true,
@@ -17,7 +17,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"moving_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061", "M062", "M054"},
Priority: 95, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
Priority: 99, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
ApplicableLifecycles: []string{"normal_operation", "setup", "teach_mode", "cleaning", "maintenance", "fault_clearing", "changeover"},
ScenarioDE: "Person befindet sich im Bewegungsbereich des Roboterarms und wird zwischen Roboterarm und feststehenden Anlagenteilen eingeklemmt.",
TriggerDE: "Roboterarm bewegt sich waehrend Person im Gefahrenbereich steht.",
@@ -31,7 +31,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M002", "M061"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person greift ueber oder durch den Schutzzaun und erreicht den Bewegungsbereich des Roboterarms.",
TriggerDE: "Unzureichender Sicherheitsabstand zwischen Schutzzaun-Oberkante und Roboter-Schwenkbereich.",
@@ -45,7 +45,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061", "M054", "M141"},
Priority: 94,
Priority: 99,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing", "changeover"},
ScenarioDE: "Person befindet sich in der Roboterzelle, Schutztuer wird geschlossen und Roboter startet. Person kann den Gefahrenbereich nicht rechtzeitig verlassen.",
TriggerDE: "Schutztuer schliesst waehrend Person im Innenraum. Wiederanlauf des Roboters ohne Quittierung.",
@@ -59,7 +59,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061", "M002"},
Priority: 92,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "changeover", "fault_clearing"},
ScenarioDE: "Roboterarm ueberschreitet Bewegungsbereich und trifft Schutzzaun. Person ausserhalb wird von Zaunteilen oder dem Roboterarm getroffen.",
TriggerDE: "Fehler in der Bahnplanung oder Ausfall der Achsbegrenzung.",
@@ -73,7 +73,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "clamping_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054"},
Priority: 93, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
Priority: 98, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
ApplicableLifecycles: []string{"teach_mode", "setup", "changeover", "fault_clearing"},
ScenarioDE: "Person steht im Bewegungsbereich des Roboterarms und wird von bewegtem Werkzeug oder Greifer getroffen. Geschwindigkeitsreduzierung im Einrichtbetrieb reicht nicht aus.",
TriggerDE: "Roboter bewegt Werkzeug/Greifer mit unerwartet hoher Geschwindigkeit oder in unerwartete Richtung.",
@@ -90,7 +90,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"clamping_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054", "M061"},
Priority: 94, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
Priority: 99, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "changeover", "fault_clearing"},
ScenarioDE: "Person greift in den Bereich des Greifers. Hand wird zwischen Greifbacken und Werkstueck eingeklemmt.",
TriggerDE: "Greiferbacken schliessen waehrend Koerperteil im Greifbereich ist.",
@@ -104,7 +104,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"clamping_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M007", "M141"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "changeover"},
ScenarioDE: "Greifer verliert das Werkstueck waehrend des Transports. Werkstueck faellt herab und trifft Person unterhalb des Roboterarms.",
TriggerDE: "Werkstueck faellt aus Greifer und trifft Person unterhalb des Roboterarms.",
@@ -118,7 +118,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"clamping_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061", "M141"},
Priority: 92,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation"},
ScenarioDE: "Greifer versagt und Werkstueck wird in Richtung Schutzzaun geschleudert. Person ausserhalb der Zelle wird von durchschlagendem Werkstueck getroffen.",
TriggerDE: "Werkstueck wird durch Roboterbewegung weggeschleudert und durchschlaegt die Schutzeinrichtung.",
@@ -135,7 +135,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"entanglement_risk"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M002", "M061", "M003"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person greift an Foerderband und wird zwischen beweglichen und feststehenden Teilen eingeklemmt.",
TriggerDE: "Hand oder Finger geraten zwischen Band und Umlenkrolle oder zwischen Werkstueck und Tunnelrahmen.",
@@ -149,7 +149,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"entanglement_risk", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M002", "M061"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "fault_clearing"},
ScenarioDE: "Person greift durch die Oeffnung im Schutzzaun fuer die Foerderbaender in den Gefahrenbereich des Roboters.",
TriggerDE: "Oeffnung ist zu gross oder Sicherheitsabstand zum Roboter-Schwenkbereich ist zu gering.",
@@ -163,7 +163,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"entanglement_risk"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M008"},
Priority: 91,
Priority: 97,
ApplicableLifecycles: []string{"normal_operation", "setup"},
ScenarioDE: "Werkstueck faehrt ueber das Ende des Transportbandes hinaus, faellt herab und trifft Person am Be-/Entladeplatz.",
TriggerDE: "Mechanischer Anschlag fehlt oder ist beschaedigt.",
@@ -180,7 +180,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M003"},
Priority: 90,
Priority: 97,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person schneidet sich an nicht entgrateten oder scharfkantigen Blechen der Einhausung oder Verkleidung.",
TriggerDE: "Zugaengliche Kanten sind nicht gerundet oder gebrochen.",
@@ -196,8 +196,8 @@ func GetRobotCellPatterns() []HazardPattern {
ID: "HP1630", NameDE: "Pneumatikschlauch springt unter Druck ab", NameEN: "Pressurized hose comes loose",
RequiredComponentTags: []string{"pinch_point"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M420"},
Priority: 91,
SuggestedMeasureIDs: []string{"M480"},
Priority: 97,
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance", "fault_clearing"},
ScenarioDE: "Pneumatikschlauch der Automation springt unter Druck ab und trifft eine Person (Peitscheneffekt).",
TriggerDE: "Befestigung loest sich, Verschraubung wird undicht, Materialermuedung des Schlauchs.",
@@ -210,8 +210,8 @@ func GetRobotCellPatterns() []HazardPattern {
ID: "HP1631", NameDE: "Restdruck in Pneumatik nach Abschaltung", NameEN: "Residual pressure in pneumatics after shutdown",
RequiredComponentTags: []string{"pinch_point"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M420", "M141"},
Priority: 91,
SuggestedMeasureIDs: []string{"M480", "M141"},
Priority: 97,
ApplicableLifecycles: []string{"maintenance", "fault_clearing", "changeover"},
ScenarioDE: "Person loest druckbeaufschlagte Pneumatik-Komponenten die nach Abschaltung noch unter Druck stehen. Teile fliegen unkontrolliert weg und treffen die Person.",
TriggerDE: "Fehlende Druckentlastung. Gesperrte Rueckschlagventile halten Druck.",
@@ -228,7 +228,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{"clamping_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054"},
Priority: 93, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
Priority: 98, MachineTypes: []string{"robotics_cobot", "automotive", "metalworking", "general_industry"},
ApplicableLifecycles: []string{"teach_mode", "setup", "changeover", "fault_clearing"},
ScenarioDE: "Einrichter steht im Schwenkbereich des Roboterarms und wird von bewegtem Greifer oder daran befestigtem Werkzeug verletzt.",
TriggerDE: "Reduzierte Geschwindigkeit im Einrichtbetrieb reicht nicht aus oder wird nicht aktiviert.",
@@ -242,7 +242,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061"},
Priority: 89, MachineTypes: []string{"cnc", "metalworking", "automotive"},
Priority: 96, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Niederdruck-Pumpe fuer Bettspuelung laeuft an waehrend Schutztuer geoeffnet ist. Person bekommt KSS-Spritzer ins Auge oder Gesicht.",
TriggerDE: "Pumpe startet automatisch, kein Verriegelungssignal von Schutztuer zur KSS-Pumpe.",
@@ -255,8 +255,8 @@ func GetRobotCellPatterns() []HazardPattern {
ID: "HP1633", NameDE: "KSS-Versorgungsschlauch platzt oder reisst ab", NameEN: "Coolant supply hose bursts or tears off",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M420"},
Priority: 90, MachineTypes: []string{"cnc", "metalworking", "automotive"},
SuggestedMeasureIDs: []string{"M480"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "maintenance", "fault_clearing"},
ScenarioDE: "KSS-Versorgungsschlauch reisst ab oder platzt. Person in der Naehe wird von abspringendem Schlauch oder KSS-Strahl unter Druck getroffen.",
TriggerDE: "Materialermuedung, mechanische Beschaedigung, fehlerhafte Befestigung des Schlauchs.",
@@ -270,7 +270,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M420"},
Priority: 90, MachineTypes: []string{"cnc", "metalworking", "automotive"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Kuehlschmierstoff tritt aus und bildet rutschigen Belag auf dem Boden. Person rutscht aus und stuerzt.",
TriggerDE: "Leckage an Schlauchverbindung, Dichtungsversagen.",
@@ -284,7 +284,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"material_environmental"},
SuggestedMeasureIDs: []string{"M141"},
Priority: 90, MachineTypes: []string{"cnc", "metalworking", "automotive"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person kommt bei Arbeiten am Bearbeitungszentrum oder der Roboterzelle mit Kuehlschmierstoff in Beruehrung.",
TriggerDE: "Hautkontakt beim Reinigen, Werkzeugwechsel oder Beseitigung von Stoerungen.",
@@ -298,7 +298,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"material_environmental"},
SuggestedMeasureIDs: []string{"M141"},
Priority: 90, MachineTypes: []string{"cnc", "metalworking", "automotive"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance"},
ScenarioDE: "Person oeffnet Schutztuer der Bearbeitungszelle und atmet freigesetzte KSS-Aerosole ein.",
TriggerDE: "Oeffnen der Schutztuer nach Bearbeitungsvorgang, unzureichende Absaugung.",
@@ -313,10 +313,10 @@ func GetRobotCellPatterns() []HazardPattern {
{
ID: "HP1640", NameDE: "Direktes Beruehren spannungsfuehrender Teile", NameEN: "Direct contact with live parts",
RequiredComponentTags: []string{},
RequiredEnergyTags: []string{"electrical"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M009", "M410"},
Priority: 93,
SuggestedMeasureIDs: []string{"M265", "M089", "M088", "M139", "M475"},
Priority: 99,
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance", "fault_clearing"},
ScenarioDE: "Person beruehrt spannungsfuehrende Teile der Anlage die nicht ausreichend isoliert oder abgedeckt sind.",
TriggerDE: "Beschaedigte Isolation, fehlende Abdeckung, ungesicherter Schaltschrank.",
@@ -330,8 +330,8 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredComponentTags: []string{},
RequiredEnergyTags: []string{"electrical"},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M410", "M411"},
Priority: 93,
SuggestedMeasureIDs: []string{"M475", "M476"},
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Schutzleiter ist unterbrochen. Person beruehrt das Maschinengehaeuse und erleidet elektrischen Schlag durch gefaehrliche Beruehrungsspannung.",
TriggerDE: "Schutzleiterunterbrechung durch mechanische Beschaedigung oder fehlerhafte Installation.",
@@ -346,7 +346,7 @@ func GetRobotCellPatterns() []HazardPattern {
RequiredEnergyTags: []string{"electrical"},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M009"},
Priority: 92,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance"},
ScenarioDE: "Kabel ueberhitzt und entzuendet sich durch Ueberlast oder fehlenden Ueberstromschutz. Person wird durch Brand oder toxische Gase verletzt.",
TriggerDE: "Dauerhafter Betrieb nahe der Belastungsgrenze, falsch dimensionierte Sicherung.",
@@ -13,7 +13,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061", "M054"},
Priority: 94,
Priority: 99,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "changeover", "fault_clearing"},
ScenarioDE: "Roboterarm ueberschreitet Bewegungsbegrenzung und trifft Schutzzaun. Person ausserhalb wird von Zaunteilen oder dem Roboterarm getroffen.",
TriggerDE: "Softwareendschalter versagt, Achsbegrenzung (DCS) fehlerhaft konfiguriert.",
@@ -27,7 +27,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054", "M061", "M141"},
Priority: 95,
Priority: 99,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing", "changeover"},
ScenarioDE: "Person befindet sich in der Roboterzelle. Schutztuer wird geschlossen und Roboter startet ohne dass sichergestellt ist, dass niemand im Gefahrenbereich ist.",
TriggerDE: "Fehlende Quittierungspflicht, kein Personenscanner, Schutztuer ohne Sicherheitszuhaltung.",
@@ -41,7 +41,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "clamping_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054", "M061"},
Priority: 94,
Priority: 99,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning"},
ScenarioDE: "Person wird von bewegtem Werkzeug oder Greifer am Roboterarm getroffen oder zwischen Werkzeug und feststehenden Teilen eingeklemmt.",
TriggerDE: "Roboter bewegt Werkzeug/Greifer waehrend Person im Schwenkbereich.",
@@ -55,7 +55,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "clamping_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054", "M061"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "changeover"},
ScenarioDE: "Person wird von sich bewegendem Werkstueck am Robotergreifer getroffen oder zwischen Werkstueck und feststehenden Anlagenteilen eingeklemmt.",
TriggerDE: "Roboter transportiert Werkstueck, Person steht im Schwenkbereich.",
@@ -69,7 +69,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"clamping_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061"},
Priority: 92,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation"},
ScenarioDE: "Greifer versagt und Werkstueck/Werkzeug wird Richtung Schutzzaun geschleudert. Person ausserhalb wird getroffen.",
TriggerDE: "Greifkraftverlust, Druckausfall, oelige Oberflaeche des Werkstuecks.",
@@ -83,7 +83,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"clamping_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M002", "M061"},
Priority: 92,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person greift ueber den Schutzzaun und erreicht den Greifer oder das Werkstueck am Roboterarm.",
TriggerDE: "Sicherheitsabstand zwischen Zaun-Oberkante und Greifer/Werkstueck zu gering.",
@@ -100,7 +100,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"clamping_part", "entanglement_risk"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M002", "M061"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person befindet sich ausserhalb der Roboterzelle und greift an die Zentriereinheit (fest montierter Greifer am Foerderband).",
TriggerDE: "Zentriergreifer schliesst waehrend Hand im Greifbereich. Unzureichender Abstand zwischen Greifer und Schutzzaun-Oeffnung.",
@@ -114,7 +114,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"clamping_part", "entanglement_risk", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054", "M061"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "cleaning", "fault_clearing"},
ScenarioDE: "Person befindet sich innerhalb der Roboterzelle und greift an die Zentriereinheit am Foerderband.",
TriggerDE: "Schutztuer geoeffnet, aber Zentriergreifer wird nicht automatisch stillgesetzt.",
@@ -131,7 +131,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"moving_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054", "M061"},
Priority: 93, MachineTypes: []string{"cnc", "metalworking", "automotive", "robotics_cobot"},
Priority: 98, MachineTypes: []string{"cnc", "metalworking", "automotive", "robotics_cobot"},
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person greift durch die Beladetuer der Werkzeugmaschine. Beladetuer schliesst sich oder bewegliche Teile im Innenraum starten.",
TriggerDE: "Tuerpositionsschalter nicht in Robotersteuerung eingebunden, fehlende Verriegelung.",
@@ -145,7 +145,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"moving_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054"},
Priority: 92, MachineTypes: []string{"cnc", "metalworking", "automotive", "robotics_cobot"},
Priority: 98, MachineTypes: []string{"cnc", "metalworking", "automotive", "robotics_cobot"},
ApplicableLifecycles: []string{"setup", "maintenance", "fault_clearing"},
ScenarioDE: "Person greift in den Bearbeitungsraum der Werkzeugmaschine und wird von beweglichen Achsen, Werkzeug oder Spannvorrichtung verletzt.",
TriggerDE: "Bewegliche Teile starten waehrend Hand im Bearbeitungsraum (Einrichtbetrieb, Stoerungsbeseitigung).",
@@ -162,7 +162,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M141"},
Priority: 91, MachineTypes: []string{"cnc", "metalworking", "automotive"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person bekommt Kuehlschmierstoff-Spritzer ins Auge oder Gesicht beim Oeffnen der Bearbeitungszelle oder bei laufender Bettspuelung.",
TriggerDE: "KSS-Pumpe laeuft waehrend Schutztuer geoeffnet ist, Austrittsduese nicht korrekt gerichtet.",
@@ -176,7 +176,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"pinch_point"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061"},
Priority: 91, MachineTypes: []string{"cnc", "metalworking", "automotive"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Person wird von ausstroemender Druckluft oder aufgewirbelten Bearbeitungsrueckstaenden in der Bearbeitungszelle verletzt.",
TriggerDE: "Druckluftreinigungsduese aktiv waehrend Schutztuer geoeffnet, Spaene oder Partikel werden aufgewirbelt.",
@@ -192,8 +192,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1675", NameDE: "KSS-Schlauch bersten oder abspringen", NameEN: "Coolant hose burst or detachment",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M420"},
Priority: 91, MachineTypes: []string{"cnc", "metalworking", "automotive"},
SuggestedMeasureIDs: []string{"M480"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance", "fault_clearing"},
ScenarioDE: "Schlauch der Kuehlschmierstoffversorgung zwischen Aufbereitungsanlage und Bearbeitungszentrum platzt oder springt unter Druck ab.",
TriggerDE: "Materialermuedung, Ueberdruck, fehlerhafte Befestigung, mechanische Beschaedigung des Schlauchs.",
@@ -210,7 +210,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"entanglement_risk"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M002", "M003"},
Priority: 91,
Priority: 97,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "fault_clearing"},
ScenarioDE: "Person greift an den Tunnel/Rahmen des Foerderbandes und wird von einem darauf bewegten Werkstueck eingequetscht.",
TriggerDE: "Zu geringer Abstand zwischen Werkstueck und Tunnel/Rahmen, scharfe Kanten an Tunneleingang.",
@@ -226,8 +226,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1685", NameDE: "Indirektes Beruehren durch Schutzleiterunterbrechung", NameEN: "Indirect contact due to PE interruption",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M410", "M411"},
Priority: 93,
SuggestedMeasureIDs: []string{"M475", "M476"},
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "Schutzleiter ist unterbrochen. Person beruehrt leitfaehige Maschinenteile und erleidet elektrischen Schlag.",
TriggerDE: "Mechanische Beschaedigung des Schutzleiters, korrodierte Verbindung, fehlerhafte Installation.",
@@ -241,7 +241,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M009"},
Priority: 93,
Priority: 98,
ApplicableLifecycles: []string{"maintenance", "fault_clearing", "commissioning"},
ScenarioDE: "Person beruehrt spannungsfuehrende Teile bei geoeffnetem Schaltschrank. Leiter um Bedienelemente sind nicht fingersicher geschuetzt.",
TriggerDE: "Schaltschranktuer geoeffnet fuer Wartung oder Fehlersuche, unzureichender Beruehrungsschutz.",
@@ -255,7 +255,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M009"},
Priority: 92,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "cleaning"},
ScenarioDE: "Fluessigkeit dringt in elektrische Komponenten ein und verursacht Kurzschluss. Person wird durch Brand oder Rauchentwicklung gefaehrdet.",
TriggerDE: "Reinigung mit Wasser, KSS-Leckage tropft auf Schaltschrank oder Steuerungskomponenten.",
@@ -268,8 +268,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1688", NameDE: "Gefaehrliche Beruehrungsspannung durch Potentialunterschiede", NameEN: "Dangerous touch voltage from potential differences",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M410"},
Priority: 92,
SuggestedMeasureIDs: []string{"M475", "M477", "M138", "M329"},
Priority: 96,
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance", "fault_clearing"},
ScenarioDE: "Person beruehrt gleichzeitig Anlagenteile mit unterschiedlichem Potential und erleidet elektrischen Schlag.",
TriggerDE: "Fehlender Potentialausgleich zwischen Anlagenteilen verschiedener Hersteller.",
@@ -282,8 +282,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1689", NameDE: "Fehlerstromschutz an Steckdosenstromkreisen", NameEN: "RCD protection at socket circuits",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M410"},
Priority: 91,
SuggestedMeasureIDs: []string{"M475"},
Priority: 97,
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance", "fault_clearing"},
ScenarioDE: "Defektes Geraet wird an Steckdose der Maschine angeschlossen. Fehlerstrom fliesst ueber den Koerper der beruerenden Person.",
TriggerDE: "Fehlende Fehlerstrom-Schutzeinrichtung (RCD) an Steckdosenstromkreisen der Maschine.",
@@ -364,8 +364,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1698", NameDE: "Kurzschluss durch unzureichende Luft-/Kriechstrecken", NameEN: "Short circuit from insufficient creepage/clearance",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M412"},
Priority: 92,
SuggestedMeasureIDs: []string{"M477"},
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "maintenance", "fault_clearing"},
ScenarioDE: "Unzureichende Luft-/Kriechstrecken fuehren bei Verschmutzung zu Kriechstroemen. Person beruehrt betroffene Teile und erleidet elektrischen Schlag.",
TriggerDE: "Verschmutzungsgrad hoeher als bei der Dimensionierung angenommen, Feuchtigkeit, alterungsbedingte Veraenderung.",
@@ -378,8 +378,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1699", NameDE: "EMV-Stoereinfluss auf Sicherheitsfunktionen", NameEN: "EMC interference with safety functions",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"radiation_hazard"},
SuggestedMeasureIDs: []string{"M415", "M416"},
Priority: 91,
SuggestedMeasureIDs: []string{"M478", "M479"},
Priority: 97,
ApplicableLifecycles: []string{"normal_operation", "setup"},
ScenarioDE: "EMV-Stoerungen verursachen unerwartete Maschinenbewegungen. Person im Gefahrenbereich wird von unkontrolliert bewegten Teilen getroffen.",
TriggerDE: "Unzureichende EMV-Schirmung, nicht-fachgerechte Verkabelung, externe Stoerquellen.",
@@ -396,7 +396,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"moving_part", "clamping_part"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054", "M061"},
Priority: 94,
Priority: 99,
ApplicableLifecycles: []string{"normal_operation", "setup", "teach_mode", "cleaning"},
ScenarioDE: "Person steht im Bewegungsbereich des Roboterarms und wird von bewegtem Werkzeug oder Greifer getroffen.",
TriggerDE: "Roboter schwenkt mit Werkzeug/Greifer in Richtung Person.",
@@ -410,7 +410,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{"clamping_part", "guard"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061"},
Priority: 92,
Priority: 98,
ApplicableLifecycles: []string{"normal_operation", "setup", "changeover"},
ScenarioDE: "Greifer oder Werkzeug am Roboterarm durchschlaegt den Schutzzaun und trifft Person ausserhalb der Zelle.",
TriggerDE: "Bewegungsbegrenzung versagt, Schutzzaun nicht auf Aufprallenergie ausgelegt.",
@@ -423,8 +423,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1702", NameDE: "KSS-Schlauch platzt unter Druck", NameEN: "Coolant hose bursts under pressure",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M420"},
Priority: 90, MachineTypes: []string{"cnc", "metalworking", "automotive"},
SuggestedMeasureIDs: []string{"M480"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "maintenance", "fault_clearing"},
ScenarioDE: "KSS-Schlauch platzt und spritzt Kuehlschmierstoff unter Druck. Person in der Naehe wird von KSS-Strahl getroffen.",
TriggerDE: "Alterung, Beschaedigung oder Ueberdruck fuehrt zum Versagen des Schlauchs.",
@@ -438,7 +438,7 @@ func GetRobotCellPatternsExt() []HazardPattern {
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M061"},
Priority: 90, MachineTypes: []string{"cnc", "metalworking", "automotive"},
Priority: 97, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "cleaning", "maintenance", "fault_clearing"},
ScenarioDE: "KSS-Pumpe laeuft bei geoeffneter Schutztuer. Person vor der Bearbeitungszelle bekommt KSS-Spritzer ins Auge oder Gesicht.",
TriggerDE: "Kein automatisches Abschalten der KSS-Pumpe bei geoeffneter Tuer.",
@@ -451,8 +451,8 @@ func GetRobotCellPatternsExt() []HazardPattern {
ID: "HP1704", NameDE: "Brand durch KSS-Leckage auf elektrische Komponenten", NameEN: "Fire from coolant leakage on electrical components",
RequiredComponentTags: []string{},
GeneratedHazardCats: []string{"electrical_hazard"},
SuggestedMeasureIDs: []string{"M420", "M009"},
Priority: 92, MachineTypes: []string{"cnc", "metalworking", "automotive"},
SuggestedMeasureIDs: []string{"M480", "M009"},
Priority: 98, MachineTypes: []string{"cnc", "metalworking", "automotive"},
ApplicableLifecycles: []string{"normal_operation", "cleaning", "maintenance"},
ScenarioDE: "KSS-Leckage tropft auf elektrische Komponenten und verursacht Kurzschluss. Person wird durch Brand oder Rauchentwicklung gefaehrdet.",
TriggerDE: "KSS-Leitung undicht oberhalb elektrischer Komponenten, tropft auf Klemmen oder Leiterplatten.",
@@ -71,21 +71,21 @@ func getSupplementaryMeasures() []ProtectiveMeasureEntry {
// Elektrische Sicherheit — Potentialausgleich & Ableitstroeme
// Gap: GT-Benchmark 2.12 (Potentialausgleich), 2.4 (Ableitstroeme)
// ══════════════════════════════════════════════════════════════
{ID: "M410", ReductionType: "design", SubType: "electrical_safety", Name: "Potentialausgleich zwischen Anlagenteilen", Description: "Alle leitfaehigen Anlagenteile mit unterschiedlicher Energieversorgung werden ueber einen Potentialausgleichsleiter verbunden um gefaehrliche Beruehrungsspannungen zu vermeiden.", HazardCategory: "electrical", Examples: []string{"Potentialausgleich zwischen Roboterzelle und Werkzeugmaschine", "Potentialausgleichsschiene im Schaltschrank"}, NormReferences: []string{"IEC 60204-1 Ziff. 8.2", "IEC 61439-1"}},
{ID: "M411", ReductionType: "design", SubType: "electrical_safety", Name: "Schutz bei erhoehten Ableitstroemen", Description: "Bei Ableitstroemen ueber 10 mA wird der Schutzleiter mechanisch geschuetzt oder ein zusaetzlicher Schutzleiter verlegt und die Verbindung ueberwacht.", HazardCategory: "electrical", Examples: []string{"Schutzrohr fuer Schutzleiter an Frequenzumrichter", "Doppelter Schutzleiter mit Ueberwachung"}, NormReferences: []string{"IEC 60204-1 Ziff. 8.2.6"}},
{ID: "M412", ReductionType: "design", SubType: "electrical_safety", Name: "Dimensionierung von Luft- und Kriechstrecken", Description: "Luft- und Kriechstrecken werden entsprechend der elektrischen Beanspruchung und Verschmutzungsgrad dimensioniert um Kurzschluesse und gefaehrliche Beruehrungsspannungen zu vermeiden.", HazardCategory: "electrical", Examples: []string{"Mindestabstaende in Schaltgeraetekombinationen einhalten", "Isolationsueberwachung installieren"}, NormReferences: []string{"IEC 60204-1 Ziff. 6.2", "IEC 61439-1"}},
{ID: "M475", ReductionType: "design", SubType: "electrical_safety", Name: "Potentialausgleich zwischen Anlagenteilen", Description: "Alle leitfaehigen Anlagenteile mit unterschiedlicher Energieversorgung werden ueber einen Potentialausgleichsleiter verbunden um gefaehrliche Beruehrungsspannungen zu vermeiden.", HazardCategory: "electrical", Examples: []string{"Potentialausgleich zwischen Roboterzelle und Werkzeugmaschine", "Potentialausgleichsschiene im Schaltschrank"}, NormReferences: []string{"IEC 60204-1 Ziff. 8.2", "IEC 61439-1"}},
{ID: "M476", ReductionType: "design", SubType: "electrical_safety", Name: "Schutz bei erhoehten Ableitstroemen", Description: "Bei Ableitstroemen ueber 10 mA wird der Schutzleiter mechanisch geschuetzt oder ein zusaetzlicher Schutzleiter verlegt und die Verbindung ueberwacht.", HazardCategory: "electrical", Examples: []string{"Schutzrohr fuer Schutzleiter an Frequenzumrichter", "Doppelter Schutzleiter mit Ueberwachung"}, NormReferences: []string{"IEC 60204-1 Ziff. 8.2.6"}},
{ID: "M477", ReductionType: "design", SubType: "electrical_safety", Name: "Dimensionierung von Luft- und Kriechstrecken", Description: "Luft- und Kriechstrecken werden entsprechend der elektrischen Beanspruchung und Verschmutzungsgrad dimensioniert um Kurzschluesse und gefaehrliche Beruehrungsspannungen zu vermeiden.", HazardCategory: "electrical", Examples: []string{"Mindestabstaende in Schaltgeraetekombinationen einhalten", "Isolationsueberwachung installieren"}, NormReferences: []string{"IEC 60204-1 Ziff. 6.2", "IEC 61439-1"}},
// ══════════════════════════════════════════════════════════════
// EMV-Sicherheit
// Gap: GT-Benchmark 6.1 (EMV-Stoereinfluss auf Sicherheitsfunktionen)
// ══════════════════════════════════════════════════════════════
{ID: "M415", ReductionType: "design", SubType: "emc_safety", Name: "EMV-konforme Installation und Verkabelung", Description: "Alle sicherheitsrelevanten Komponenten und Sub-Systeme werden nach EMV-Richtlinien installiert und verkabelt um Stoereinfluss auf Sicherheitsfunktionen zu verhindern.", HazardCategory: "electrical", Examples: []string{"Geschirmte Steuerleitungen verwenden", "Getrennte Kabelkanaele fuer Leistungs- und Signalleitungen"}, NormReferences: []string{"IEC 61000-6-2", "EN 16090-1 Ziff. 5.8.7"}},
{ID: "M416", ReductionType: "design", SubType: "emc_safety", Name: "EMV-Pruefung sicherheitsrelevanter Systeme", Description: "Sicherheitsrelevante Steuerungen und Antriebe werden auf Stoerfestigkeit gegenueber elektromagnetischen Einflussgroessen geprueft.", HazardCategory: "electrical", Examples: []string{"Burst/Surge-Pruefung nach IEC 61000-4", "Stoerfestigkeitspruefung der Sicherheits-SPS"}, NormReferences: []string{"IEC 61000-4-4", "IEC 61000-4-5", "IEC 62061"}},
{ID: "M478", ReductionType: "design", SubType: "emc_safety", Name: "EMV-konforme Installation und Verkabelung", Description: "Alle sicherheitsrelevanten Komponenten und Sub-Systeme werden nach EMV-Richtlinien installiert und verkabelt um Stoereinfluss auf Sicherheitsfunktionen zu verhindern.", HazardCategory: "electrical", Examples: []string{"Geschirmte Steuerleitungen verwenden", "Getrennte Kabelkanaele fuer Leistungs- und Signalleitungen"}, NormReferences: []string{"IEC 61000-6-2", "EN 16090-1 Ziff. 5.8.7"}},
{ID: "M479", ReductionType: "design", SubType: "emc_safety", Name: "EMV-Pruefung sicherheitsrelevanter Systeme", Description: "Sicherheitsrelevante Steuerungen und Antriebe werden auf Stoerfestigkeit gegenueber elektromagnetischen Einflussgroessen geprueft.", HazardCategory: "electrical", Examples: []string{"Burst/Surge-Pruefung nach IEC 61000-4", "Stoerfestigkeitspruefung der Sicherheits-SPS"}, NormReferences: []string{"IEC 61000-4-4", "IEC 61000-4-5", "IEC 62061"}},
// ══════════════════════════════════════════════════════════════
// Kuehlschmierstoff-Leitungssicherheit
// Gap: GT-Benchmark 2.10 (KSS-Leckage fuehrt zu Brand)
// ══════════════════════════════════════════════════════════════
{ID: "M420", ReductionType: "design", SubType: "fluid_safety", Name: "Druckfeste Auslegung von KSS-Leitungen", Description: "Schlaeuche, Dichtungen, Verbindungsstuecke und Befestigungen des Kuehlschmierstoffsystems werden auf den Nenndruck der jeweiligen Komponente ausgelegt und gegen Abspringen gesichert.", HazardCategory: "mechanical", Examples: []string{"Druckschlaeuche auf maximalen Betriebsdruck dimensionieren", "Schlauchbruchsicherungen an kritischen Verbindungen"}, NormReferences: []string{"IEC 60204-1 Ziff. 11.3", "EN ISO 4414"}},
{ID: "M480", ReductionType: "design", SubType: "fluid_safety", Name: "Druckfeste Auslegung von KSS-Leitungen", Description: "Schlaeuche, Dichtungen, Verbindungsstuecke und Befestigungen des Kuehlschmierstoffsystems werden auf den Nenndruck der jeweiligen Komponente ausgelegt und gegen Abspringen gesichert.", HazardCategory: "mechanical", Examples: []string{"Druckschlaeuche auf maximalen Betriebsdruck dimensionieren", "Schlauchbruchsicherungen an kritischen Verbindungen"}, NormReferences: []string{"IEC 60204-1 Ziff. 11.3", "EN ISO 4414"}},
}
}
@@ -0,0 +1,84 @@
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)
}
}
@@ -380,37 +380,55 @@ def _update(check_id: str, msg: str):
async def _fetch_text(url: str) -> str:
"""Fetch text from URL via consent-tester.
"""Fetch text from URL via consent-tester, with HTTP fallback.
Merges ALL documents found on the page (handles sites like BMW
that split DSI across multiple sub-pages/accordions).
1. Try consent-tester (Playwright) — handles JS-heavy SPAs
2. Fallback: direct HTTP fetch + HTML strip — fast, works for SSR pages
"""
# 1. Consent-tester (Playwright-based, full JS rendering)
try:
async with httpx.AsyncClient(timeout=300.0) as client:
async with httpx.AsyncClient(timeout=60.0) as client:
resp = await client.post(
f"{CONSENT_TESTER_URL}/dsi-discovery",
json={"url": url, "max_documents": 5},
timeout=300.0,
json={"url": url, "max_documents": 3},
timeout=60.0,
)
if resp.status_code != 200:
return ""
docs = resp.json().get("documents", [])
if not docs:
return ""
# Merge all documents found on the page
texts = []
for doc in docs:
t = doc.get("full_text", "") or doc.get("text_preview", "") or ""
if t and len(t) > 50:
texts.append(t)
merged = "\n\n".join(texts)
if len(texts) > 1:
logger.info("Merged %d documents from %s (%d words)",
len(texts), url, len(merged.split()))
return merged
if resp.status_code == 200:
docs = resp.json().get("documents", [])
if docs:
texts = []
for doc in docs:
t = doc.get("full_text", "") or doc.get("text_preview", "") or ""
if t and len(t) > 50:
texts.append(t)
merged = "\n\n".join(texts)
if merged and len(merged.split()) > 100:
if len(texts) > 1:
logger.info("Merged %d docs from %s (%d words)",
len(texts), url, len(merged.split()))
return merged
except Exception as e:
logger.warning("Text fetch failed for %s: %s", url, e)
return ""
logger.warning("Consent-tester fetch failed for %s: %s", url, e)
# 2. Fallback: direct HTTP fetch (works for SSR pages like BMW)
try:
import re as _re
async with httpx.AsyncClient(timeout=30.0, follow_redirects=True) as client:
resp = await client.get(url)
if resp.status_code == 200 and "text/html" in resp.headers.get("content-type", ""):
html = resp.text
# Strip HTML tags, decode entities
text = _re.sub(r"<script[^>]*>.*?</script>", " ", html, flags=_re.DOTALL | _re.IGNORECASE)
text = _re.sub(r"<style[^>]*>.*?</style>", " ", text, flags=_re.DOTALL | _re.IGNORECASE)
text = _re.sub(r"<[^>]+>", " ", text)
text = _re.sub(r"\s+", " ", text).strip()
if len(text.split()) > 100:
logger.info("HTTP fallback for %s: %d words", url, len(text.split()))
return text
except Exception as e:
logger.warning("HTTP fallback failed for %s: %s", url, e)
return ""
async def _check_single(