feat: IACE SIL/PL calculator + Cobot patterns + library extensions

SIL/PL Calculator: Deterministic S×E×P → PL (a-e) → SIL (1-3) mapping
Cobot Patterns (HP059-HP065): Human-robot collision, afterrun, misprogramming
Press Patterns split into separate file (500-line guardrail)
5 new components (C136-C140), 5 new tags, 18 keyword entries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-05 09:29:03 +02:00
parent ea8353f1a0
commit 8dd1581fae
9 changed files with 430 additions and 150 deletions
@@ -188,6 +188,13 @@ func GetComponentLibrary() []ComponentLibraryEntry {
{ID: "C133", NameDE: "Schwungrad", NameEN: "Flywheel", Category: "mechanical", DescriptionDE: "Energiespeicher fuer mechanische Pressen (Drehenergie).", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN02", "EN03"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part", "stored_energy", "high_speed"}, SortOrder: 133},
{ID: "C134", NameDE: "Kistenwechselstation", NameEN: "Bin Changeover Station", Category: "mechanical", DescriptionDE: "Bereich zum manuellen Wechsel von Auffangkisten waehrend des Betriebs.", TypicalHazardCategories: []string{"mechanical_hazard", "ergonomic"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "gravity_risk", "ergonomic"}, SortOrder: 134},
{ID: "C135", NameDE: "Waage / Pruefstation", NameEN: "Scale / Inspection Station", Category: "sensor", DescriptionDE: "Inline-Wiegestation oder Pruefeinrichtung zur Qualitaetskontrolle.", TypicalHazardCategories: []string{}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 135},
// ── Extended: Cobot / Collaborative Robot Components (C136-C140) ─────
{ID: "C136", NameDE: "Roboter-Endeffektor / Werkzeug", NameEN: "Robot End Effector / Tool", Category: "mechanical", DescriptionDE: "Am Roboterarm montiertes Werkzeug oder Greifer — bestimmt das Verletzungsrisiko im kollaborierenden Betrieb.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "cutting_part", "pinch_point", "tool_at_robot"}, SortOrder: 136},
{ID: "C137", NameDE: "Werkstueck (generisch, variabel)", NameEN: "Workpiece (generic, variable)", Category: "mechanical", DescriptionDE: "Wechselnde Werkstuecke am Roboter — erfordern separate Beurteilung je nach Geometrie und Gewicht.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "gravity_risk", "variable_workpiece"}, SortOrder: 137},
{ID: "C138", NameDE: "Sicherheitsscanner (Cobot-Bereich)", NameEN: "Safety Scanner (Cobot Zone)", Category: "sensor", DescriptionDE: "Laserscanner zur Ueberwachung des Kollaborationsbereichs — triggert Betriebsartwechsel.", TypicalHazardCategories: []string{}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part", "safety_device"}, SortOrder: 138},
{ID: "C139", NameDE: "Kollaborierender Roboter (Cobot)", NameEN: "Collaborative Robot (Cobot)", Category: "mechanical", DescriptionDE: "Roboter fuer den direkten Mensch-Maschine-Betrieb ohne trennende Schutzeinrichtungen.", TypicalHazardCategories: []string{"mechanical_hazard", "ergonomic"}, TypicalEnergySources: []string{"EN01", "EN02"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "has_software", "programmable", "collaborative_operation", "force_limited"}, SortOrder: 139},
{ID: "C140", NameDE: "Kraft-/Momentsensor (Roboter)", NameEN: "Force/Torque Sensor (Robot)", Category: "sensor", DescriptionDE: "Sensor zur Erkennung von Kollisionen und Kraftbegrenzung im kollaborierenden Betrieb.", TypicalHazardCategories: []string{}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part", "safety_device", "force_limited"}, SortOrder: 140},
}
}
@@ -0,0 +1,22 @@
package iace
// HazardPattern defines a rule that matches component/energy tags to
// hazards, measures, and evidence. When a pattern's required tags are all
// present (AND) and none of its excluded tags are present (NOT), it fires.
type HazardPattern struct {
ID string `json:"id"`
NameDE string `json:"name_de"`
NameEN string `json:"name_en"`
RequiredComponentTags []string `json:"required_component_tags"`
RequiredEnergyTags []string `json:"required_energy_tags"`
RequiredLifecycles []string `json:"required_lifecycle_phases"`
ExcludedComponentTags []string `json:"excluded_component_tags"`
GeneratedHazardCats []string `json:"generated_hazard_categories"`
SuggestedMeasureIDs []string `json:"suggested_measure_ids"`
SuggestedEvidenceIDs []string `json:"suggested_evidence_ids"`
Priority int `json:"priority"`
// Expert calculation hint — shown when pattern fires and expert validation is needed
RequiresExpertCalculation bool `json:"requires_expert_calculation,omitempty"`
ExpertHintDE string `json:"expert_hint_de,omitempty"`
ExpertHintEN string `json:"expert_hint_en,omitempty"`
}
@@ -1,21 +1,6 @@
package iace
// HazardPattern defines a rule that matches component/energy tags to
// hazards, measures, and evidence. When a pattern's required tags are all
// present (AND) and none of its excluded tags are present (NOT), it fires.
type HazardPattern struct {
ID string `json:"id"`
NameDE string `json:"name_de"`
NameEN string `json:"name_en"`
RequiredComponentTags []string `json:"required_component_tags"`
RequiredEnergyTags []string `json:"required_energy_tags"`
RequiredLifecycles []string `json:"required_lifecycle_phases"`
ExcludedComponentTags []string `json:"excluded_component_tags"`
GeneratedHazardCats []string `json:"generated_hazard_categories"`
SuggestedMeasureIDs []string `json:"suggested_measure_ids"`
SuggestedEvidenceIDs []string `json:"suggested_evidence_ids"`
Priority int `json:"priority"`
}
// HazardPattern is defined in hazard_pattern_types.go
// GetBuiltinHazardPatterns returns ~44 built-in hazard patterns organized
// by domain (mechanical, electrical, thermal, hydraulic/pneumatic,
@@ -456,134 +441,4 @@ func GetBuiltinHazardPatterns() []HazardPattern {
},
// ================================================================
// Press/Forming Machine Patterns (HP045-HP058)
// ================================================================
{
ID: "HP045", NameDE: "Stoesselabsturz durch Druckverlust", NameEN: "Ram drop due to pressure loss",
RequiredComponentTags: []string{"hydraulic_part", "gravity_risk", "high_force"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard", "pneumatic_hydraulic"},
SuggestedMeasureIDs: []string{"M001", "M051", "M054", "M131"},
SuggestedEvidenceIDs: []string{"E01", "E08", "E20"},
Priority: 98,
},
{
ID: "HP046", NameDE: "Quetschen im Werkzeugeinbauraum", NameEN: "Crushing in die space",
RequiredComponentTags: []string{"crush_point", "high_force"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M005", "M051", "M106"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 97,
},
{
ID: "HP047", NameDE: "Oelnebelexposition Atemwege", NameEN: "Oil mist inhalation exposure",
RequiredComponentTags: []string{"hydraulic_part", "oil_mist_risk"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"material_environmental"},
SuggestedMeasureIDs: []string{"M124", "M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 80,
},
{
ID: "HP048", NameDE: "Verbrennung durch heisse Werkstuecke", NameEN: "Burns from hot workpieces",
RequiredComponentTags: []string{"moving_part"},
RequiredEnergyTags: []string{"thermal"},
GeneratedHazardCats: []string{"thermal_hazard"},
SuggestedMeasureIDs: []string{"M054", "M141"},
SuggestedEvidenceIDs: []string{"E08"},
Priority: 85,
},
{
ID: "HP049", NameDE: "Schwebende Last (Hubwerk/Aufzug)", NameEN: "Suspended load (hoist/elevator)",
RequiredComponentTags: []string{"gravity_risk", "person_under_load"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M005", "M051"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 95,
},
{
ID: "HP050", NameDE: "Einziehen/Scheren Transfersystem", NameEN: "Draw-in/shearing at transfer system",
RequiredComponentTags: []string{"moving_part", "shear_risk"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M005", "M051"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 90,
},
{
ID: "HP051", NameDE: "Sturzgefahr Auswurfbereich", NameEN: "Fall hazard at ejection area",
RequiredComponentTags: []string{"gravity_risk"},
RequiredEnergyTags: []string{},
ExcludedComponentTags: []string{"safety_device"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M051", "M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 75,
},
{
ID: "HP052", NameDE: "Druckfreisetzung Hydraulikspeicher", NameEN: "Pressure release from hydraulic accumulator",
RequiredComponentTags: []string{"hydraulic_part", "high_pressure"},
RequiredEnergyTags: []string{"stored_energy"},
GeneratedHazardCats: []string{"pneumatic_hydraulic"},
SuggestedMeasureIDs: []string{"M051", "M131"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 92,
},
{
ID: "HP053", NameDE: "Impulslaerm Pressvorgang", NameEN: "Impact noise during press operation",
RequiredComponentTags: []string{"noise_source", "high_force"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"noise_vibration"},
SuggestedMeasureIDs: []string{"M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 70,
},
{
ID: "HP054", NameDE: "Schwungrad-Restenergie nach Abschaltung", NameEN: "Flywheel residual energy after shutdown",
RequiredComponentTags: []string{"rotating_part", "stored_energy"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M054"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 88,
},
{
ID: "HP055", NameDE: "Umgehung Schutzeinrichtung (Pressentuer)", NameEN: "Bypass of safety guard (press door)",
RequiredComponentTags: []string{"interlocked", "crush_point"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"safety_function_failure"},
SuggestedMeasureIDs: []string{"M005", "M106"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 96,
},
{
ID: "HP056", NameDE: "Fehlbedienung Zweihandschaltung", NameEN: "Two-hand control misoperation",
RequiredComponentTags: []string{"two_hand_control_required"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"safety_function_failure"},
SuggestedMeasureIDs: []string{"M106"},
SuggestedEvidenceIDs: []string{"E01"},
Priority: 90,
},
{
ID: "HP057", NameDE: "Hydraulikoelleckage + Rutschgefahr", NameEN: "Hydraulic oil leakage + slip hazard",
RequiredComponentTags: []string{"hydraulic_part", "chemical_risk"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"material_environmental"},
SuggestedMeasureIDs: []string{"M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 65,
},
{
ID: "HP058", NameDE: "Ergonomische Belastung Kistenwechsel", NameEN: "Ergonomic strain during bin changeover",
RequiredComponentTags: []string{"ergonomic", "moving_part"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"ergonomic"},
SuggestedMeasureIDs: []string{"M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 55,
},
}
}
@@ -0,0 +1,86 @@
package iace
// GetCobotHazardPatterns returns patterns specific to collaborative robots,
// press-specific expert hints, and the afterrun/SIL calculation domain.
// These extend the builtin patterns (HP045-HP058 for press, HP059+ for cobot).
func GetCobotHazardPatterns() []HazardPattern {
return []HazardPattern{
// ================================================================
// Collaborative Robot (Cobot) Patterns (HP059-HP065)
// ================================================================
{
ID: "HP059", NameDE: "Kollision Mensch-Roboter (Kraft/Geschwindigkeit)", NameEN: "Human-robot collision (force/speed)",
RequiredComponentTags: []string{"collaborative_operation", "moving_part"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M054"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 98,
RequiresExpertCalculation: true,
ExpertHintDE: "Sicherheitsabstaende und maximal zulaessige Kraefte/Geschwindigkeiten muessen berechnet werden.",
ExpertHintEN: "Safety distances and maximum permissible forces/speeds must be calculated.",
},
{
ID: "HP060", NameDE: "Quetschen durch Werkzeug am Cobot", NameEN: "Crushing by tool on cobot",
RequiredComponentTags: []string{"tool_at_robot", "collaborative_operation"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M054", "M141"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 95,
RequiresExpertCalculation: true,
ExpertHintDE: "Werkzeug-/Werkstueckgeometrie bestimmt das Quetschrisiko. Separate Beurteilung pro Werkzeug erforderlich.",
ExpertHintEN: "Tool/workpiece geometry determines crushing risk. Separate assessment per tool required.",
},
{
ID: "HP061", NameDE: "Nachlauf nach Stopp (Reaktionszeit)", NameEN: "Afterrun after stop (reaction time)",
RequiredComponentTags: []string{"afterrun_risk", "moving_part"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M054"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 90,
RequiresExpertCalculation: true,
ExpertHintDE: "Nachlaufwegberechnung erforderlich. Sicherheitsfeld muss entsprechend dimensioniert werden.",
ExpertHintEN: "Afterrun distance calculation required. Safety field must be dimensioned accordingly.",
},
{
ID: "HP062", NameDE: "Fehlprogrammierung Kraft-/Geschwindigkeitsgrenzwerte", NameEN: "Misprogramming of force/speed limits",
RequiredComponentTags: []string{"programmable", "force_limited"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"safety_function_failure"},
SuggestedMeasureIDs: []string{"M106"},
SuggestedEvidenceIDs: []string{"E01"},
Priority: 88,
ExpertHintDE: "Grenzwerte duerfen nur nach Risikobeurteilung veraendert werden. Zugriffsschutz erforderlich.",
},
{
ID: "HP063", NameDE: "Werkstueck-Herabfallen vom Roboter", NameEN: "Workpiece drop from robot",
RequiredComponentTags: []string{"variable_workpiece", "gravity_risk"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M051"},
SuggestedEvidenceIDs: []string{"E08"},
Priority: 82,
},
{
ID: "HP064", NameDE: "Quetschen im Roboter-Arbeitsraum (nicht-kollaborierend)", NameEN: "Crushing in robot workspace (non-collaborative)",
RequiredComponentTags: []string{"moving_part", "high_force", "sensor_part"},
RequiredEnergyTags: []string{},
ExcludedComponentTags: []string{"collaborative_operation"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M005", "M051"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 94,
},
{
ID: "HP065", NameDE: "Einklemmen am Arbeitstisch (Cobot-Zelle)", NameEN: "Trapping at work table (cobot cell)",
RequiredComponentTags: []string{"pinch_point", "structural_part"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001"},
SuggestedEvidenceIDs: []string{"E08"},
Priority: 70,
},
}
}
@@ -0,0 +1,141 @@
package iace
// GetPressHazardPatterns returns patterns specific to hydraulic/mechanical presses,
// forming machines, and related equipment (HP045-HP058).
func GetPressHazardPatterns() []HazardPattern {
return []HazardPattern{
// ================================================================
// Press/Forming Machine Patterns (HP045-HP058)
// ================================================================
{
ID: "HP045", NameDE: "Stoesselabsturz durch Druckverlust", NameEN: "Ram drop due to pressure loss",
RequiredComponentTags: []string{"hydraulic_part", "gravity_risk", "high_force"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard", "pneumatic_hydraulic"},
SuggestedMeasureIDs: []string{"M001", "M051", "M054", "M131"},
SuggestedEvidenceIDs: []string{"E01", "E08", "E20"},
Priority: 98,
RequiresExpertCalculation: true,
ExpertHintDE: "SIL/PL-Nachweis fuer Stoesselabsturzsicherung erforderlich.",
ExpertHintEN: "SIL/PL verification for ram drop protection required.",
},
{
ID: "HP046", NameDE: "Quetschen im Werkzeugeinbauraum", NameEN: "Crushing in die space",
RequiredComponentTags: []string{"crush_point", "high_force"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M005", "M051", "M106"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 97,
},
{
ID: "HP047", NameDE: "Oelnebelexposition Atemwege", NameEN: "Oil mist inhalation exposure",
RequiredComponentTags: []string{"hydraulic_part", "oil_mist_risk"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"material_environmental"},
SuggestedMeasureIDs: []string{"M124", "M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 80,
},
{
ID: "HP048", NameDE: "Verbrennung durch heisse Werkstuecke", NameEN: "Burns from hot workpieces",
RequiredComponentTags: []string{"moving_part"},
RequiredEnergyTags: []string{"thermal"},
GeneratedHazardCats: []string{"thermal_hazard"},
SuggestedMeasureIDs: []string{"M054", "M141"},
SuggestedEvidenceIDs: []string{"E08"},
Priority: 85,
},
{
ID: "HP049", NameDE: "Schwebende Last (Hubwerk/Aufzug)", NameEN: "Suspended load (hoist/elevator)",
RequiredComponentTags: []string{"gravity_risk", "person_under_load"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M005", "M051"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 95,
},
{
ID: "HP050", NameDE: "Einziehen/Scheren Transfersystem", NameEN: "Draw-in/shearing at transfer system",
RequiredComponentTags: []string{"moving_part", "shear_risk"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M005", "M051"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 90,
},
{
ID: "HP051", NameDE: "Sturzgefahr Auswurfbereich", NameEN: "Fall hazard at ejection area",
RequiredComponentTags: []string{"gravity_risk"},
RequiredEnergyTags: []string{},
ExcludedComponentTags: []string{"safety_device"},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M051", "M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 75,
},
{
ID: "HP052", NameDE: "Druckfreisetzung Hydraulikspeicher", NameEN: "Pressure release from hydraulic accumulator",
RequiredComponentTags: []string{"hydraulic_part", "high_pressure"},
RequiredEnergyTags: []string{"stored_energy"},
GeneratedHazardCats: []string{"pneumatic_hydraulic"},
SuggestedMeasureIDs: []string{"M051", "M131"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 92,
},
{
ID: "HP053", NameDE: "Impulslaerm Pressvorgang", NameEN: "Impact noise during press operation",
RequiredComponentTags: []string{"noise_source", "high_force"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"noise_vibration"},
SuggestedMeasureIDs: []string{"M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 70,
},
{
ID: "HP054", NameDE: "Schwungrad-Restenergie nach Abschaltung", NameEN: "Flywheel residual energy after shutdown",
RequiredComponentTags: []string{"rotating_part", "stored_energy"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"mechanical_hazard"},
SuggestedMeasureIDs: []string{"M001", "M054"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 88,
},
{
ID: "HP055", NameDE: "Umgehung Schutzeinrichtung (Pressentuer)", NameEN: "Bypass of safety guard (press door)",
RequiredComponentTags: []string{"interlocked", "crush_point"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"safety_function_failure"},
SuggestedMeasureIDs: []string{"M005", "M106"},
SuggestedEvidenceIDs: []string{"E01", "E08"},
Priority: 96,
},
{
ID: "HP056", NameDE: "Fehlbedienung Zweihandschaltung", NameEN: "Two-hand control misoperation",
RequiredComponentTags: []string{"two_hand_control_required"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"safety_function_failure"},
SuggestedMeasureIDs: []string{"M106"},
SuggestedEvidenceIDs: []string{"E01"},
Priority: 90,
},
{
ID: "HP057", NameDE: "Hydraulikoelleckage + Rutschgefahr", NameEN: "Hydraulic oil leakage + slip hazard",
RequiredComponentTags: []string{"hydraulic_part", "chemical_risk"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"material_environmental"},
SuggestedMeasureIDs: []string{"M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 65,
},
{
ID: "HP058", NameDE: "Ergonomische Belastung Kistenwechsel", NameEN: "Ergonomic strain during bin changeover",
RequiredComponentTags: []string{"ergonomic", "moving_part"},
RequiredEnergyTags: []string{},
GeneratedHazardCats: []string{"ergonomic"},
SuggestedMeasureIDs: []string{"M141"},
SuggestedEvidenceIDs: []string{"E20"},
Priority: 55,
},
}
}
@@ -126,6 +126,27 @@ func GetKeywordDictionary() []KeywordEntry {
{Keywords: []string{"luefter", "fan", "geblaese"}, ComponentIDs: []string{"C096"}, ExtraTags: []string{"rotating_part", "noise_source"}},
{Keywords: []string{"spannvorrichtung", "fixture", "clamp"}, ComponentIDs: []string{"C100"}, ExtraTags: []string{"clamping_part"}},
// ── Cobot / Kollaborativer Betrieb ──────────────────────────────
{Keywords: []string{"kollaborier", "kollaboration", "collaborative"}, ComponentIDs: []string{"C139"}, ExtraTags: []string{"collaborative_operation", "force_limited"}},
{Keywords: []string{"cobot"}, ComponentIDs: []string{"C139"}, ExtraTags: []string{"collaborative_operation"}},
{Keywords: []string{"endeffektor", "end effector", "werkzeug am roboter"}, ComponentIDs: []string{"C136"}, ExtraTags: []string{"tool_at_robot"}},
{Keywords: []string{"werkstueck", "workpiece"}, ComponentIDs: []string{"C137"}, ExtraTags: []string{"variable_workpiece"}},
{Keywords: []string{"sicherheitsscanner", "safety scanner"}, ComponentIDs: []string{"C138"}, ExtraTags: []string{"safety_device"}},
{Keywords: []string{"kraftsensor", "momentsensor", "force sensor", "torque sensor"}, ComponentIDs: []string{"C140"}, ExtraTags: []string{"force_limited"}},
{Keywords: []string{"nachlauf", "afterrun"}, ExtraTags: []string{"afterrun_risk"}},
{Keywords: []string{"traglast", "payload"}, ExtraTags: []string{"gravity_risk"}},
{Keywords: []string{"reichweite", "reach"}, ExtraTags: []string{"moving_part"}},
// ── Elektromotor-spezifisch ────────────────────────────────────
{Keywords: []string{"elektromotor", "electric motor", "asynchronmotor", "synchronmotor"}, ComponentIDs: []string{"C031"}, EnergyIDs: []string{"EN02", "EN05"}, ExtraTags: []string{"rotating_part"}},
{Keywords: []string{"wicklung", "winding", "stator", "rotor"}, ComponentIDs: []string{"C031"}, EnergyIDs: []string{"EN05"}, ExtraTags: []string{"rotating_part", "high_voltage"}},
{Keywords: []string{"lager", "bearing", "waelzlager", "kugellager"}, ComponentIDs: []string{"C013"}, ExtraTags: []string{"rotating_part"}},
{Keywords: []string{"luefter", "ventilator", "kuehlung"}, ComponentIDs: []string{"C096"}, ExtraTags: []string{"rotating_part", "noise_source"}},
{Keywords: []string{"klemmenkasten", "terminal box"}, ComponentIDs: []string{"C061"}, EnergyIDs: []string{"EN05"}, ExtraTags: []string{"high_voltage"}},
{Keywords: []string{"welle", "shaft", "abtriebswelle"}, ComponentIDs: []string{"C031"}, EnergyIDs: []string{"EN02"}, ExtraTags: []string{"rotating_part", "entanglement_risk"}},
{Keywords: []string{"drehmoment", "torque"}, EnergyIDs: []string{"EN02"}, ExtraTags: []string{"high_force", "rotating_part"}},
{Keywords: []string{"isolierung", "insulation"}, ExtraTags: []string{"high_voltage"}},
// ── Kontext-Keywords (keine Komponente, nur Tags) ───────────────
{Keywords: []string{"vollautomatisch", "automatisch"}, ExtraTags: []string{"auto_operation"}},
{Keywords: []string{"schutzausruestung", "psa", "ppe"}, ExtraTags: []string{"ppe_required"}},
@@ -52,11 +52,13 @@ type PatternEngine struct {
patterns []HazardPattern
}
// NewPatternEngine creates a PatternEngine with built-in + extended patterns and resolver.
// NewPatternEngine creates a PatternEngine with all pattern sources and resolver.
func NewPatternEngine() *PatternEngine {
// Combine built-in (HP001-HP044) and extended (HP045+) patterns
patterns := GetBuiltinHazardPatterns()
patterns = append(patterns, GetExtendedHazardPatterns()...)
// Combine all pattern sources
patterns := GetBuiltinHazardPatterns() // HP001-HP044
patterns = append(patterns, GetExtendedHazardPatterns()...) // HP045+ from rule library
patterns = append(patterns, GetPressHazardPatterns()...) // HP045-HP058 press-specific
patterns = append(patterns, GetCobotHazardPatterns()...) // HP059-HP065 cobot-specific
return &PatternEngine{
resolver: NewTagResolver(),
patterns: patterns,
@@ -0,0 +1,139 @@
package iace
// SILPLResult contains the deterministic SIL/PL recommendation
// derived from the risk assessment S×E×P values, plus expert override fields.
type SILPLResult struct {
RecommendedPL string `json:"recommended_pl"` // "a", "b", "c", "d", "e"
RecommendedSIL string `json:"recommended_sil"` // "none", "SIL 1", "SIL 2", "SIL 3"
RiskGraphInput RiskGraphIn `json:"risk_graph_input"`
// Expert override fields (filled by Fachmann)
OverriddenPL string `json:"overridden_pl,omitempty"`
OverriddenSIL string `json:"overridden_sil,omitempty"`
OverrideReason string `json:"override_reason,omitempty"`
NormReferences []string `json:"norm_references,omitempty"`
ExpertValidated bool `json:"expert_validated"`
ValidatedBy string `json:"validated_by,omitempty"`
ValidatedAt string `json:"validated_at,omitempty"`
}
// RiskGraphIn shows the mapped ISO risk graph factors.
type RiskGraphIn struct {
S string `json:"s"` // "S1" or "S2"
F string `json:"f"` // "F1" or "F2"
P string `json:"p"` // "P1" or "P2"
}
// CalculateSILPL derives Performance Level (PL) and Safety Integrity Level (SIL)
// from the IACE risk assessment factors (Severity 1-5, Exposure 1-5, Probability 1-5).
//
// This is a deterministic mapping based on the general risk graph principle:
// - Severity ≥ 4 → S2 (serious/fatal), else S1 (minor/reversible)
// - Exposure ≥ 3 → F2 (frequent/continuous), else F1 (rare/short)
// - Probability ≥ 4 → P2 (hardly avoidable), else P1 (avoidable)
//
// NO normative text is reproduced. This is our own implementation.
func CalculateSILPL(severity, exposure, probability int) SILPLResult {
s, f, p := mapToRiskGraph(severity, exposure, probability)
pl := calculatePL(s, f, p)
sil := plToSIL(pl)
return SILPLResult{
RecommendedPL: pl,
RecommendedSIL: sil,
RiskGraphInput: RiskGraphIn{S: s, F: f, P: p},
}
}
// mapToRiskGraph converts 1-5 scale factors to binary S1/S2, F1/F2, P1/P2.
func mapToRiskGraph(severity, exposure, probability int) (string, string, string) {
s := "S1"
if severity >= 4 {
s = "S2"
}
f := "F1"
if exposure >= 3 {
f = "F2"
}
p := "P1"
if probability >= 4 {
p = "P2"
}
return s, f, p
}
// calculatePL determines Performance Level from the risk graph.
//
// Risk graph (own formulation, no norm text):
//
// S1+F1+P1 a (lowest)
// S1+F1+P2 → b
// S1+F2+P1 → b
// S1+F2+P2 → c
// S2+F1+P1 → c
// S2+F1+P2 → d
// S2+F2+P1 → d
// S2+F2+P2 → e (highest)
func calculatePL(s, f, p string) string {
if s == "S1" {
if f == "F1" {
if p == "P1" {
return "a"
}
return "b"
}
// F2
if p == "P1" {
return "b"
}
return "c"
}
// S2
if f == "F1" {
if p == "P1" {
return "c"
}
return "d"
}
// S2+F2
if p == "P1" {
return "d"
}
return "e"
}
// plToSIL maps Performance Level to Safety Integrity Level.
//
// PL a, b → no SIL requirement
// PL c → SIL 1
// PL d → SIL 2
// PL e → SIL 3
func plToSIL(pl string) string {
switch pl {
case "a", "b":
return "none"
case "c":
return "SIL 1"
case "d":
return "SIL 2"
case "e":
return "SIL 3"
default:
return "none"
}
}
// GetEffectivePL returns the expert-overridden PL if set, otherwise the recommendation.
func (r *SILPLResult) GetEffectivePL() string {
if r.OverriddenPL != "" {
return r.OverriddenPL
}
return r.RecommendedPL
}
// GetEffectiveSIL returns the expert-overridden SIL if set, otherwise the recommendation.
func (r *SILPLResult) GetEffectiveSIL() string {
if r.OverriddenSIL != "" {
return r.OverriddenSIL
}
return r.RecommendedSIL
}
@@ -96,6 +96,13 @@ func GetTagTaxonomy() []TagEntry {
{ID: "gravity_suspended_load", Domain: "hazard", DescriptionDE: "Schwebende Last unter Schwerkraft", DescriptionEN: "Suspended load under gravity"},
{ID: "bypass_risk", Domain: "hazard", DescriptionDE: "Risiko der Sicherheitsumgehung", DescriptionEN: "Safety bypass risk"},
// ── Extended: Cobot/Collaborative tags ──────────────────────────────
{ID: "collaborative_operation", Domain: "component", DescriptionDE: "Kollaborierender Betrieb (Mensch und Maschine ohne Trennung)", DescriptionEN: "Collaborative operation (human-machine without separation)"},
{ID: "force_limited", Domain: "component", DescriptionDE: "Kraft-/Geschwindigkeitsbegrenzung aktiv", DescriptionEN: "Force/speed limitation active"},
{ID: "tool_at_robot", Domain: "component", DescriptionDE: "Werkzeug am Roboterarm montiert", DescriptionEN: "Tool mounted on robot arm"},
{ID: "variable_workpiece", Domain: "component", DescriptionDE: "Wechselnde Werkstuecke (separate Beurteilung)", DescriptionEN: "Variable workpieces (separate assessment required)"},
{ID: "afterrun_risk", Domain: "hazard", DescriptionDE: "Nachlaufgefahr nach Stopp", DescriptionEN: "Afterrun risk after stop"},
// ── Domain: measure (~10 tags) ──────────────────────────────────────
{ID: "guard_measure", Domain: "measure", DescriptionDE: "Trennende Schutzeinrichtung", DescriptionEN: "Separating guard measure"},
{ID: "interlock_measure", Domain: "measure", DescriptionDE: "Verriegelungsmassnahme", DescriptionEN: "Interlock measure"},