feat(iace): Sprint 3A — Operational State Graph + fix(ucca) flaky keyword sort

State Graph:
- 9 Standard-Betriebszustaende (startup, homing, automatic_operation, manual_operation, teach_mode, maintenance, cleaning, emergency_stop, recovery_mode)
- 20 State-Transitions als gerichteter Graph
- OperationalStates + StateTransitions Felder in HazardPattern, MatchInput, PatternMatch
- patternMatches() filtert Patterns nach Betriebszustand (nil = feuert immer)
- Narrative-Parser extrahiert States aus Maschinenbeschreibung (22 Keywords + 4 Transition-Keywords)
- 27 bestehende Patterns mit State-Einschraenkungen annotiert (10 operational, 15 maintenance, 2 cobot)
- MatchReason um operational_state + state_transition Typen erweitert (Explainability)
- 6 neue Tests: NilFiresAlways, MaintenanceFilter, StateTransition, MatchReasons, Count, TransitionValid

UCCA fix:
- Stabiler Tiebreaker (Pattern-ID aufsteigend) bei gleichem Keyword-Score in MatchByKeywords
- Behebt flaky TestControlPatternIndex_MatchByKeywords (1/10 Failure-Rate durch Go map iteration order)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-10 08:05:02 +02:00
parent 33f0a64ff6
commit 77a497d930
10 changed files with 449 additions and 48 deletions
@@ -41,7 +41,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 4, DefaultExposure: 3,
},
{
ID: "HP068", NameDE: "Unerwarteter Wiederanlauf nach Stoerung", NameEN: "Unexpected restart after fault",
ID: "HP068", NameDE: "Unerwarteter Wiederanlauf nach Stoerung", OperationalStates: []string{"recovery_mode", "emergency_stop"}, StateTransitions: []string{"maintenance→automatic_operation", "emergency_stop→recovery_mode"}, NameEN: "Unexpected restart after fault",
RequiredComponentTags: []string{"moving_part", "programmable"},
RequiredLifecycles: []string{"fault_clearing"},
GeneratedHazardCats: []string{"mechanical_hazard", "safety_function_failure"},
@@ -57,7 +57,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 5, DefaultExposure: 3,
},
{
ID: "HP069", NameDE: "Restenergie nach Abschaltung (gespeichert)", NameEN: "Residual stored energy after shutdown",
ID: "HP069", NameDE: "Restenergie nach Abschaltung (gespeichert)", OperationalStates: []string{"maintenance", "emergency_stop"}, NameEN: "Residual stored energy after shutdown",
RequiredComponentTags: []string{"stored_energy"},
RequiredLifecycles: []string{"maintenance", "fault_clearing"},
GeneratedHazardCats: []string{"mechanical_hazard", "electrical_hazard"},
@@ -72,7 +72,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 4, DefaultExposure: 3,
},
{
ID: "HP070", NameDE: "Eingriff in laufende Maschine bei Stoerung", NameEN: "Intervention in running machine during fault",
ID: "HP070", NameDE: "Eingriff in laufende Maschine bei Stoerung", OperationalStates: []string{"recovery_mode"}, NameEN: "Intervention in running machine during fault",
RequiredComponentTags: []string{"moving_part"},
RequiredLifecycles: []string{"fault_clearing"},
ExcludedComponentTags: []string{"interlocked"},
@@ -120,7 +120,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
// Wartung / Instandhaltung (HP073-HP079)
// ================================================================
{
ID: "HP073", NameDE: "Wartung ohne LOTO (Lockout/Tagout)", NameEN: "Maintenance without LOTO",
ID: "HP073", NameDE: "Wartung ohne LOTO (Lockout/Tagout)", OperationalStates: []string{"maintenance"}, NameEN: "Maintenance without LOTO",
RequiredComponentTags: []string{"moving_part"},
RequiredLifecycles: []string{"maintenance"},
GeneratedHazardCats: []string{"maintenance_hazard"},
@@ -136,7 +136,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 5, DefaultExposure: 3,
},
{
ID: "HP074", NameDE: "Sturz von Wartungsbuehne / Leiter", NameEN: "Fall from maintenance platform / ladder",
ID: "HP074", OperationalStates: []string{"maintenance"}, NameDE: "Sturz von Wartungsbuehne / Leiter", NameEN: "Fall from maintenance platform / ladder",
RequiredComponentTags: []string{"structural_part"},
RequiredLifecycles: []string{"maintenance", "cleaning"},
GeneratedHazardCats: []string{"mechanical_hazard"},
@@ -150,7 +150,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 4, DefaultExposure: 2,
},
{
ID: "HP075", NameDE: "Kontakt mit heissen Teilen bei Wartung", NameEN: "Contact with hot parts during maintenance",
ID: "HP075", OperationalStates: []string{"maintenance"}, NameDE: "Kontakt mit heissen Teilen bei Wartung", NameEN: "Contact with hot parts during maintenance",
RequiredComponentTags: []string{"high_temperature"},
RequiredLifecycles: []string{"maintenance"},
GeneratedHazardCats: []string{"thermal_hazard"},
@@ -165,7 +165,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 3, DefaultExposure: 3,
},
{
ID: "HP076", NameDE: "Kontakt mit Gefahrstoffen bei Wartung", NameEN: "Contact with hazardous substances during maintenance",
ID: "HP076", OperationalStates: []string{"maintenance"}, NameDE: "Kontakt mit Gefahrstoffen bei Wartung", NameEN: "Contact with hazardous substances during maintenance",
RequiredComponentTags: []string{"chemical_risk"},
RequiredLifecycles: []string{"maintenance", "cleaning"},
GeneratedHazardCats: []string{"material_environmental"},
@@ -179,7 +179,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 3, DefaultExposure: 3,
},
{
ID: "HP077", NameDE: "Elektrischer Schlag bei Wartungsarbeiten", NameEN: "Electric shock during maintenance",
ID: "HP077", OperationalStates: []string{"maintenance"}, NameDE: "Elektrischer Schlag bei Wartungsarbeiten", NameEN: "Electric shock during maintenance",
RequiredComponentTags: []string{"high_voltage"},
RequiredLifecycles: []string{"maintenance", "fault_clearing"},
GeneratedHazardCats: []string{"electrical_hazard"},
@@ -195,7 +195,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
DefaultSeverity: 5, DefaultExposure: 3,
},
{
ID: "HP078", NameDE: "Ergonomische Belastung bei Wartungszugang", NameEN: "Ergonomic strain at maintenance access",
ID: "HP078", OperationalStates: []string{"maintenance"}, NameDE: "Ergonomische Belastung bei Wartungszugang", NameEN: "Ergonomic strain at maintenance access",
RequiredComponentTags: []string{"structural_part"},
RequiredLifecycles: []string{"maintenance"},
GeneratedHazardCats: []string{"ergonomic"},
@@ -228,7 +228,7 @@ func GetOperationalHazardPatterns() []HazardPattern {
// Einrichten / Umruesten / Werkzeugwechsel (HP080-HP085)
// ================================================================
{
ID: "HP080", NameDE: "Quetschen bei Werkzeugwechsel", NameEN: "Crushing during tool change",
ID: "HP080", NameDE: "Quetschen bei Werkzeugwechsel", OperationalStates: []string{"maintenance", "teach_mode"}, NameEN: "Crushing during tool change",
RequiredComponentTags: []string{"crush_point", "high_force"},
RequiredLifecycles: []string{"changeover", "setup"},
GeneratedHazardCats: []string{"mechanical_hazard"},