feat(iace): add hazard-matching-engine with component library, tag system, and pattern engine
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 44s
CI/CD / test-python-backend-compliance (push) Successful in 33s
CI/CD / test-python-document-crawler (push) Successful in 22s
CI/CD / test-python-dsms-gateway (push) Successful in 19s
CI/CD / validate-canonical-controls (push) Successful in 13s
CI/CD / Deploy (push) Successful in 4s
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 44s
CI/CD / test-python-backend-compliance (push) Successful in 33s
CI/CD / test-python-document-crawler (push) Successful in 22s
CI/CD / test-python-dsms-gateway (push) Successful in 19s
CI/CD / validate-canonical-controls (push) Successful in 13s
CI/CD / Deploy (push) Successful in 4s
Implements Phases 1-4 of the IACE Hazard-Matching-Engine: - 120 machine components (C001-C120) in 11 categories - 20 energy sources (EN01-EN20) - ~85 tag taxonomy across 5 domains - 44 hazard patterns with AND/NOT matching logic - Pattern engine with tag resolution and confidence scoring - 8 new API endpoints (component-library, energy-sources, tags, patterns, match/apply) - Completeness gate G09 for pattern matching - 320 tests passing (36 new) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -135,6 +135,23 @@ func buildGateDefinitions() []GateDefinition {
|
||||
},
|
||||
},
|
||||
|
||||
// =====================================================================
|
||||
// Pattern Matching Gate (G09) - Recommended
|
||||
// =====================================================================
|
||||
{
|
||||
ID: "G09",
|
||||
Category: "onboarding",
|
||||
Label: "Pattern matching performed",
|
||||
Required: false,
|
||||
Recommended: true,
|
||||
CheckFunc: func(ctx *CompletenessContext) bool {
|
||||
// Check audit trail for pattern_matching entries
|
||||
// Since we can't query audit trail from context, check if hazards
|
||||
// have been created (proxy for pattern matching having been performed)
|
||||
return len(ctx.Hazards) >= 3
|
||||
},
|
||||
},
|
||||
|
||||
// =====================================================================
|
||||
// Classification Gates (G10-G13) - Required
|
||||
// =====================================================================
|
||||
|
||||
@@ -608,10 +608,10 @@ func TestCompletenessCheck_GateCountsAndCategories(t *testing.T) {
|
||||
}
|
||||
result := checker.Check(ctx)
|
||||
|
||||
// The buildGateDefinitions function returns exactly 21 gates
|
||||
// (G01-G08: 8, G10-G13: 4, G20-G24: 5, G30: 1, G40-G42: 3 = 21 total)
|
||||
if len(result.Gates) != 21 {
|
||||
t.Errorf("Total gates = %d, want 21", len(result.Gates))
|
||||
// The buildGateDefinitions function returns exactly 22 gates
|
||||
// (G01-G08: 8, G09: 1, G10-G13: 4, G20-G24: 5, G30: 1, G40-G42: 3 = 22 total)
|
||||
if len(result.Gates) != 22 {
|
||||
t.Errorf("Total gates = %d, want 22", len(result.Gates))
|
||||
}
|
||||
|
||||
// Count required vs recommended
|
||||
@@ -622,8 +622,8 @@ func TestCompletenessCheck_GateCountsAndCategories(t *testing.T) {
|
||||
requiredCount++
|
||||
}
|
||||
}
|
||||
// G30 is the only recommended gate (Required=false, Recommended=true)
|
||||
// All others are required (20 required, 1 recommended)
|
||||
// G09 and G30 are recommended gates (Required=false, Recommended=true)
|
||||
// All others are required (20 required, 2 recommended)
|
||||
if requiredCount != 20 {
|
||||
t.Errorf("Required gates count = %d, want 20", requiredCount)
|
||||
}
|
||||
@@ -632,9 +632,9 @@ func TestCompletenessCheck_GateCountsAndCategories(t *testing.T) {
|
||||
t.Errorf("TotalRequired = %d, want 20", result.TotalRequired)
|
||||
}
|
||||
|
||||
// TotalRecommended should be 1 (G30)
|
||||
if result.TotalRecommended != 1 {
|
||||
t.Errorf("TotalRecommended = %d, want 1", result.TotalRecommended)
|
||||
// TotalRecommended should be 2 (G09, G30)
|
||||
if result.TotalRecommended != 2 {
|
||||
t.Errorf("TotalRecommended = %d, want 2", result.TotalRecommended)
|
||||
}
|
||||
_ = recommendedCount
|
||||
|
||||
@@ -645,7 +645,7 @@ func TestCompletenessCheck_GateCountsAndCategories(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedCategories := map[string]int{
|
||||
"onboarding": 8,
|
||||
"onboarding": 9, // G01-G08 + G09 (recommended)
|
||||
"classification": 4,
|
||||
"hazard_risk": 5,
|
||||
"evidence": 1,
|
||||
|
||||
209
ai-compliance-sdk/internal/iace/component_library.go
Normal file
209
ai-compliance-sdk/internal/iace/component_library.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package iace
|
||||
|
||||
// ComponentLibraryEntry represents a reusable machine component template from the library.
|
||||
type ComponentLibraryEntry struct {
|
||||
ID string `json:"id"`
|
||||
NameDE string `json:"name_de"`
|
||||
NameEN string `json:"name_en"`
|
||||
Category string `json:"category"`
|
||||
DescriptionDE string `json:"description_de,omitempty"`
|
||||
TypicalHazardCategories []string `json:"typical_hazard_categories"`
|
||||
TypicalEnergySources []string `json:"typical_energy_sources"`
|
||||
MapsToComponentType string `json:"maps_to_component_type"`
|
||||
Tags []string `json:"tags"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
// EnergySourceEntry represents an energy source type used in machinery.
|
||||
type EnergySourceEntry struct {
|
||||
ID string `json:"id"`
|
||||
NameDE string `json:"name_de"`
|
||||
NameEN string `json:"name_en"`
|
||||
DescriptionDE string `json:"description_de,omitempty"`
|
||||
TypicalComponents []string `json:"typical_components"`
|
||||
TypicalHazardCategories []string `json:"typical_hazard_categories"`
|
||||
Tags []string `json:"tags"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
// GetComponentLibrary returns the complete built-in component library with 120 entries
|
||||
// across 11 categories, covering typical industrial machine components.
|
||||
func GetComponentLibrary() []ComponentLibraryEntry {
|
||||
return []ComponentLibraryEntry{
|
||||
// ── Category: mechanical (C001-C020) ────────────────────────────────────
|
||||
{ID: "C001", NameDE: "Roboterarm", NameEN: "Robot Arm", Category: "mechanical", DescriptionDE: "Mehrgelenkiger Industrierobotearm fuer Pick-and-Place, Schweissen oder Montage.", TypicalHazardCategories: []string{"mechanical_hazard", "ergonomic"}, TypicalEnergySources: []string{"EN01", "EN02"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "rotating_part", "high_force"}, SortOrder: 1},
|
||||
{ID: "C002", NameDE: "Greifer", NameEN: "Gripper", Category: "mechanical", DescriptionDE: "Pneumatischer oder elektrischer Greifer zum Greifen und Halten von Werkstuecken.", TypicalHazardCategories: []string{"mechanical_hazard", "pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN01", "EN05"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "clamping_part", "pinch_point"}, SortOrder: 2},
|
||||
{ID: "C003", NameDE: "Foerderband", NameEN: "Conveyor Belt", Category: "mechanical", DescriptionDE: "Endlosband zum Transport von Werkstuecken zwischen Arbeitsstationen.", TypicalHazardCategories: []string{"mechanical_hazard", "ergonomic"}, TypicalEnergySources: []string{"EN01", "EN02"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "rotating_part", "entanglement_risk"}, SortOrder: 3},
|
||||
{ID: "C004", NameDE: "Drehtisch", NameEN: "Rotary Table", Category: "mechanical", DescriptionDE: "Rotierender Arbeitstisch fuer Bearbeitungs- oder Montageprozesse.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part", "high_force"}, SortOrder: 4},
|
||||
{ID: "C005", NameDE: "Linearachse", NameEN: "Linear Axis", Category: "mechanical", DescriptionDE: "Linearfuehrung fuer praezise translatorische Bewegungen.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "crush_point"}, SortOrder: 5},
|
||||
{ID: "C006", NameDE: "Spindel", NameEN: "Spindle", Category: "mechanical", DescriptionDE: "Hochdrehende Spindel fuer Fräs-, Bohr- oder Schleifoperationen.", TypicalHazardCategories: []string{"mechanical_hazard", "noise_vibration"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part", "high_speed", "cutting_part"}, SortOrder: 6},
|
||||
{ID: "C007", NameDE: "Saegeblatt", NameEN: "Saw Blade", Category: "mechanical", DescriptionDE: "Rotierendes oder oszillierendes Schneidwerkzeug.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"cutting_part", "rotating_part", "high_speed"}, SortOrder: 7},
|
||||
{ID: "C008", NameDE: "Pressenstoessel", NameEN: "Press Ram", Category: "mechanical", DescriptionDE: "Auf- und abfahrender Stoessel einer Presse zum Umformen.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01", "EN05"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "high_force", "crush_point"}, SortOrder: 8},
|
||||
{ID: "C009", NameDE: "Walze", NameEN: "Roller", Category: "mechanical", DescriptionDE: "Zylindrische Walze zum Foerdern, Pressen oder Kalandrieren.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part", "entanglement_risk", "pinch_point"}, SortOrder: 9},
|
||||
{ID: "C010", NameDE: "Kettenantrieb", NameEN: "Chain Drive", Category: "mechanical", DescriptionDE: "Kette und Kettenrad zur Kraftuebertragung.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "entanglement_risk"}, SortOrder: 10},
|
||||
{ID: "C011", NameDE: "Zahnradgetriebe", NameEN: "Gear Transmission", Category: "mechanical", DescriptionDE: "Zahnradpaar oder -satz zur Drehzahl-/Drehmomentanpassung.", TypicalHazardCategories: []string{"mechanical_hazard", "noise_vibration"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part", "pinch_point"}, SortOrder: 11},
|
||||
{ID: "C012", NameDE: "Kupplung", NameEN: "Clutch", Category: "mechanical", DescriptionDE: "Mechanische Kupplung zur An-/Abkopplung von Antriebsstraengen.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part"}, SortOrder: 12},
|
||||
{ID: "C013", NameDE: "Bremse", NameEN: "Brake", Category: "mechanical", DescriptionDE: "Mechanische oder elektromagnetische Bremse zum Stillsetzen von Antrieben.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "stored_energy"}, SortOrder: 13},
|
||||
{ID: "C014", NameDE: "Hubwerk", NameEN: "Hoist", Category: "mechanical", DescriptionDE: "Hebezeug zum vertikalen Bewegen von Lasten.", TypicalHazardCategories: []string{"mechanical_hazard", "ergonomic"}, TypicalEnergySources: []string{"EN01", "EN03"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "high_force", "gravity_risk"}, SortOrder: 14},
|
||||
{ID: "C015", NameDE: "Werkzeugwechsler", NameEN: "Tool Changer", Category: "mechanical", DescriptionDE: "Automatischer Werkzeugwechsler fuer CNC-Maschinen.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01", "EN05"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "pinch_point"}, SortOrder: 15},
|
||||
{ID: "C016", NameDE: "Schweisskopf", NameEN: "Welding Head", Category: "mechanical", DescriptionDE: "Schweisskopf fuer MIG/MAG, WIG oder Laserschweissen.", TypicalHazardCategories: []string{"mechanical_hazard", "thermal_hazard", "electrical_hazard"}, TypicalEnergySources: []string{"EN03", "EN07"}, MapsToComponentType: "mechanical", Tags: []string{"high_temperature", "radiation_risk"}, SortOrder: 16},
|
||||
{ID: "C017", NameDE: "Schraubstation", NameEN: "Screwdriving Station", Category: "mechanical", DescriptionDE: "Automatische Schraubeinheit fuer Montageprozesse.", TypicalHazardCategories: []string{"mechanical_hazard", "noise_vibration"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part"}, SortOrder: 17},
|
||||
{ID: "C018", NameDE: "Stanzen-Werkzeug", NameEN: "Punching Tool", Category: "mechanical", DescriptionDE: "Stanzwerkzeug zum Ausschneiden von Formen aus Blech oder Folie.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"cutting_part", "high_force", "crush_point"}, SortOrder: 18},
|
||||
{ID: "C019", NameDE: "Biegewerkzeug", NameEN: "Bending Tool", Category: "mechanical", DescriptionDE: "Werkzeug zum Biegen von Blech oder Profilen.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "high_force", "crush_point"}, SortOrder: 19},
|
||||
{ID: "C020", NameDE: "Vibrationsfoerderer", NameEN: "Vibratory Feeder", Category: "mechanical", DescriptionDE: "Schwingfoerderer zum Sortieren und Zufuehren von Kleinteilen.", TypicalHazardCategories: []string{"mechanical_hazard", "noise_vibration"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "vibration_source"}, SortOrder: 20},
|
||||
|
||||
// ── Category: structural (C021-C030) ────────────────────────────────────
|
||||
{ID: "C021", NameDE: "Maschinenrahmen", NameEN: "Machine Frame", Category: "structural", DescriptionDE: "Tragender Rahmen als Grundstruktur der Maschine.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part"}, SortOrder: 21},
|
||||
{ID: "C022", NameDE: "Schutzgehaeuse", NameEN: "Protective Enclosure", Category: "structural", DescriptionDE: "Feste Verkleidung zum Schutz vor Gefahrstellen.", TypicalHazardCategories: []string{}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part", "guard"}, SortOrder: 22},
|
||||
{ID: "C023", NameDE: "Schutztuer", NameEN: "Safety Door", Category: "structural", DescriptionDE: "Verriegelte Tuer mit Zugangsschutz zum Gefahrbereich.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part", "guard", "interlocked"}, SortOrder: 23},
|
||||
{ID: "C024", NameDE: "Arbeitstisch", NameEN: "Work Table", Category: "structural", DescriptionDE: "Feststehende oder hoehenverstellbare Arbeitsflaeche.", TypicalHazardCategories: []string{"ergonomic"}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part"}, SortOrder: 24},
|
||||
{ID: "C025", NameDE: "Kabelkanal", NameEN: "Cable Tray", Category: "structural", DescriptionDE: "Fuehrung und Schutz fuer elektrische Leitungen und Kabel.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part"}, SortOrder: 25},
|
||||
{ID: "C026", NameDE: "Schwingungsdaempfer", NameEN: "Vibration Damper", Category: "structural", DescriptionDE: "Daempfungselement zur Reduzierung von Maschinenschwingungen.", TypicalHazardCategories: []string{"noise_vibration"}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part"}, SortOrder: 26},
|
||||
{ID: "C027", NameDE: "Fundamentplatte", NameEN: "Foundation Plate", Category: "structural", DescriptionDE: "Fundamentplatte zur Aufstellung und Verankerung der Maschine.", TypicalHazardCategories: []string{}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part"}, SortOrder: 27},
|
||||
{ID: "C028", NameDE: "Schutzgitter", NameEN: "Safety Fence", Category: "structural", DescriptionDE: "Feststehende Schutzeinrichtung als Umzaeunung des Gefahrbereichs.", TypicalHazardCategories: []string{}, TypicalEnergySources: []string{}, MapsToComponentType: "mechanical", Tags: []string{"structural_part", "guard"}, SortOrder: 28},
|
||||
{ID: "C029", NameDE: "Aufstiegsleiter", NameEN: "Access Ladder", Category: "structural", DescriptionDE: "Fest montierte Leiter fuer Wartungszugang in der Hoehe.", TypicalHazardCategories: []string{"ergonomic", "mechanical_hazard"}, TypicalEnergySources: []string{"EN03"}, MapsToComponentType: "mechanical", Tags: []string{"structural_part", "gravity_risk"}, SortOrder: 29},
|
||||
{ID: "C030", NameDE: "Plattform/Buehne", NameEN: "Platform/Walkway", Category: "structural", DescriptionDE: "Begehbare Plattform fuer Bedienung oder Wartung in der Hoehe.", TypicalHazardCategories: []string{"ergonomic", "mechanical_hazard"}, TypicalEnergySources: []string{"EN03"}, MapsToComponentType: "mechanical", Tags: []string{"structural_part", "gravity_risk"}, SortOrder: 30},
|
||||
|
||||
// ── Category: drive (C031-C040) ─────────────────────────────────────────
|
||||
{ID: "C031", NameDE: "Elektromotor (Drehstrom)", NameEN: "AC Motor", Category: "drive", DescriptionDE: "Drehstrom-Asynchronmotor als Hauptantrieb.", TypicalHazardCategories: []string{"electrical_hazard", "mechanical_hazard", "noise_vibration"}, TypicalEnergySources: []string{"EN02", "EN04"}, MapsToComponentType: "electrical", Tags: []string{"rotating_part", "high_voltage", "high_force"}, SortOrder: 31},
|
||||
{ID: "C032", NameDE: "Servomotor", NameEN: "Servo Motor", Category: "drive", DescriptionDE: "Hochdynamischer Servomotor fuer praezise Positionierung.", TypicalHazardCategories: []string{"electrical_hazard", "mechanical_hazard"}, TypicalEnergySources: []string{"EN02", "EN04"}, MapsToComponentType: "electrical", Tags: []string{"rotating_part", "high_speed"}, SortOrder: 32},
|
||||
{ID: "C033", NameDE: "Schrittmotor", NameEN: "Stepper Motor", Category: "drive", DescriptionDE: "Schrittmotor fuer inkrementelle Positionierung.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN02", "EN04"}, MapsToComponentType: "electrical", Tags: []string{"rotating_part"}, SortOrder: 33},
|
||||
{ID: "C034", NameDE: "Frequenzumrichter", NameEN: "Frequency Converter", Category: "drive", DescriptionDE: "Frequenzumrichter zur stufenlosen Drehzahlregelung.", TypicalHazardCategories: []string{"electrical_hazard", "emc_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"high_voltage", "stored_energy"}, SortOrder: 34},
|
||||
{ID: "C035", NameDE: "Getriebemotor", NameEN: "Gear Motor", Category: "drive", DescriptionDE: "Motor mit integriertem Getriebe fuer hohes Drehmoment bei niedriger Drehzahl.", TypicalHazardCategories: []string{"mechanical_hazard", "electrical_hazard"}, TypicalEnergySources: []string{"EN02", "EN04"}, MapsToComponentType: "electrical", Tags: []string{"rotating_part", "high_force"}, SortOrder: 35},
|
||||
{ID: "C036", NameDE: "Linearmotor", NameEN: "Linear Motor", Category: "drive", DescriptionDE: "Elektromagnetischer Direktantrieb fuer lineare Bewegung.", TypicalHazardCategories: []string{"electrical_hazard", "mechanical_hazard"}, TypicalEnergySources: []string{"EN01", "EN04"}, MapsToComponentType: "electrical", Tags: []string{"moving_part", "high_speed"}, SortOrder: 36},
|
||||
{ID: "C037", NameDE: "Torque-Motor", NameEN: "Torque Motor", Category: "drive", DescriptionDE: "Direktantriebsmotor fuer hohe Drehmomente ohne Getriebe.", TypicalHazardCategories: []string{"electrical_hazard", "mechanical_hazard"}, TypicalEnergySources: []string{"EN02", "EN04"}, MapsToComponentType: "electrical", Tags: []string{"rotating_part", "high_force"}, SortOrder: 37},
|
||||
{ID: "C038", NameDE: "Elektrischer Stellantrieb", NameEN: "Electric Actuator", Category: "drive", DescriptionDE: "Elektrischer Antrieb fuer Ventile, Klappen oder Schieber.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN01", "EN04"}, MapsToComponentType: "actuator", Tags: []string{"moving_part"}, SortOrder: 38},
|
||||
{ID: "C039", NameDE: "Spindelantrieb", NameEN: "Spindle Drive", Category: "drive", DescriptionDE: "Kugelgewindetrieb fuer praezise Linearbewegung.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01"}, MapsToComponentType: "mechanical", Tags: []string{"moving_part", "crush_point"}, SortOrder: 39},
|
||||
{ID: "C040", NameDE: "Riemenantrieb", NameEN: "Belt Drive", Category: "drive", DescriptionDE: "Riemen und Riemenscheiben zur Kraftuebertragung.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "mechanical", Tags: []string{"rotating_part", "entanglement_risk"}, SortOrder: 40},
|
||||
|
||||
// ── Category: hydraulic (C041-C050) ─────────────────────────────────────
|
||||
{ID: "C041", NameDE: "Hydraulikpumpe", NameEN: "Hydraulic Pump", Category: "hydraulic", DescriptionDE: "Pumpe zur Erzeugung des hydraulischen Drucks im System.", TypicalHazardCategories: []string{"pneumatic_hydraulic", "noise_vibration"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "high_pressure"}, SortOrder: 41},
|
||||
{ID: "C042", NameDE: "Hydraulikzylinder", NameEN: "Hydraulic Cylinder", Category: "hydraulic", DescriptionDE: "Linearaktuator zur Erzeugung hoher Kraefte.", TypicalHazardCategories: []string{"pneumatic_hydraulic", "mechanical_hazard"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "moving_part", "high_force", "high_pressure"}, SortOrder: 42},
|
||||
{ID: "C043", NameDE: "Hydraulikventil", NameEN: "Hydraulic Valve", Category: "hydraulic", DescriptionDE: "Steuer- oder Regelventil im Hydraulikkreislauf.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "high_pressure"}, SortOrder: 43},
|
||||
{ID: "C044", NameDE: "Hydraulikspeicher", NameEN: "Hydraulic Accumulator", Category: "hydraulic", DescriptionDE: "Druckspeicher zur Pufferung von Druckspitzen.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "stored_energy", "high_pressure"}, SortOrder: 44},
|
||||
{ID: "C045", NameDE: "Hydraulikschlauch", NameEN: "Hydraulic Hose", Category: "hydraulic", DescriptionDE: "Flexible Schlauchleitung fuer Hydraulikfluid.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "high_pressure"}, SortOrder: 45},
|
||||
{ID: "C046", NameDE: "Hydraulikfilter", NameEN: "Hydraulic Filter", Category: "hydraulic", DescriptionDE: "Filter zur Reinigung des Hydraulikfluids.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part"}, SortOrder: 46},
|
||||
{ID: "C047", NameDE: "Hydraulikkuehler", NameEN: "Hydraulic Cooler", Category: "hydraulic", DescriptionDE: "Kuehlaggregat zur Temperierung des Hydraulikoels.", TypicalHazardCategories: []string{"pneumatic_hydraulic", "thermal_hazard"}, TypicalEnergySources: []string{"EN05", "EN07"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "high_temperature"}, SortOrder: 47},
|
||||
{ID: "C048", NameDE: "Hydraulik-Proportionalventil", NameEN: "Hydraulic Proportional Valve", Category: "hydraulic", DescriptionDE: "Proportionalventil fuer stufenlose Steuerung von Druck und Volumen.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "high_pressure"}, SortOrder: 48},
|
||||
{ID: "C049", NameDE: "Hydraulik-Druckminderer", NameEN: "Hydraulic Pressure Reducer", Category: "hydraulic", DescriptionDE: "Druckregelventil zur Begrenzung des Systemdrucks.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part", "high_pressure"}, SortOrder: 49},
|
||||
{ID: "C050", NameDE: "Hydraulik-Absperrventil", NameEN: "Hydraulic Shut-off Valve", Category: "hydraulic", DescriptionDE: "Handventil zum sicheren Absperren von Leitungsabschnitten.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"hydraulic_part"}, SortOrder: 50},
|
||||
|
||||
// ── Category: pneumatic (C051-C060) ─────────────────────────────────────
|
||||
{ID: "C051", NameDE: "Pneumatikzylinder", NameEN: "Pneumatic Cylinder", Category: "pneumatic", DescriptionDE: "Druckluftbetriebener Linearaktuator.", TypicalHazardCategories: []string{"pneumatic_hydraulic", "mechanical_hazard"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part", "moving_part", "stored_energy"}, SortOrder: 51},
|
||||
{ID: "C052", NameDE: "Kompressor", NameEN: "Compressor", Category: "pneumatic", DescriptionDE: "Druckluftkompressor zur Erzeugung von Druckluft.", TypicalHazardCategories: []string{"pneumatic_hydraulic", "noise_vibration"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part", "high_pressure", "noise_source"}, SortOrder: 52},
|
||||
{ID: "C053", NameDE: "Pneumatikventil", NameEN: "Pneumatic Valve", Category: "pneumatic", DescriptionDE: "Steuerventil zur Druckluftverteilung.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part"}, SortOrder: 53},
|
||||
{ID: "C054", NameDE: "Druckluftaufbereitung", NameEN: "Air Treatment Unit", Category: "pneumatic", DescriptionDE: "Wartungseinheit mit Filter, Regler und Oeler.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part"}, SortOrder: 54},
|
||||
{ID: "C055", NameDE: "Vakuumsauger", NameEN: "Vacuum Suction Cup", Category: "pneumatic", DescriptionDE: "Vakuumgreifer zum beruehrungslosen Heben von Werkstuecken.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part"}, SortOrder: 55},
|
||||
{ID: "C056", NameDE: "Vakuumerzeuger", NameEN: "Vacuum Generator", Category: "pneumatic", DescriptionDE: "Venturi-Erzeuger oder Vakuumpumpe.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part"}, SortOrder: 56},
|
||||
{ID: "C057", NameDE: "Druckluftmotor", NameEN: "Pneumatic Motor", Category: "pneumatic", DescriptionDE: "Druckluftbetriebener Rotationsmotor.", TypicalHazardCategories: []string{"pneumatic_hydraulic", "mechanical_hazard"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part", "rotating_part"}, SortOrder: 57},
|
||||
{ID: "C058", NameDE: "Pneumatik-Absperrventil", NameEN: "Pneumatic Shut-off Valve", Category: "pneumatic", DescriptionDE: "Handventil zum sicheren Absperren der Druckluft.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part"}, SortOrder: 58},
|
||||
{ID: "C059", NameDE: "Pneumatik-Drosselventil", NameEN: "Pneumatic Flow Control", Category: "pneumatic", DescriptionDE: "Drosselventil zur Geschwindigkeitsregelung von Pneumatikzylindern.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part"}, SortOrder: 59},
|
||||
{ID: "C060", NameDE: "Druckluftspeicher", NameEN: "Air Reservoir", Category: "pneumatic", DescriptionDE: "Druckluftbehaelter als Energiespeicher.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN06"}, MapsToComponentType: "actuator", Tags: []string{"pneumatic_part", "stored_energy", "high_pressure"}, SortOrder: 60},
|
||||
|
||||
// ── Category: electrical (C061-C070) ────────────────────────────────────
|
||||
{ID: "C061", NameDE: "Schaltschrank", NameEN: "Control Cabinet", Category: "electrical", DescriptionDE: "Zentraler Schaltschrank mit Sicherungen, Schuetzen und Steuerung.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"high_voltage", "electrical_part"}, SortOrder: 61},
|
||||
{ID: "C062", NameDE: "Stromversorgung (Netzteil)", NameEN: "Power Supply", Category: "electrical", DescriptionDE: "AC/DC-Wandler oder Schaltnetzteil fuer die Maschinensteuerung.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"high_voltage", "electrical_part"}, SortOrder: 62},
|
||||
{ID: "C063", NameDE: "Transformator", NameEN: "Transformer", Category: "electrical", DescriptionDE: "Spannungswandler fuer die Versorgung verschiedener Spannungsebenen.", TypicalHazardCategories: []string{"electrical_hazard", "thermal_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"high_voltage", "electrical_part"}, SortOrder: 63},
|
||||
{ID: "C064", NameDE: "Schuetz/Relais", NameEN: "Contactor/Relay", Category: "electrical", DescriptionDE: "Elektromechanisches Schaltgeraet fuer Lastkreise.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"electrical_part"}, SortOrder: 64},
|
||||
{ID: "C065", NameDE: "Sicherungsautomat", NameEN: "Circuit Breaker", Category: "electrical", DescriptionDE: "Leitungsschutzschalter oder Motorschutzschalter.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"electrical_part"}, SortOrder: 65},
|
||||
{ID: "C066", NameDE: "FI-Schutzschalter", NameEN: "Residual Current Device", Category: "electrical", DescriptionDE: "Fehlerstromschutzschalter zum Personenschutz.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"electrical_part", "safety_device"}, SortOrder: 66},
|
||||
{ID: "C067", NameDE: "USV (Unterbrechungsfreie Stromversorgung)", NameEN: "Uninterruptible Power Supply", Category: "electrical", DescriptionDE: "Batteriepuffer fuer sicherheitsrelevante Verbraucher.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04", "EN08"}, MapsToComponentType: "electrical", Tags: []string{"electrical_part", "stored_energy"}, SortOrder: 67},
|
||||
{ID: "C068", NameDE: "Energiekette/Schleppkette", NameEN: "Cable Carrier", Category: "electrical", DescriptionDE: "Fuehrung fuer Kabel und Schlaeuche an bewegten Achsen.", TypicalHazardCategories: []string{"electrical_hazard", "mechanical_hazard"}, TypicalEnergySources: []string{}, MapsToComponentType: "electrical", Tags: []string{"electrical_part", "moving_part"}, SortOrder: 68},
|
||||
{ID: "C069", NameDE: "Erdungssystem", NameEN: "Grounding System", Category: "electrical", DescriptionDE: "Schutz- und Funktionserdung der Maschine.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"electrical_part"}, SortOrder: 69},
|
||||
{ID: "C070", NameDE: "Hauptschalter", NameEN: "Main Switch", Category: "electrical", DescriptionDE: "Zentraler Netztrennschalter der Maschine.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "electrical", Tags: []string{"electrical_part", "high_voltage"}, SortOrder: 70},
|
||||
|
||||
// ── Category: control (C071-C080) ───────────────────────────────────────
|
||||
{ID: "C071", NameDE: "SPS (Speicherprogrammierbare Steuerung)", NameEN: "PLC (Programmable Logic Controller)", Category: "control", DescriptionDE: "Zentrale Maschinensteuerung mit SPS-Programm.", TypicalHazardCategories: []string{"software_fault", "configuration_error"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"has_software", "programmable"}, SortOrder: 71},
|
||||
{ID: "C072", NameDE: "Sicherheits-SPS", NameEN: "Safety PLC", Category: "control", DescriptionDE: "Redundante Sicherheitssteuerung bis SIL 3 / PL e.", TypicalHazardCategories: []string{"safety_function_failure", "software_fault"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"has_software", "programmable", "safety_device"}, SortOrder: 72},
|
||||
{ID: "C073", NameDE: "HMI (Bedienterminal)", NameEN: "HMI (Human Machine Interface)", Category: "control", DescriptionDE: "Bedienpanel mit Touchscreen zur Maschinensteuerung.", TypicalHazardCategories: []string{"hmi_error", "mode_confusion"}, TypicalEnergySources: []string{}, MapsToComponentType: "hmi", Tags: []string{"has_software", "user_interface"}, SortOrder: 73},
|
||||
{ID: "C074", NameDE: "Industrierechner (IPC)", NameEN: "Industrial PC", Category: "control", DescriptionDE: "Industrie-PC fuer komplexe Steuerungs- und Datenverarbeitungsaufgaben.", TypicalHazardCategories: []string{"software_fault", "configuration_error"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"has_software", "programmable", "networked"}, SortOrder: 74},
|
||||
{ID: "C075", NameDE: "Motion Controller", NameEN: "Motion Controller", Category: "control", DescriptionDE: "Achscontroller fuer synchronisierte Mehrachsbewegungen.", TypicalHazardCategories: []string{"software_fault", "mechanical_hazard"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"has_software", "programmable"}, SortOrder: 75},
|
||||
{ID: "C076", NameDE: "Sicherheitsrelais", NameEN: "Safety Relay", Category: "control", DescriptionDE: "Sicherheitsschaltgeraet fuer Not-Halt, Schutztuer etc.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device"}, SortOrder: 76},
|
||||
{ID: "C077", NameDE: "Antriebsregler", NameEN: "Drive Controller", Category: "control", DescriptionDE: "Intelligenter Antriebsregler mit integrierten Sicherheitsfunktionen.", TypicalHazardCategories: []string{"software_fault", "electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "controller", Tags: []string{"has_software", "programmable"}, SortOrder: 77},
|
||||
{ID: "C078", NameDE: "Remote I/O", NameEN: "Remote I/O Module", Category: "control", DescriptionDE: "Dezentrales Ein-/Ausgangsmodul im Feldbus.", TypicalHazardCategories: []string{"communication_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"networked"}, SortOrder: 78},
|
||||
{ID: "C079", NameDE: "Bedienpult", NameEN: "Control Desk", Category: "control", DescriptionDE: "Zentrales Bedienpult mit Tastern, Schaltern und Anzeigen.", TypicalHazardCategories: []string{"hmi_error", "mode_confusion"}, TypicalEnergySources: []string{}, MapsToComponentType: "hmi", Tags: []string{"user_interface"}, SortOrder: 79},
|
||||
{ID: "C080", NameDE: "Datenschreiber/Logger", NameEN: "Data Logger", Category: "control", DescriptionDE: "Geraet zur Aufzeichnung von Prozessparametern.", TypicalHazardCategories: []string{"logging_audit_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"has_software"}, SortOrder: 80},
|
||||
|
||||
// ── Category: sensor (C081-C090) ────────────────────────────────────────
|
||||
{ID: "C081", NameDE: "Positionssensor", NameEN: "Position Sensor", Category: "sensor", DescriptionDE: "Induktiver, kapazitiver oder optischer Positionssensor.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 81},
|
||||
{ID: "C082", NameDE: "Kamerasystem", NameEN: "Camera System", Category: "sensor", DescriptionDE: "Industriekamera fuer Bildverarbeitung und Qualitaetskontrolle.", TypicalHazardCategories: []string{"sensor_spoofing", "false_classification"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part", "networked"}, SortOrder: 82},
|
||||
{ID: "C083", NameDE: "Kraftsensor", NameEN: "Force Sensor", Category: "sensor", DescriptionDE: "Dehnungsmessstreifen oder piezoelektrischer Kraftsensor.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 83},
|
||||
{ID: "C084", NameDE: "Temperatursensor", NameEN: "Temperature Sensor", Category: "sensor", DescriptionDE: "Thermocouple oder PT100 zur Temperaturueberwachung.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 84},
|
||||
{ID: "C085", NameDE: "Drucksensor", NameEN: "Pressure Sensor", Category: "sensor", DescriptionDE: "Sensor zur Ueberwachung von Druck in Hydraulik- oder Pneumatiksystemen.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 85},
|
||||
{ID: "C086", NameDE: "Drehgeber/Encoder", NameEN: "Rotary Encoder", Category: "sensor", DescriptionDE: "Absolut- oder Inkrementaldrehgeber zur Winkel-/Positionsmessung.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 86},
|
||||
{ID: "C087", NameDE: "Laserscanner", NameEN: "Laser Scanner", Category: "sensor", DescriptionDE: "Sicherheits-Laserscanner zur Ueberwachung von Schutzzonen.", TypicalHazardCategories: []string{"sensor_spoofing", "safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part", "safety_device"}, SortOrder: 87},
|
||||
{ID: "C088", NameDE: "Beschleunigungssensor", NameEN: "Accelerometer", Category: "sensor", DescriptionDE: "Sensor zur Vibrations- und Beschleunigungsmessung.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 88},
|
||||
{ID: "C089", NameDE: "Durchflusssensor", NameEN: "Flow Sensor", Category: "sensor", DescriptionDE: "Sensor zur Ueberwachung des Volumenstrom.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 89},
|
||||
{ID: "C090", NameDE: "Fuellstandsensor", NameEN: "Level Sensor", Category: "sensor", DescriptionDE: "Sensor zur Ueberwachung des Fuellstands in Tanks und Behaeltern.", TypicalHazardCategories: []string{"sensor_spoofing"}, TypicalEnergySources: []string{}, MapsToComponentType: "sensor", Tags: []string{"sensor_part"}, SortOrder: 90},
|
||||
|
||||
// ── Category: actuator (C091-C100) ──────────────────────────────────────
|
||||
{ID: "C091", NameDE: "Magnetventil", NameEN: "Solenoid Valve", Category: "actuator", DescriptionDE: "Elektromagnetisch betaetigtes Ventil fuer Pneumatik oder Hydraulik.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05", "EN06"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part"}, SortOrder: 91},
|
||||
{ID: "C092", NameDE: "Linearantrieb (elektrisch)", NameEN: "Electric Linear Actuator", Category: "actuator", DescriptionDE: "Elektrischer Linearantrieb fuer Positionieraufgaben.", TypicalHazardCategories: []string{"mechanical_hazard", "electrical_hazard"}, TypicalEnergySources: []string{"EN01", "EN04"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part", "moving_part"}, SortOrder: 92},
|
||||
{ID: "C093", NameDE: "Proportionalventil", NameEN: "Proportional Valve", Category: "actuator", DescriptionDE: "Stetig regelbares Ventil fuer praezise Drucksteuerung.", TypicalHazardCategories: []string{"pneumatic_hydraulic"}, TypicalEnergySources: []string{"EN05", "EN06"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part"}, SortOrder: 93},
|
||||
{ID: "C094", NameDE: "Heizelement", NameEN: "Heating Element", Category: "actuator", DescriptionDE: "Elektrisches Heizelement fuer Temperierung von Werkzeugen oder Medien.", TypicalHazardCategories: []string{"thermal_hazard", "electrical_hazard"}, TypicalEnergySources: []string{"EN07"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part", "high_temperature"}, SortOrder: 94},
|
||||
{ID: "C095", NameDE: "Kuehlaggregat", NameEN: "Cooling Unit", Category: "actuator", DescriptionDE: "Kuehlanlage fuer Prozesse oder Schaltschraenke.", TypicalHazardCategories: []string{"thermal_hazard"}, TypicalEnergySources: []string{"EN07"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part"}, SortOrder: 95},
|
||||
{ID: "C096", NameDE: "Luefter/Geblaese", NameEN: "Fan/Blower", Category: "actuator", DescriptionDE: "Luefter zur Kuehlung oder Absaugung.", TypicalHazardCategories: []string{"mechanical_hazard", "noise_vibration"}, TypicalEnergySources: []string{"EN02"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part", "rotating_part"}, SortOrder: 96},
|
||||
{ID: "C097", NameDE: "Dosierpumpe", NameEN: "Dosing Pump", Category: "actuator", DescriptionDE: "Praezisionspumpe zur Dosierung von Fluessigkeiten oder Klebstoffen.", TypicalHazardCategories: []string{"pneumatic_hydraulic", "material_environmental"}, TypicalEnergySources: []string{"EN05"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part"}, SortOrder: 97},
|
||||
{ID: "C098", NameDE: "Elektromagnet", NameEN: "Electromagnet", Category: "actuator", DescriptionDE: "Elektromagnet fuer Halten, Spannen oder Foerdern.", TypicalHazardCategories: []string{"electrical_hazard", "emc_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part", "stored_energy"}, SortOrder: 98},
|
||||
{ID: "C099", NameDE: "Piezo-Aktuator", NameEN: "Piezo Actuator", Category: "actuator", DescriptionDE: "Piezoelektrischer Aktuator fuer hochpraezise Mikrobewegungen.", TypicalHazardCategories: []string{"electrical_hazard"}, TypicalEnergySources: []string{"EN04"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part"}, SortOrder: 99},
|
||||
{ID: "C100", NameDE: "Spannvorrichtung", NameEN: "Clamping Device", Category: "actuator", DescriptionDE: "Mechanische, pneumatische oder hydraulische Spannvorrichtung.", TypicalHazardCategories: []string{"mechanical_hazard"}, TypicalEnergySources: []string{"EN01", "EN05", "EN06"}, MapsToComponentType: "actuator", Tags: []string{"actuator_part", "clamping_part", "pinch_point"}, SortOrder: 100},
|
||||
|
||||
// ── Category: safety (C101-C110) ────────────────────────────────────────
|
||||
{ID: "C101", NameDE: "Not-Halt-Taster", NameEN: "Emergency Stop Button", Category: "safety", DescriptionDE: "Pilzfoermiger Taster fuer den sofortigen Maschinenstopp.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device", "emergency_stop"}, SortOrder: 101},
|
||||
{ID: "C102", NameDE: "Lichtgitter / Lichtvorhang", NameEN: "Light Curtain", Category: "safety", DescriptionDE: "Optoelektronische Schutzeinrichtung zur Zugangsueberwachung.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device", "interlocked"}, SortOrder: 102},
|
||||
{ID: "C103", NameDE: "Sicherheits-Laserscanner", NameEN: "Safety Laser Scanner", Category: "safety", DescriptionDE: "Scanner zur Ueberwachung von Schutzfeldern und Warnfeldern.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device", "sensor_part"}, SortOrder: 103},
|
||||
{ID: "C104", NameDE: "Sicherheitsschalter (Tuerkontakt)", NameEN: "Safety Switch (Door Contact)", Category: "safety", DescriptionDE: "Positions- oder Schluesseltransferschalter an Schutztueren.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device", "interlocked"}, SortOrder: 104},
|
||||
{ID: "C105", NameDE: "Zuhaltung", NameEN: "Guard Locking Device", Category: "safety", DescriptionDE: "Elektromechanische Zuhaltung fuer Schutztueren.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device", "interlocked"}, SortOrder: 105},
|
||||
{ID: "C106", NameDE: "Zweihandschaltung", NameEN: "Two-Hand Control", Category: "safety", DescriptionDE: "Zweihandschaltung zur sicheren Ausloesung von Hubbewegungen.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device"}, SortOrder: 106},
|
||||
{ID: "C107", NameDE: "Sicherheitsmagnet / RFID-Schalter", NameEN: "Safety RFID Switch", Category: "safety", DescriptionDE: "Manipulationssicherer Sicherheitsschalter mit RFID-Codierung.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device", "interlocked"}, SortOrder: 107},
|
||||
{ID: "C108", NameDE: "Schaltmatte / Trittmatte", NameEN: "Safety Mat", Category: "safety", DescriptionDE: "Druckempfindliche Matte zur Personenerkennung in Gefahrzonen.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device"}, SortOrder: 108},
|
||||
{ID: "C109", NameDE: "Seilzugschalter", NameEN: "Pull-Wire Switch", Category: "safety", DescriptionDE: "Seilzug-Notschalter entlang von Foerderstrecken.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device", "emergency_stop"}, SortOrder: 109},
|
||||
{ID: "C110", NameDE: "Zustimmtaster", NameEN: "Enabling Device", Category: "safety", DescriptionDE: "Dreistufiger Zustimmtaster fuer den Einrichtbetrieb.", TypicalHazardCategories: []string{"safety_function_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "controller", Tags: []string{"safety_device"}, SortOrder: 110},
|
||||
|
||||
// ── Category: it_network (C111-C120) ────────────────────────────────────
|
||||
{ID: "C111", NameDE: "Industrie-Switch (managed)", NameEN: "Managed Industrial Switch", Category: "it_network", DescriptionDE: "Managed Ethernet Switch fuer das Maschinennetzwerk.", TypicalHazardCategories: []string{"communication_failure", "unauthorized_access"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component"}, SortOrder: 111},
|
||||
{ID: "C112", NameDE: "Industrie-Router", NameEN: "Industrial Router", Category: "it_network", DescriptionDE: "Router zur Segmentierung und Absicherung des Maschinennetzwerks.", TypicalHazardCategories: []string{"communication_failure", "unauthorized_access"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component"}, SortOrder: 112},
|
||||
{ID: "C113", NameDE: "Industrie-Firewall", NameEN: "Industrial Firewall", Category: "it_network", DescriptionDE: "Firewall zum Schutz des OT-Netzwerks vor externen Angriffen.", TypicalHazardCategories: []string{"unauthorized_access"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component", "security_device"}, SortOrder: 113},
|
||||
{ID: "C114", NameDE: "IoT-Gateway", NameEN: "IoT Gateway", Category: "it_network", DescriptionDE: "Gateway fuer die Anbindung von Maschinen an Cloud/Edge.", TypicalHazardCategories: []string{"communication_failure", "unauthorized_access"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component", "has_software"}, SortOrder: 114},
|
||||
{ID: "C115", NameDE: "Edge-Computing-Einheit", NameEN: "Edge Computing Unit", Category: "it_network", DescriptionDE: "Lokale Recheneinheit fuer Datenvorverarbeitung und KI-Inferenz.", TypicalHazardCategories: []string{"software_fault", "communication_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component", "has_software", "has_ai"}, SortOrder: 115},
|
||||
{ID: "C116", NameDE: "WLAN Access Point (Industrie)", NameEN: "Industrial WiFi Access Point", Category: "it_network", DescriptionDE: "Drahtloser Netzwerkzugang im Maschinenumfeld.", TypicalHazardCategories: []string{"communication_failure", "unauthorized_access"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component", "wireless"}, SortOrder: 116},
|
||||
{ID: "C117", NameDE: "OPC UA Server", NameEN: "OPC UA Server", Category: "it_network", DescriptionDE: "OPC UA Kommunikationsserver fuer Maschine-zu-Maschine-Vernetzung.", TypicalHazardCategories: []string{"communication_failure", "unauthorized_access"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component", "has_software"}, SortOrder: 117},
|
||||
{ID: "C118", NameDE: "VPN-Appliance", NameEN: "VPN Appliance", Category: "it_network", DescriptionDE: "VPN-Geraet fuer sichere Fernzugriffe auf die Maschinensteuerung.", TypicalHazardCategories: []string{"unauthorized_access"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component", "security_device"}, SortOrder: 118},
|
||||
{ID: "C119", NameDE: "KI-Inferenzmodul", NameEN: "AI Inference Module", Category: "it_network", DescriptionDE: "Dediziertes KI-Modul (GPU/TPU) fuer Echtzeit-Inferenz.", TypicalHazardCategories: []string{"false_classification", "model_drift", "unintended_bias"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"has_ai", "has_software", "networked"}, SortOrder: 119},
|
||||
{ID: "C120", NameDE: "Feldbus-Koppler", NameEN: "Fieldbus Coupler", Category: "it_network", DescriptionDE: "Koppler fuer PROFINET, EtherCAT oder andere Feldbussysteme.", TypicalHazardCategories: []string{"communication_failure"}, TypicalEnergySources: []string{}, MapsToComponentType: "network", Tags: []string{"networked", "it_component"}, SortOrder: 120},
|
||||
}
|
||||
}
|
||||
|
||||
// GetEnergySources returns the complete built-in energy source library with 20 entries.
|
||||
func GetEnergySources() []EnergySourceEntry {
|
||||
return []EnergySourceEntry{
|
||||
{ID: "EN01", NameDE: "Kinetische Energie (translatorisch)", NameEN: "Kinetic Energy (Translational)", DescriptionDE: "Energie durch lineare Bewegung von Maschinenteilen.", TypicalComponents: []string{"C001", "C002", "C005", "C008"}, TypicalHazardCategories: []string{"mechanical_hazard"}, Tags: []string{"kinetic", "translational"}, SortOrder: 1},
|
||||
{ID: "EN02", NameDE: "Kinetische Energie (rotatorisch)", NameEN: "Kinetic Energy (Rotational)", DescriptionDE: "Energie durch Drehbewegung von Wellen, Spindeln, Motoren.", TypicalComponents: []string{"C004", "C006", "C009", "C031"}, TypicalHazardCategories: []string{"mechanical_hazard"}, Tags: []string{"kinetic", "rotational"}, SortOrder: 2},
|
||||
{ID: "EN03", NameDE: "Potentielle Energie (Lage)", NameEN: "Potential Energy (Gravitational)", DescriptionDE: "Energie durch angehobene Lasten oder Maschinenteile.", TypicalComponents: []string{"C014", "C029", "C030"}, TypicalHazardCategories: []string{"mechanical_hazard"}, Tags: []string{"potential", "gravitational"}, SortOrder: 3},
|
||||
{ID: "EN04", NameDE: "Elektrische Energie", NameEN: "Electrical Energy", DescriptionDE: "Netz- oder Batteriespannung in Schaltschraenken und Antrieben.", TypicalComponents: []string{"C061", "C062", "C063", "C070"}, TypicalHazardCategories: []string{"electrical_hazard"}, Tags: []string{"electrical_energy"}, SortOrder: 4},
|
||||
{ID: "EN05", NameDE: "Hydraulische Energie", NameEN: "Hydraulic Energy", DescriptionDE: "Druckenergie in Hydrauliksystemen.", TypicalComponents: []string{"C041", "C042", "C043", "C044"}, TypicalHazardCategories: []string{"pneumatic_hydraulic"}, Tags: []string{"hydraulic_pressure"}, SortOrder: 5},
|
||||
{ID: "EN06", NameDE: "Pneumatische Energie", NameEN: "Pneumatic Energy", DescriptionDE: "Druckenergie in Druckluftsystemen.", TypicalComponents: []string{"C051", "C052", "C053", "C060"}, TypicalHazardCategories: []string{"pneumatic_hydraulic"}, Tags: []string{"pneumatic_pressure"}, SortOrder: 6},
|
||||
{ID: "EN07", NameDE: "Thermische Energie", NameEN: "Thermal Energy", DescriptionDE: "Waerme- oder Kaelteenergie in Prozessen oder Kuehlsystemen.", TypicalComponents: []string{"C094", "C095", "C047"}, TypicalHazardCategories: []string{"thermal_hazard"}, Tags: []string{"thermal"}, SortOrder: 7},
|
||||
{ID: "EN08", NameDE: "Gespeicherte Energie (elektrisch)", NameEN: "Stored Energy (Electrical)", DescriptionDE: "Energie in Kondensatoren, Batterien oder USV-Systemen.", TypicalComponents: []string{"C067", "C034"}, TypicalHazardCategories: []string{"electrical_hazard"}, Tags: []string{"stored_energy", "electrical_energy"}, SortOrder: 8},
|
||||
{ID: "EN09", NameDE: "Gespeicherte Energie (mechanisch)", NameEN: "Stored Energy (Mechanical)", DescriptionDE: "Energie in Federn, Schwungraedern oder Gegengewichten.", TypicalComponents: []string{"C013"}, TypicalHazardCategories: []string{"mechanical_hazard"}, Tags: []string{"stored_energy", "mechanical"}, SortOrder: 9},
|
||||
{ID: "EN10", NameDE: "Gespeicherte Energie (hydraulisch)", NameEN: "Stored Energy (Hydraulic)", DescriptionDE: "Restdruck in Hydraulikspeichern und -leitungen.", TypicalComponents: []string{"C044", "C045"}, TypicalHazardCategories: []string{"pneumatic_hydraulic"}, Tags: []string{"stored_energy", "hydraulic_pressure"}, SortOrder: 10},
|
||||
{ID: "EN11", NameDE: "Gespeicherte Energie (pneumatisch)", NameEN: "Stored Energy (Pneumatic)", DescriptionDE: "Restdruck in Druckluftbehaeltern und -leitungen.", TypicalComponents: []string{"C060", "C051"}, TypicalHazardCategories: []string{"pneumatic_hydraulic"}, Tags: []string{"stored_energy", "pneumatic_pressure"}, SortOrder: 11},
|
||||
{ID: "EN12", NameDE: "Strahlung (optisch/Laser)", NameEN: "Radiation (Optical/Laser)", DescriptionDE: "Licht- oder Laserstrahlung bei Schneid-, Schweiß- oder Messprozessen.", TypicalComponents: []string{"C016", "C087"}, TypicalHazardCategories: []string{"thermal_hazard"}, Tags: []string{"radiation"}, SortOrder: 12},
|
||||
{ID: "EN13", NameDE: "Strahlung (elektromagnetisch)", NameEN: "Radiation (Electromagnetic)", DescriptionDE: "EMV-Stoerungen durch Frequenzumrichter, Motoren oder Funksender.", TypicalComponents: []string{"C034", "C098", "C116"}, TypicalHazardCategories: []string{"emc_hazard"}, Tags: []string{"radiation", "electromagnetic"}, SortOrder: 13},
|
||||
{ID: "EN14", NameDE: "Schallenergie", NameEN: "Acoustic Energy", DescriptionDE: "Laermemission durch Antriebe, Kompressoren oder Bearbeitungsprozesse.", TypicalComponents: []string{"C052", "C006", "C020"}, TypicalHazardCategories: []string{"noise_vibration"}, Tags: []string{"acoustic"}, SortOrder: 14},
|
||||
{ID: "EN15", NameDE: "Vibrationsenergie", NameEN: "Vibration Energy", DescriptionDE: "Mechanische Schwingungen durch rotierende oder oszillierende Teile.", TypicalComponents: []string{"C020", "C006"}, TypicalHazardCategories: []string{"noise_vibration"}, Tags: []string{"vibration"}, SortOrder: 15},
|
||||
{ID: "EN16", NameDE: "Chemische Energie", NameEN: "Chemical Energy", DescriptionDE: "Gefahrstoffe, Klebstoffe, Kuehlschmierstoffe oder Hydraulikoele.", TypicalComponents: []string{"C097", "C046"}, TypicalHazardCategories: []string{"material_environmental"}, Tags: []string{"chemical"}, SortOrder: 16},
|
||||
{ID: "EN17", NameDE: "Magnetische Energie", NameEN: "Magnetic Energy", DescriptionDE: "Magnetfelder durch Elektromagnete oder Permanentmagnete.", TypicalComponents: []string{"C098"}, TypicalHazardCategories: []string{"emc_hazard"}, Tags: []string{"magnetic"}, SortOrder: 17},
|
||||
{ID: "EN18", NameDE: "Datenenergie (Cyber)", NameEN: "Data/Cyber Energy", DescriptionDE: "Logische Steuerungsdaten und Kommunikation als Angriffsvektor.", TypicalComponents: []string{"C111", "C112", "C114", "C119"}, TypicalHazardCategories: []string{"unauthorized_access", "firmware_corruption"}, Tags: []string{"cyber", "data"}, SortOrder: 18},
|
||||
{ID: "EN19", NameDE: "KI-Modell-Energie", NameEN: "AI Model Energy", DescriptionDE: "Trainierte Modellparameter als potenzielle Fehlerquelle bei Inferenz.", TypicalComponents: []string{"C119", "C115"}, TypicalHazardCategories: []string{"false_classification", "model_drift", "data_poisoning", "unintended_bias"}, Tags: []string{"ai_model", "cyber"}, SortOrder: 19},
|
||||
{ID: "EN20", NameDE: "Ergonomische Belastung", NameEN: "Ergonomic Load", DescriptionDE: "Koerperliche Belastung durch ungünstige Arbeitshaltungen oder Gewichte.", TypicalComponents: []string{"C024", "C029", "C030"}, TypicalHazardCategories: []string{"ergonomic"}, Tags: []string{"ergonomic"}, SortOrder: 20},
|
||||
}
|
||||
}
|
||||
|
||||
// ValidComponentLibraryCategories returns all valid component library categories.
|
||||
func ValidComponentLibraryCategories() []string {
|
||||
return []string{
|
||||
"mechanical", "structural", "drive", "hydraulic", "pneumatic",
|
||||
"electrical", "control", "sensor", "actuator", "safety", "it_network",
|
||||
}
|
||||
}
|
||||
131
ai-compliance-sdk/internal/iace/component_library_test.go
Normal file
131
ai-compliance-sdk/internal/iace/component_library_test.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package iace
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestGetComponentLibrary_EntryCount verifies the component library has exactly 120 entries.
|
||||
func TestGetComponentLibrary_EntryCount(t *testing.T) {
|
||||
entries := GetComponentLibrary()
|
||||
if len(entries) != 120 {
|
||||
t.Fatalf("GetComponentLibrary returned %d entries, want 120", len(entries))
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetComponentLibrary_UniqueIDs verifies all component IDs are unique.
|
||||
func TestGetComponentLibrary_UniqueIDs(t *testing.T) {
|
||||
entries := GetComponentLibrary()
|
||||
seen := make(map[string]bool)
|
||||
for _, e := range entries {
|
||||
if e.ID == "" {
|
||||
t.Errorf("component has empty ID: %s", e.NameDE)
|
||||
}
|
||||
if seen[e.ID] {
|
||||
t.Errorf("duplicate component ID: %s", e.ID)
|
||||
}
|
||||
seen[e.ID] = true
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetComponentLibrary_ValidCategories verifies all categories are valid.
|
||||
func TestGetComponentLibrary_ValidCategories(t *testing.T) {
|
||||
validCats := make(map[string]bool)
|
||||
for _, c := range ValidComponentLibraryCategories() {
|
||||
validCats[c] = true
|
||||
}
|
||||
for _, e := range GetComponentLibrary() {
|
||||
if !validCats[e.Category] {
|
||||
t.Errorf("component %s has invalid category %q", e.ID, e.Category)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetComponentLibrary_NonEmptyFields verifies required fields are filled.
|
||||
func TestGetComponentLibrary_NonEmptyFields(t *testing.T) {
|
||||
for _, e := range GetComponentLibrary() {
|
||||
if e.NameDE == "" {
|
||||
t.Errorf("component %s: NameDE is empty", e.ID)
|
||||
}
|
||||
if e.NameEN == "" {
|
||||
t.Errorf("component %s: NameEN is empty", e.ID)
|
||||
}
|
||||
if e.MapsToComponentType == "" {
|
||||
t.Errorf("component %s: MapsToComponentType is empty", e.ID)
|
||||
}
|
||||
if len(e.Tags) == 0 {
|
||||
t.Errorf("component %s: Tags is empty", e.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetComponentLibrary_CategoryDistribution verifies expected category counts.
|
||||
func TestGetComponentLibrary_CategoryDistribution(t *testing.T) {
|
||||
counts := make(map[string]int)
|
||||
for _, e := range GetComponentLibrary() {
|
||||
counts[e.Category]++
|
||||
}
|
||||
expected := map[string]int{
|
||||
"mechanical": 20,
|
||||
"structural": 10,
|
||||
"drive": 10,
|
||||
"hydraulic": 10,
|
||||
"pneumatic": 10,
|
||||
"electrical": 10,
|
||||
"control": 10,
|
||||
"sensor": 10,
|
||||
"actuator": 10,
|
||||
"safety": 10,
|
||||
"it_network": 10,
|
||||
}
|
||||
for cat, want := range expected {
|
||||
got := counts[cat]
|
||||
if got != want {
|
||||
t.Errorf("category %s: got %d entries, want %d", cat, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetEnergySources_EntryCount verifies the energy source library has exactly 20 entries.
|
||||
func TestGetEnergySources_EntryCount(t *testing.T) {
|
||||
entries := GetEnergySources()
|
||||
if len(entries) != 20 {
|
||||
t.Fatalf("GetEnergySources returned %d entries, want 20", len(entries))
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetEnergySources_UniqueIDs verifies all energy source IDs are unique.
|
||||
func TestGetEnergySources_UniqueIDs(t *testing.T) {
|
||||
entries := GetEnergySources()
|
||||
seen := make(map[string]bool)
|
||||
for _, e := range entries {
|
||||
if e.ID == "" {
|
||||
t.Errorf("energy source has empty ID: %s", e.NameDE)
|
||||
}
|
||||
if seen[e.ID] {
|
||||
t.Errorf("duplicate energy source ID: %s", e.ID)
|
||||
}
|
||||
seen[e.ID] = true
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetEnergySources_NonEmptyFields verifies required fields are filled.
|
||||
func TestGetEnergySources_NonEmptyFields(t *testing.T) {
|
||||
for _, e := range GetEnergySources() {
|
||||
if e.NameDE == "" {
|
||||
t.Errorf("energy source %s: NameDE is empty", e.ID)
|
||||
}
|
||||
if e.NameEN == "" {
|
||||
t.Errorf("energy source %s: NameEN is empty", e.ID)
|
||||
}
|
||||
if len(e.Tags) == 0 {
|
||||
t.Errorf("energy source %s: Tags is empty", e.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetEnergySources_AllHaveTags verifies every energy source has at least one tag.
|
||||
func TestGetEnergySources_AllHaveTags(t *testing.T) {
|
||||
for _, e := range GetEnergySources() {
|
||||
if len(e.Tags) == 0 {
|
||||
t.Errorf("energy source %s has no tags", e.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
458
ai-compliance-sdk/internal/iace/hazard_patterns.go
Normal file
458
ai-compliance-sdk/internal/iace/hazard_patterns.go
Normal file
@@ -0,0 +1,458 @@
|
||||
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"`
|
||||
}
|
||||
|
||||
// GetBuiltinHazardPatterns returns ~44 built-in hazard patterns organized
|
||||
// by domain (mechanical, electrical, thermal, hydraulic/pneumatic,
|
||||
// noise/vibration, ergonomic, software/control, cyber/network, AI-specific).
|
||||
func GetBuiltinHazardPatterns() []HazardPattern {
|
||||
return []HazardPattern{
|
||||
// ====================================================================
|
||||
// Mechanical Patterns (HP001-HP010)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP001", NameDE: "Quetschgefahr durch bewegte Teile", NameEN: "Crush risk from moving parts",
|
||||
RequiredComponentTags: []string{"moving_part"},
|
||||
RequiredEnergyTags: []string{"kinetic"},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M001", "M005", "M051", "M054"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08", "E20"},
|
||||
Priority: 95,
|
||||
},
|
||||
{
|
||||
ID: "HP002", NameDE: "Einzugsgefahr durch rotierende Teile", NameEN: "Entanglement risk from rotating parts",
|
||||
RequiredComponentTags: []string{"rotating_part"},
|
||||
RequiredEnergyTags: []string{"rotational"},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M002", "M051", "M053", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08"},
|
||||
Priority: 95,
|
||||
},
|
||||
{
|
||||
ID: "HP003", NameDE: "Schnittgefahr durch Schneidwerkzeuge", NameEN: "Cut risk from cutting tools",
|
||||
RequiredComponentTags: []string{"cutting_part"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M003", "M051", "M054", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP004", NameDE: "Klemmgefahr an Quetsch-/Klemmstellen", NameEN: "Pinch risk at clamping points",
|
||||
RequiredComponentTags: []string{"pinch_point"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M001", "M004", "M051", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP005", NameDE: "Quetschgefahr an Quetschstellen", NameEN: "Crush risk at crush points",
|
||||
RequiredComponentTags: []string{"crush_point"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M001", "M005", "M054"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP006", NameDE: "Gefahr durch hohe Kraefte", NameEN: "Risk from high forces",
|
||||
RequiredComponentTags: []string{"high_force"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M001", "M005", "M051", "M106"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E07", "E08"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP007", NameDE: "Gefahr durch hohe Geschwindigkeit", NameEN: "Risk from high speed",
|
||||
RequiredComponentTags: []string{"high_speed"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M002", "M051", "M053", "M054"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP008", NameDE: "Absturzgefahr / Herabfallende Teile", NameEN: "Fall/drop risk",
|
||||
RequiredComponentTags: []string{"gravity_risk"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M009", "M121", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E20"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP009", NameDE: "Gefahr durch Spannvorrichtungen", NameEN: "Clamping device risk",
|
||||
RequiredComponentTags: []string{"clamping_part"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M004", "M051", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08"},
|
||||
Priority: 80,
|
||||
},
|
||||
{
|
||||
ID: "HP010", NameDE: "Gefahr durch gespeicherte mechanische Energie", NameEN: "Stored mechanical energy risk",
|
||||
RequiredComponentTags: []string{"stored_energy"},
|
||||
RequiredEnergyTags: []string{"mechanical"},
|
||||
GeneratedHazardCats: []string{"mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M010", "M121", "M123"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E20"},
|
||||
Priority: 80,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// Electrical Patterns (HP011-HP015)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP011", NameDE: "Stromschlaggefahr durch Hochspannung", NameEN: "Electric shock risk from high voltage",
|
||||
RequiredComponentTags: []string{"high_voltage"},
|
||||
RequiredEnergyTags: []string{"electrical_energy"},
|
||||
GeneratedHazardCats: []string{"electrical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M061", "M062", "M063", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E04", "E10"},
|
||||
Priority: 95,
|
||||
},
|
||||
{
|
||||
ID: "HP012", NameDE: "Gefahr durch elektrische Komponenten", NameEN: "Risk from electrical components",
|
||||
RequiredComponentTags: []string{"electrical_part"},
|
||||
RequiredEnergyTags: []string{"electrical_energy"},
|
||||
GeneratedHazardCats: []string{"electrical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M061", "M064", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E04", "E10"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP013", NameDE: "Gefahr durch gespeicherte elektrische Energie", NameEN: "Stored electrical energy risk",
|
||||
RequiredComponentTags: []string{"stored_energy"},
|
||||
RequiredEnergyTags: []string{"electrical_energy"},
|
||||
GeneratedHazardCats: []string{"electrical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M062", "M063", "M121", "M123"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E10"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP014", NameDE: "Kurzschluss-/Lichtbogengefahr", NameEN: "Short circuit / arc flash risk",
|
||||
RequiredComponentTags: []string{"high_voltage", "electrical_part"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"electrical_hazard", "thermal_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M061", "M065", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E04", "E10"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP015", NameDE: "EMV-Stoerungsgefahr", NameEN: "EMC interference risk",
|
||||
RequiredComponentTags: []string{"electrical_part"},
|
||||
RequiredEnergyTags: []string{"electromagnetic"},
|
||||
GeneratedHazardCats: []string{"emc_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M066", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E10"},
|
||||
Priority: 70,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// Thermal Patterns (HP016-HP018)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP016", NameDE: "Verbrennungsgefahr durch heisse Oberflaechen", NameEN: "Burn risk from hot surfaces",
|
||||
RequiredComponentTags: []string{"high_temperature"},
|
||||
RequiredEnergyTags: []string{"thermal"},
|
||||
GeneratedHazardCats: []string{"thermal_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M071", "M121", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E20"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP017", NameDE: "Strahlungsgefahr (Laser/optisch)", NameEN: "Radiation risk (laser/optical)",
|
||||
RequiredComponentTags: []string{"radiation_risk"},
|
||||
RequiredEnergyTags: []string{"radiation"},
|
||||
GeneratedHazardCats: []string{"thermal_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M072", "M051", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E20"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP018", NameDE: "Verbrennungsgefahr durch Aktuatoren", NameEN: "Burn risk from actuators",
|
||||
RequiredComponentTags: []string{"actuator_part", "high_temperature"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"thermal_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M071", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01"},
|
||||
Priority: 75,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// Hydraulic / Pneumatic Patterns (HP019-HP022)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP019", NameDE: "Hydraulikdruck-Gefahr", NameEN: "Hydraulic pressure hazard",
|
||||
RequiredComponentTags: []string{"hydraulic_part"},
|
||||
RequiredEnergyTags: []string{"hydraulic_pressure"},
|
||||
GeneratedHazardCats: []string{"pneumatic_hydraulic"},
|
||||
SuggestedMeasureIDs: []string{"M081", "M082", "M121", "M123"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E05", "E11"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP020", NameDE: "Pneumatikdruck-Gefahr", NameEN: "Pneumatic pressure hazard",
|
||||
RequiredComponentTags: []string{"pneumatic_part"},
|
||||
RequiredEnergyTags: []string{"pneumatic_pressure"},
|
||||
GeneratedHazardCats: []string{"pneumatic_hydraulic"},
|
||||
SuggestedMeasureIDs: []string{"M083", "M084", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E06", "E11"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP021", NameDE: "Gefahr durch gespeicherten Hydraulikdruck", NameEN: "Stored hydraulic pressure risk",
|
||||
RequiredComponentTags: []string{"hydraulic_part", "stored_energy"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"pneumatic_hydraulic"},
|
||||
SuggestedMeasureIDs: []string{"M081", "M082", "M123"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E05", "E11"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP022", NameDE: "Gefahr durch Druckluftspeicher", NameEN: "Stored pneumatic pressure risk",
|
||||
RequiredComponentTags: []string{"pneumatic_part", "stored_energy"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"pneumatic_hydraulic"},
|
||||
SuggestedMeasureIDs: []string{"M083", "M084", "M123"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E06", "E11"},
|
||||
Priority: 85,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// Noise / Vibration Patterns (HP023-HP025)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP023", NameDE: "Laermgefahr", NameEN: "Noise hazard",
|
||||
RequiredComponentTags: []string{"noise_source"},
|
||||
RequiredEnergyTags: []string{"acoustic"},
|
||||
GeneratedHazardCats: []string{"noise_vibration"},
|
||||
SuggestedMeasureIDs: []string{"M091", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E12"},
|
||||
Priority: 70,
|
||||
},
|
||||
{
|
||||
ID: "HP024", NameDE: "Vibrationsgefahr", NameEN: "Vibration hazard",
|
||||
RequiredComponentTags: []string{"vibration_source"},
|
||||
RequiredEnergyTags: []string{"vibration"},
|
||||
GeneratedHazardCats: []string{"noise_vibration"},
|
||||
SuggestedMeasureIDs: []string{"M092", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E13"},
|
||||
Priority: 65,
|
||||
},
|
||||
{
|
||||
ID: "HP025", NameDE: "Laerm durch rotierende Hochgeschwindigkeitsteile", NameEN: "Noise from high-speed rotating parts",
|
||||
RequiredComponentTags: []string{"rotating_part", "high_speed"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"noise_vibration"},
|
||||
SuggestedMeasureIDs: []string{"M091", "M092", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E12", "E13"},
|
||||
Priority: 70,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// Ergonomic Patterns (HP026-HP028)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP026", NameDE: "Ergonomische Belastung an Bedienstationen", NameEN: "Ergonomic risk at operator stations",
|
||||
RequiredComponentTags: []string{"user_interface"},
|
||||
RequiredEnergyTags: []string{"ergonomic"},
|
||||
GeneratedHazardCats: []string{"ergonomic"},
|
||||
SuggestedMeasureIDs: []string{"M126", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E24"},
|
||||
Priority: 50,
|
||||
},
|
||||
{
|
||||
ID: "HP027", NameDE: "Ergonomische Belastung bei Wartung in der Hoehe", NameEN: "Ergonomic risk for work at height",
|
||||
RequiredComponentTags: []string{"structural_part", "gravity_risk"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"ergonomic", "mechanical_hazard"},
|
||||
SuggestedMeasureIDs: []string{"M121", "M131"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E20"},
|
||||
Priority: 60,
|
||||
},
|
||||
{
|
||||
ID: "HP028", NameDE: "Fehlbedienungsgefahr", NameEN: "Mode confusion / misoperation risk",
|
||||
RequiredComponentTags: []string{"user_interface", "programmable"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"hmi_error", "mode_confusion"},
|
||||
SuggestedMeasureIDs: []string{"M126", "M127", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E14", "E24"},
|
||||
Priority: 70,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// Software / Control Patterns (HP029-HP034)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP029", NameDE: "Software-Fehler in Steuerung", NameEN: "Software fault in controller",
|
||||
RequiredComponentTags: []string{"has_software", "programmable"},
|
||||
RequiredEnergyTags: []string{},
|
||||
ExcludedComponentTags: []string{"has_ai"},
|
||||
GeneratedHazardCats: []string{"software_fault"},
|
||||
SuggestedMeasureIDs: []string{"M101", "M102", "M103"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E14"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP030", NameDE: "Sicherheitsfunktionsversagen", NameEN: "Safety function failure",
|
||||
RequiredComponentTags: []string{"safety_device"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"safety_function_failure"},
|
||||
SuggestedMeasureIDs: []string{"M104", "M105", "M051"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E07", "E08", "E09"},
|
||||
Priority: 95,
|
||||
},
|
||||
{
|
||||
ID: "HP031", NameDE: "Konfigurationsfehler", NameEN: "Configuration error",
|
||||
RequiredComponentTags: []string{"programmable"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"configuration_error"},
|
||||
SuggestedMeasureIDs: []string{"M145", "M146", "M121"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E14"},
|
||||
Priority: 70,
|
||||
},
|
||||
{
|
||||
ID: "HP032", NameDE: "Fehlende Protokollierung / Audit", NameEN: "Missing logging / audit",
|
||||
RequiredComponentTags: []string{"has_software"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"logging_audit_failure"},
|
||||
SuggestedMeasureIDs: []string{"M142", "M149"},
|
||||
SuggestedEvidenceIDs: []string{"E01"},
|
||||
Priority: 50,
|
||||
},
|
||||
{
|
||||
ID: "HP033", NameDE: "Update-Fehler / Rollback-Problem", NameEN: "Update failure / rollback problem",
|
||||
RequiredComponentTags: []string{"has_software", "programmable"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"update_failure"},
|
||||
SuggestedMeasureIDs: []string{"M138", "M141", "M146"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E14"},
|
||||
Priority: 65,
|
||||
},
|
||||
{
|
||||
ID: "HP034", NameDE: "Verriegelungs-Umgehungsgefahr", NameEN: "Interlock bypass risk",
|
||||
RequiredComponentTags: []string{"interlocked"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"safety_function_failure"},
|
||||
SuggestedMeasureIDs: []string{"M051", "M104", "M107"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E08"},
|
||||
Priority: 85,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// Cyber / Network Patterns (HP035-HP039)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP035", NameDE: "Unbefugter Netzwerkzugriff", NameEN: "Unauthorized network access",
|
||||
RequiredComponentTags: []string{"networked"},
|
||||
RequiredEnergyTags: []string{"cyber"},
|
||||
GeneratedHazardCats: []string{"unauthorized_access"},
|
||||
SuggestedMeasureIDs: []string{"M111", "M112", "M113", "M140"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E16", "E17"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP036", NameDE: "Kommunikationsausfall", NameEN: "Communication failure",
|
||||
RequiredComponentTags: []string{"networked", "it_component"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"communication_failure"},
|
||||
SuggestedMeasureIDs: []string{"M114", "M115"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E17"},
|
||||
Priority: 80,
|
||||
},
|
||||
{
|
||||
ID: "HP037", NameDE: "Firmware-Manipulation", NameEN: "Firmware manipulation",
|
||||
RequiredComponentTags: []string{"has_software", "networked"},
|
||||
RequiredEnergyTags: []string{"cyber"},
|
||||
GeneratedHazardCats: []string{"firmware_corruption"},
|
||||
SuggestedMeasureIDs: []string{"M116", "M138", "M146"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E16", "E18"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP038", NameDE: "Drahtlos-Angriff (WiFi/Bluetooth)", NameEN: "Wireless attack (WiFi/Bluetooth)",
|
||||
RequiredComponentTags: []string{"wireless"},
|
||||
RequiredEnergyTags: []string{"cyber"},
|
||||
GeneratedHazardCats: []string{"unauthorized_access"},
|
||||
SuggestedMeasureIDs: []string{"M111", "M113", "M140"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E16"},
|
||||
Priority: 80,
|
||||
},
|
||||
{
|
||||
ID: "HP039", NameDE: "Supply-Chain-Angriff auf IT-Komponenten", NameEN: "Supply chain attack on IT components",
|
||||
RequiredComponentTags: []string{"it_component", "has_software"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"unauthorized_access", "firmware_corruption"},
|
||||
SuggestedMeasureIDs: []string{"M116", "M118"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E18", "E19"},
|
||||
Priority: 75,
|
||||
},
|
||||
|
||||
// ====================================================================
|
||||
// AI-Specific Patterns (HP040-HP044)
|
||||
// ====================================================================
|
||||
{
|
||||
ID: "HP040", NameDE: "KI-Fehlklassifikation", NameEN: "AI misclassification",
|
||||
RequiredComponentTags: []string{"has_ai"},
|
||||
RequiredEnergyTags: []string{"ai_model"},
|
||||
GeneratedHazardCats: []string{"false_classification"},
|
||||
SuggestedMeasureIDs: []string{"M101", "M102"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E15"},
|
||||
Priority: 90,
|
||||
},
|
||||
{
|
||||
ID: "HP041", NameDE: "Model Drift / Concept Drift", NameEN: "Model drift / concept drift",
|
||||
RequiredComponentTags: []string{"has_ai"},
|
||||
RequiredEnergyTags: []string{"ai_model"},
|
||||
GeneratedHazardCats: []string{"model_drift"},
|
||||
SuggestedMeasureIDs: []string{"M103"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E15"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP042", NameDE: "Data Poisoning / Adversarial Attack", NameEN: "Data poisoning / adversarial attack",
|
||||
RequiredComponentTags: []string{"has_ai"},
|
||||
RequiredEnergyTags: []string{"cyber", "ai_model"},
|
||||
GeneratedHazardCats: []string{"data_poisoning"},
|
||||
SuggestedMeasureIDs: []string{"M101", "M116"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E15", "E16"},
|
||||
Priority: 85,
|
||||
},
|
||||
{
|
||||
ID: "HP043", NameDE: "Unbeabsichtigte KI-Diskriminierung", NameEN: "Unintended AI bias",
|
||||
RequiredComponentTags: []string{"has_ai"},
|
||||
RequiredEnergyTags: []string{"ai_model"},
|
||||
GeneratedHazardCats: []string{"unintended_bias"},
|
||||
SuggestedMeasureIDs: []string{"M101"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E15"},
|
||||
Priority: 75,
|
||||
},
|
||||
{
|
||||
ID: "HP044", NameDE: "KI-Sensormanipulation", NameEN: "AI sensor spoofing",
|
||||
RequiredComponentTags: []string{"has_ai", "sensor_part"},
|
||||
RequiredEnergyTags: []string{},
|
||||
GeneratedHazardCats: []string{"sensor_spoofing"},
|
||||
SuggestedMeasureIDs: []string{"M101", "M102"},
|
||||
SuggestedEvidenceIDs: []string{"E01", "E15"},
|
||||
Priority: 80,
|
||||
},
|
||||
}
|
||||
}
|
||||
126
ai-compliance-sdk/internal/iace/hazard_patterns_test.go
Normal file
126
ai-compliance-sdk/internal/iace/hazard_patterns_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package iace
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestGetBuiltinHazardPatterns_UniqueIDs verifies all pattern IDs are unique.
|
||||
func TestGetBuiltinHazardPatterns_UniqueIDs(t *testing.T) {
|
||||
patterns := GetBuiltinHazardPatterns()
|
||||
seen := make(map[string]bool)
|
||||
for _, p := range patterns {
|
||||
if p.ID == "" {
|
||||
t.Errorf("pattern has empty ID: %s", p.NameDE)
|
||||
}
|
||||
if seen[p.ID] {
|
||||
t.Errorf("duplicate pattern ID: %s", p.ID)
|
||||
}
|
||||
seen[p.ID] = true
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_Count verifies the expected number of patterns.
|
||||
func TestGetBuiltinHazardPatterns_Count(t *testing.T) {
|
||||
patterns := GetBuiltinHazardPatterns()
|
||||
if len(patterns) < 40 {
|
||||
t.Fatalf("expected at least 40 patterns, got %d", len(patterns))
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_AllHaveRequiredTags verifies every pattern has at
|
||||
// least one required component tag or energy tag.
|
||||
func TestGetBuiltinHazardPatterns_AllHaveRequiredTags(t *testing.T) {
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
if len(p.RequiredComponentTags) == 0 && len(p.RequiredEnergyTags) == 0 {
|
||||
t.Errorf("pattern %s (%s) has no required component or energy tags", p.ID, p.NameDE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_AllHaveGeneratedHazardCats verifies every pattern
|
||||
// generates at least one hazard category.
|
||||
func TestGetBuiltinHazardPatterns_AllHaveGeneratedHazardCats(t *testing.T) {
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
if len(p.GeneratedHazardCats) == 0 {
|
||||
t.Errorf("pattern %s (%s) has no generated hazard categories", p.ID, p.NameDE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_AllHaveSuggestedMeasures verifies every pattern
|
||||
// suggests at least one measure.
|
||||
func TestGetBuiltinHazardPatterns_AllHaveSuggestedMeasures(t *testing.T) {
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
if len(p.SuggestedMeasureIDs) == 0 {
|
||||
t.Errorf("pattern %s (%s) has no suggested measure IDs", p.ID, p.NameDE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_AllHaveSuggestedEvidence verifies every pattern
|
||||
// suggests at least one evidence type.
|
||||
func TestGetBuiltinHazardPatterns_AllHaveSuggestedEvidence(t *testing.T) {
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
if len(p.SuggestedEvidenceIDs) == 0 {
|
||||
t.Errorf("pattern %s (%s) has no suggested evidence IDs", p.ID, p.NameDE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_ValidPriorities verifies all priorities are 1-100.
|
||||
func TestGetBuiltinHazardPatterns_ValidPriorities(t *testing.T) {
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
if p.Priority < 1 || p.Priority > 100 {
|
||||
t.Errorf("pattern %s has invalid priority %d (want 1-100)", p.ID, p.Priority)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_ReferencedMeasuresExist verifies all referenced
|
||||
// measure IDs exist in the protective measures library.
|
||||
func TestGetBuiltinHazardPatterns_ReferencedMeasuresExist(t *testing.T) {
|
||||
measureIDs := make(map[string]bool)
|
||||
for _, m := range GetProtectiveMeasureLibrary() {
|
||||
measureIDs[m.ID] = true
|
||||
}
|
||||
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
for _, mid := range p.SuggestedMeasureIDs {
|
||||
if !measureIDs[mid] {
|
||||
t.Errorf("pattern %s references non-existent measure ID %s", p.ID, mid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_ReferencedEvidenceExist verifies all referenced
|
||||
// evidence IDs exist in the evidence type library.
|
||||
func TestGetBuiltinHazardPatterns_ReferencedEvidenceExist(t *testing.T) {
|
||||
evidenceIDs := make(map[string]bool)
|
||||
for _, e := range GetEvidenceTypeLibrary() {
|
||||
evidenceIDs[e.ID] = true
|
||||
}
|
||||
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
for _, eid := range p.SuggestedEvidenceIDs {
|
||||
if !evidenceIDs[eid] {
|
||||
t.Errorf("pattern %s references non-existent evidence ID %s", p.ID, eid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetBuiltinHazardPatterns_HazardCategoriesValid verifies all generated
|
||||
// hazard categories match known categories in the hazard library.
|
||||
func TestGetBuiltinHazardPatterns_HazardCategoriesValid(t *testing.T) {
|
||||
validCategories := make(map[string]bool)
|
||||
for _, h := range GetBuiltinHazardLibrary() {
|
||||
validCategories[h.Category] = true
|
||||
}
|
||||
|
||||
for _, p := range GetBuiltinHazardPatterns() {
|
||||
for _, cat := range p.GeneratedHazardCats {
|
||||
if !validCategories[cat] {
|
||||
t.Errorf("pattern %s references unknown hazard category %q", p.ID, cat)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,6 +277,7 @@ type HazardLibraryEntry struct {
|
||||
RecommendedMeasuresInformation []string `json:"recommended_measures_information,omitempty"`
|
||||
SuggestedEvidence []string `json:"suggested_evidence,omitempty"`
|
||||
RelatedKeywords []string `json:"related_keywords,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
IsBuiltin bool `json:"is_builtin"`
|
||||
TenantID *uuid.UUID `json:"tenant_id,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
@@ -580,11 +581,12 @@ type RoleInfo struct {
|
||||
|
||||
// EvidenceTypeInfo represents an evidence/verification type with labels
|
||||
type EvidenceTypeInfo struct {
|
||||
ID string `json:"id"`
|
||||
Category string `json:"category"`
|
||||
LabelDE string `json:"label_de"`
|
||||
LabelEN string `json:"label_en"`
|
||||
Sort int `json:"sort_order"`
|
||||
ID string `json:"id"`
|
||||
Category string `json:"category"`
|
||||
LabelDE string `json:"label_de"`
|
||||
LabelEN string `json:"label_en"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Sort int `json:"sort_order"`
|
||||
}
|
||||
|
||||
// ProtectiveMeasureEntry represents a protective measure from the library
|
||||
@@ -596,6 +598,7 @@ type ProtectiveMeasureEntry struct {
|
||||
Description string `json:"description"`
|
||||
HazardCategory string `json:"hazard_category,omitempty"`
|
||||
Examples []string `json:"examples,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// ValidateMitigationHierarchyRequest is the request for hierarchy validation
|
||||
|
||||
240
ai-compliance-sdk/internal/iace/pattern_engine.go
Normal file
240
ai-compliance-sdk/internal/iace/pattern_engine.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package iace
|
||||
|
||||
import "sort"
|
||||
|
||||
// MatchInput defines the inputs for the pattern-matching engine.
|
||||
type MatchInput struct {
|
||||
ComponentLibraryIDs []string `json:"component_library_ids"`
|
||||
EnergySourceIDs []string `json:"energy_source_ids"`
|
||||
LifecyclePhases []string `json:"lifecycle_phases"`
|
||||
CustomTags []string `json:"custom_tags"`
|
||||
}
|
||||
|
||||
// MatchOutput contains the results of pattern matching.
|
||||
type MatchOutput struct {
|
||||
MatchedPatterns []PatternMatch `json:"matched_patterns"`
|
||||
SuggestedHazards []HazardSuggestion `json:"suggested_hazards"`
|
||||
SuggestedMeasures []MeasureSuggestion `json:"suggested_measures"`
|
||||
SuggestedEvidence []EvidenceSuggestion `json:"suggested_evidence"`
|
||||
ResolvedTags []string `json:"resolved_tags"`
|
||||
}
|
||||
|
||||
// PatternMatch records which pattern fired and why.
|
||||
type PatternMatch struct {
|
||||
PatternID string `json:"pattern_id"`
|
||||
PatternName string `json:"pattern_name"`
|
||||
Priority int `json:"priority"`
|
||||
MatchedTags []string `json:"matched_tags"`
|
||||
}
|
||||
|
||||
// HazardSuggestion is a suggested hazard from pattern matching.
|
||||
type HazardSuggestion struct {
|
||||
Category string `json:"category"`
|
||||
SourcePatterns []string `json:"source_patterns"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
}
|
||||
|
||||
// MeasureSuggestion is a suggested protective measure from pattern matching.
|
||||
type MeasureSuggestion struct {
|
||||
MeasureID string `json:"measure_id"`
|
||||
SourcePatterns []string `json:"source_patterns"`
|
||||
}
|
||||
|
||||
// EvidenceSuggestion is a suggested evidence type from pattern matching.
|
||||
type EvidenceSuggestion struct {
|
||||
EvidenceID string `json:"evidence_id"`
|
||||
SourcePatterns []string `json:"source_patterns"`
|
||||
}
|
||||
|
||||
// PatternEngine evaluates hazard patterns against resolved tags.
|
||||
type PatternEngine struct {
|
||||
resolver *TagResolver
|
||||
patterns []HazardPattern
|
||||
}
|
||||
|
||||
// NewPatternEngine creates a PatternEngine with built-in patterns and resolver.
|
||||
func NewPatternEngine() *PatternEngine {
|
||||
return &PatternEngine{
|
||||
resolver: NewTagResolver(),
|
||||
patterns: GetBuiltinHazardPatterns(),
|
||||
}
|
||||
}
|
||||
|
||||
// Match executes the pattern-matching algorithm:
|
||||
// 1. Resolve component + energy IDs → tags
|
||||
// 2. Merge with custom tags
|
||||
// 3. Sort patterns by priority (descending)
|
||||
// 4. For each pattern: check required_tags (AND) and excluded_tags (NOT)
|
||||
// 5. Collect hazards, measures, evidence from fired patterns (deduplicated)
|
||||
// 6. Calculate confidence scores
|
||||
func (e *PatternEngine) Match(input MatchInput) *MatchOutput {
|
||||
// Step 1+2: resolve all tags
|
||||
allTags := e.resolver.ResolveTags(input.ComponentLibraryIDs, input.EnergySourceIDs, input.CustomTags)
|
||||
|
||||
if len(allTags) == 0 {
|
||||
return &MatchOutput{ResolvedTags: []string{}}
|
||||
}
|
||||
|
||||
tagSet := toSet(allTags)
|
||||
|
||||
// Step 3: sort patterns by priority descending
|
||||
patterns := make([]HazardPattern, len(e.patterns))
|
||||
copy(patterns, e.patterns)
|
||||
sort.Slice(patterns, func(i, j int) bool {
|
||||
return patterns[i].Priority > patterns[j].Priority
|
||||
})
|
||||
|
||||
// Step 4+5: evaluate each pattern
|
||||
var matchedPatterns []PatternMatch
|
||||
hazardCatSources := make(map[string][]string) // category → pattern IDs
|
||||
measureSources := make(map[string][]string) // measure ID → pattern IDs
|
||||
evidenceSources := make(map[string][]string) // evidence ID → pattern IDs
|
||||
|
||||
for _, p := range patterns {
|
||||
if !patternMatches(p, tagSet, input.LifecyclePhases) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Collect the tags that contributed to this match
|
||||
var matchedTags []string
|
||||
for _, t := range p.RequiredComponentTags {
|
||||
if tagSet[t] {
|
||||
matchedTags = append(matchedTags, t)
|
||||
}
|
||||
}
|
||||
for _, t := range p.RequiredEnergyTags {
|
||||
if tagSet[t] {
|
||||
matchedTags = append(matchedTags, t)
|
||||
}
|
||||
}
|
||||
|
||||
matchedPatterns = append(matchedPatterns, PatternMatch{
|
||||
PatternID: p.ID,
|
||||
PatternName: p.NameDE,
|
||||
Priority: p.Priority,
|
||||
MatchedTags: matchedTags,
|
||||
})
|
||||
|
||||
for _, cat := range p.GeneratedHazardCats {
|
||||
hazardCatSources[cat] = appendUnique(hazardCatSources[cat], p.ID)
|
||||
}
|
||||
for _, mid := range p.SuggestedMeasureIDs {
|
||||
measureSources[mid] = appendUnique(measureSources[mid], p.ID)
|
||||
}
|
||||
for _, eid := range p.SuggestedEvidenceIDs {
|
||||
evidenceSources[eid] = appendUnique(evidenceSources[eid], p.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6: build output with confidence scores
|
||||
totalPatterns := len(patterns)
|
||||
firedCount := len(matchedPatterns)
|
||||
|
||||
var suggestedHazards []HazardSuggestion
|
||||
for cat, sources := range hazardCatSources {
|
||||
confidence := float64(len(sources)) / float64(maxInt(firedCount, 1))
|
||||
if confidence > 1.0 {
|
||||
confidence = 1.0
|
||||
}
|
||||
suggestedHazards = append(suggestedHazards, HazardSuggestion{
|
||||
Category: cat,
|
||||
SourcePatterns: sources,
|
||||
Confidence: confidence,
|
||||
})
|
||||
}
|
||||
// Sort by confidence descending
|
||||
sort.Slice(suggestedHazards, func(i, j int) bool {
|
||||
return suggestedHazards[i].Confidence > suggestedHazards[j].Confidence
|
||||
})
|
||||
|
||||
var suggestedMeasures []MeasureSuggestion
|
||||
for mid, sources := range measureSources {
|
||||
suggestedMeasures = append(suggestedMeasures, MeasureSuggestion{
|
||||
MeasureID: mid,
|
||||
SourcePatterns: sources,
|
||||
})
|
||||
}
|
||||
sort.Slice(suggestedMeasures, func(i, j int) bool {
|
||||
return suggestedMeasures[i].MeasureID < suggestedMeasures[j].MeasureID
|
||||
})
|
||||
|
||||
var suggestedEvidence []EvidenceSuggestion
|
||||
for eid, sources := range evidenceSources {
|
||||
suggestedEvidence = append(suggestedEvidence, EvidenceSuggestion{
|
||||
EvidenceID: eid,
|
||||
SourcePatterns: sources,
|
||||
})
|
||||
}
|
||||
sort.Slice(suggestedEvidence, func(i, j int) bool {
|
||||
return suggestedEvidence[i].EvidenceID < suggestedEvidence[j].EvidenceID
|
||||
})
|
||||
|
||||
_ = totalPatterns // used conceptually for confidence normalization
|
||||
|
||||
return &MatchOutput{
|
||||
MatchedPatterns: matchedPatterns,
|
||||
SuggestedHazards: suggestedHazards,
|
||||
SuggestedMeasures: suggestedMeasures,
|
||||
SuggestedEvidence: suggestedEvidence,
|
||||
ResolvedTags: allTags,
|
||||
}
|
||||
}
|
||||
|
||||
// patternMatches checks if a pattern fires given the resolved tag set and lifecycle phases.
|
||||
func patternMatches(p HazardPattern, tagSet map[string]bool, lifecyclePhases []string) bool {
|
||||
// All required component tags must be present (AND)
|
||||
for _, t := range p.RequiredComponentTags {
|
||||
if !tagSet[t] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// All required energy tags must be present (AND)
|
||||
for _, t := range p.RequiredEnergyTags {
|
||||
if !tagSet[t] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// None of the excluded tags may be present (NOT)
|
||||
for _, t := range p.ExcludedComponentTags {
|
||||
if tagSet[t] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// If pattern requires specific lifecycle phases, at least one must match
|
||||
if len(p.RequiredLifecycles) > 0 && len(lifecyclePhases) > 0 {
|
||||
found := false
|
||||
phaseSet := toSet(lifecyclePhases)
|
||||
for _, lp := range p.RequiredLifecycles {
|
||||
if phaseSet[lp] {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// appendUnique appends val to slice if not already present.
|
||||
func appendUnique(slice []string, val string) []string {
|
||||
for _, s := range slice {
|
||||
if s == val {
|
||||
return slice
|
||||
}
|
||||
}
|
||||
return append(slice, val)
|
||||
}
|
||||
|
||||
// maxInt returns the larger of a and b.
|
||||
func maxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
217
ai-compliance-sdk/internal/iace/pattern_engine_test.go
Normal file
217
ai-compliance-sdk/internal/iace/pattern_engine_test.go
Normal file
@@ -0,0 +1,217 @@
|
||||
package iace
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPatternEngine_RobotArm_MechanicalHazards(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C001"}, // Roboterarm: moving_part, rotating_part, high_force
|
||||
EnergySourceIDs: []string{"EN01", "EN02"}, // kinetic translational + rotational
|
||||
})
|
||||
|
||||
if len(result.MatchedPatterns) == 0 {
|
||||
t.Fatal("expected matched patterns for robot arm + kinetic energy")
|
||||
}
|
||||
|
||||
// Should match mechanical hazard patterns (HP001, HP002, HP006)
|
||||
hasMechHazard := false
|
||||
for _, h := range result.SuggestedHazards {
|
||||
if h.Category == "mechanical_hazard" {
|
||||
hasMechHazard = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasMechHazard {
|
||||
t.Error("expected mechanical_hazard in suggested hazards for robot arm")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_Schaltschrank_ElectricalHazards(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C061"}, // Schaltschrank: high_voltage, electrical_part
|
||||
EnergySourceIDs: []string{"EN04"}, // Elektrische Energie
|
||||
})
|
||||
|
||||
if len(result.MatchedPatterns) == 0 {
|
||||
t.Fatal("expected matched patterns for control cabinet + electrical energy")
|
||||
}
|
||||
|
||||
hasElecHazard := false
|
||||
for _, h := range result.SuggestedHazards {
|
||||
if h.Category == "electrical_hazard" {
|
||||
hasElecHazard = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasElecHazard {
|
||||
t.Error("expected electrical_hazard in suggested hazards for Schaltschrank")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_SPS_Switch_SoftwareCyberHazards(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C071", "C111"}, // SPS + Switch: has_software, programmable, networked, it_component
|
||||
EnergySourceIDs: []string{"EN18"}, // Cyber/Data energy
|
||||
})
|
||||
|
||||
if len(result.MatchedPatterns) == 0 {
|
||||
t.Fatal("expected matched patterns for SPS + Switch + cyber energy")
|
||||
}
|
||||
|
||||
categories := make(map[string]bool)
|
||||
for _, h := range result.SuggestedHazards {
|
||||
categories[h.Category] = true
|
||||
}
|
||||
|
||||
if !categories["software_fault"] {
|
||||
t.Error("expected software_fault hazard for SPS")
|
||||
}
|
||||
if !categories["unauthorized_access"] {
|
||||
t.Error("expected unauthorized_access hazard for networked components + cyber energy")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_AIModule_AISpecificHazards(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C119"}, // KI-Inferenzmodul: has_ai, has_software, networked
|
||||
EnergySourceIDs: []string{"EN19", "EN18"}, // AI model + cyber energy
|
||||
})
|
||||
|
||||
if len(result.MatchedPatterns) == 0 {
|
||||
t.Fatal("expected matched patterns for AI inference module")
|
||||
}
|
||||
|
||||
categories := make(map[string]bool)
|
||||
for _, h := range result.SuggestedHazards {
|
||||
categories[h.Category] = true
|
||||
}
|
||||
|
||||
if !categories["false_classification"] {
|
||||
t.Error("expected false_classification hazard for AI module")
|
||||
}
|
||||
if !categories["model_drift"] {
|
||||
t.Error("expected model_drift hazard for AI module")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_EmptyInput_EmptyResults(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{})
|
||||
|
||||
if len(result.MatchedPatterns) != 0 {
|
||||
t.Errorf("expected no matched patterns for empty input, got %d", len(result.MatchedPatterns))
|
||||
}
|
||||
if len(result.SuggestedHazards) != 0 {
|
||||
t.Errorf("expected no suggested hazards for empty input, got %d", len(result.SuggestedHazards))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_ExclusionTags(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
|
||||
// HP029 requires has_software+programmable, excludes has_ai
|
||||
// C071 (SPS) has has_software+programmable but NOT has_ai → should match HP029
|
||||
result1 := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C071"}, // SPS
|
||||
})
|
||||
hasHP029 := false
|
||||
for _, p := range result1.MatchedPatterns {
|
||||
if p.PatternID == "HP029" {
|
||||
hasHP029 = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasHP029 {
|
||||
t.Error("HP029 should match for SPS (has_software+programmable, no has_ai)")
|
||||
}
|
||||
|
||||
// C119 (KI-Inferenzmodul) has has_ai → HP029 should be excluded
|
||||
result2 := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C119"}, // KI-Inferenzmodul: has_ai
|
||||
})
|
||||
hasHP029_2 := false
|
||||
for _, p := range result2.MatchedPatterns {
|
||||
if p.PatternID == "HP029" {
|
||||
hasHP029_2 = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasHP029_2 {
|
||||
t.Error("HP029 should NOT match for AI module (excluded by has_ai tag)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_HydraulicPatterns(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C042"}, // Hydraulikzylinder
|
||||
EnergySourceIDs: []string{"EN05"}, // Hydraulische Energie
|
||||
})
|
||||
|
||||
hasHydraulicHazard := false
|
||||
for _, h := range result.SuggestedHazards {
|
||||
if h.Category == "pneumatic_hydraulic" {
|
||||
hasHydraulicHazard = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasHydraulicHazard {
|
||||
t.Error("expected pneumatic_hydraulic hazard for hydraulic cylinder + hydraulic energy")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_MeasuresAndEvidence(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C001"}, // Roboterarm
|
||||
EnergySourceIDs: []string{"EN01"}, // Kinetische Energie
|
||||
})
|
||||
|
||||
if len(result.SuggestedMeasures) == 0 {
|
||||
t.Error("expected suggested measures for robot arm")
|
||||
}
|
||||
if len(result.SuggestedEvidence) == 0 {
|
||||
t.Error("expected suggested evidence for robot arm")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_ResolvedTags(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C001"},
|
||||
EnergySourceIDs: []string{"EN01"},
|
||||
CustomTags: []string{"my_custom_tag"},
|
||||
})
|
||||
|
||||
tagSet := toSet(result.ResolvedTags)
|
||||
if !tagSet["moving_part"] {
|
||||
t.Error("expected 'moving_part' in resolved tags")
|
||||
}
|
||||
if !tagSet["kinetic"] {
|
||||
t.Error("expected 'kinetic' in resolved tags")
|
||||
}
|
||||
if !tagSet["my_custom_tag"] {
|
||||
t.Error("expected 'my_custom_tag' in resolved tags")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternEngine_SafetyDevice_HighPriority(t *testing.T) {
|
||||
engine := NewPatternEngine()
|
||||
result := engine.Match(MatchInput{
|
||||
ComponentLibraryIDs: []string{"C101"}, // Not-Halt-Taster: safety_device, emergency_stop
|
||||
})
|
||||
|
||||
hasSafetyFail := false
|
||||
for _, h := range result.SuggestedHazards {
|
||||
if h.Category == "safety_function_failure" {
|
||||
hasSafetyFail = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasSafetyFail {
|
||||
t.Error("expected safety_function_failure for Not-Halt-Taster")
|
||||
}
|
||||
}
|
||||
@@ -980,6 +980,11 @@ func (s *Store) ListMitigations(ctx context.Context, hazardID uuid.UUID) ([]Miti
|
||||
return mitigations, nil
|
||||
}
|
||||
|
||||
// GetMitigation fetches a single mitigation by ID.
|
||||
func (s *Store) GetMitigation(ctx context.Context, id uuid.UUID) (*Mitigation, error) {
|
||||
return s.getMitigation(ctx, id)
|
||||
}
|
||||
|
||||
// getMitigation is a helper to fetch a single mitigation by ID
|
||||
func (s *Store) getMitigation(ctx context.Context, id uuid.UUID) (*Mitigation, error) {
|
||||
var m Mitigation
|
||||
|
||||
172
ai-compliance-sdk/internal/iace/tag_resolver.go
Normal file
172
ai-compliance-sdk/internal/iace/tag_resolver.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package iace
|
||||
|
||||
// TagResolver resolves component/energy IDs to tags and finds matching
|
||||
// hazards, measures, and evidence by tag intersection.
|
||||
type TagResolver struct {
|
||||
componentIndex map[string]ComponentLibraryEntry
|
||||
energyIndex map[string]EnergySourceEntry
|
||||
}
|
||||
|
||||
// NewTagResolver creates a TagResolver pre-indexed from the built-in libraries.
|
||||
func NewTagResolver() *TagResolver {
|
||||
tr := &TagResolver{
|
||||
componentIndex: make(map[string]ComponentLibraryEntry),
|
||||
energyIndex: make(map[string]EnergySourceEntry),
|
||||
}
|
||||
for _, c := range GetComponentLibrary() {
|
||||
tr.componentIndex[c.ID] = c
|
||||
}
|
||||
for _, e := range GetEnergySources() {
|
||||
tr.energyIndex[e.ID] = e
|
||||
}
|
||||
return tr
|
||||
}
|
||||
|
||||
// ResolveComponentTags resolves component library IDs to their combined tag set.
|
||||
func (tr *TagResolver) ResolveComponentTags(componentIDs []string) []string {
|
||||
seen := make(map[string]bool)
|
||||
var tags []string
|
||||
for _, id := range componentIDs {
|
||||
comp, ok := tr.componentIndex[id]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, tag := range comp.Tags {
|
||||
if !seen[tag] {
|
||||
seen[tag] = true
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// ResolveEnergyTags resolves energy source IDs to their combined tag set.
|
||||
func (tr *TagResolver) ResolveEnergyTags(energyIDs []string) []string {
|
||||
seen := make(map[string]bool)
|
||||
var tags []string
|
||||
for _, id := range energyIDs {
|
||||
src, ok := tr.energyIndex[id]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, tag := range src.Tags {
|
||||
if !seen[tag] {
|
||||
seen[tag] = true
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// ResolveTags combines component, energy, and custom tags into a unified set.
|
||||
func (tr *TagResolver) ResolveTags(componentIDs, energyIDs, customTags []string) []string {
|
||||
seen := make(map[string]bool)
|
||||
var all []string
|
||||
|
||||
add := func(tags []string) {
|
||||
for _, t := range tags {
|
||||
if !seen[t] {
|
||||
seen[t] = true
|
||||
all = append(all, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add(tr.ResolveComponentTags(componentIDs))
|
||||
add(tr.ResolveEnergyTags(energyIDs))
|
||||
add(customTags)
|
||||
return all
|
||||
}
|
||||
|
||||
// FindHazardsByTags returns hazard library entries that have any matching tag.
|
||||
func (tr *TagResolver) FindHazardsByTags(tags []string) []HazardLibraryEntry {
|
||||
tagSet := toSet(tags)
|
||||
var matched []HazardLibraryEntry
|
||||
for _, h := range GetBuiltinHazardLibrary() {
|
||||
if h.Tags == nil {
|
||||
continue
|
||||
}
|
||||
for _, t := range h.Tags {
|
||||
if tagSet[t] {
|
||||
matched = append(matched, h)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
// FindMeasuresByTags returns protective measure entries that have any matching tag.
|
||||
func (tr *TagResolver) FindMeasuresByTags(tags []string) []ProtectiveMeasureEntry {
|
||||
tagSet := toSet(tags)
|
||||
var matched []ProtectiveMeasureEntry
|
||||
for _, m := range GetProtectiveMeasureLibrary() {
|
||||
if m.Tags == nil {
|
||||
continue
|
||||
}
|
||||
for _, t := range m.Tags {
|
||||
if tagSet[t] {
|
||||
matched = append(matched, m)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
// FindEvidenceByTags returns evidence type entries that have any matching tag.
|
||||
func (tr *TagResolver) FindEvidenceByTags(tags []string) []EvidenceTypeInfo {
|
||||
tagSet := toSet(tags)
|
||||
var matched []EvidenceTypeInfo
|
||||
for _, e := range GetEvidenceTypeLibrary() {
|
||||
for _, t := range e.Tags {
|
||||
if tagSet[t] {
|
||||
matched = append(matched, e)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
// toSet converts a string slice to a map for O(1) lookup.
|
||||
func toSet(s []string) map[string]bool {
|
||||
m := make(map[string]bool, len(s))
|
||||
for _, v := range s {
|
||||
m[v] = true
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// GetEvidenceTypeLibrary returns built-in evidence types with tags for tag resolution.
|
||||
func GetEvidenceTypeLibrary() []EvidenceTypeInfo {
|
||||
return []EvidenceTypeInfo{
|
||||
{ID: "E01", Category: "design", LabelDE: "Risikobeurteilung", LabelEN: "Risk Assessment Document", Tags: []string{"design_evidence"}, Sort: 1},
|
||||
{ID: "E02", Category: "design", LabelDE: "FMEA-Dokument", LabelEN: "FMEA Document", Tags: []string{"design_evidence", "analysis_evidence"}, Sort: 2},
|
||||
{ID: "E03", Category: "design", LabelDE: "Sicherheitskonzept", LabelEN: "Safety Concept", Tags: []string{"design_evidence"}, Sort: 3},
|
||||
{ID: "E04", Category: "design", LabelDE: "Schaltplan", LabelEN: "Circuit Diagram", Tags: []string{"design_evidence"}, Sort: 4},
|
||||
{ID: "E05", Category: "design", LabelDE: "Hydraulikschaltplan", LabelEN: "Hydraulic Diagram", Tags: []string{"design_evidence"}, Sort: 5},
|
||||
{ID: "E06", Category: "design", LabelDE: "Pneumatikschaltplan", LabelEN: "Pneumatic Diagram", Tags: []string{"design_evidence"}, Sort: 6},
|
||||
{ID: "E07", Category: "design", LabelDE: "SIL/PL-Berechnung", LabelEN: "SIL/PL Calculation", Tags: []string{"design_evidence", "analysis_evidence"}, Sort: 7},
|
||||
{ID: "E08", Category: "test", LabelDE: "Funktionspruefung Schutzeinrichtung", LabelEN: "Guard Function Test", Tags: []string{"test_evidence", "guard_measure"}, Sort: 8},
|
||||
{ID: "E09", Category: "test", LabelDE: "Not-Halt-Test", LabelEN: "Emergency Stop Test", Tags: []string{"test_evidence"}, Sort: 9},
|
||||
{ID: "E10", Category: "test", LabelDE: "Elektrische Sicherheitspruefung", LabelEN: "Electrical Safety Test", Tags: []string{"test_evidence"}, Sort: 10},
|
||||
{ID: "E11", Category: "test", LabelDE: "Druckpruefung", LabelEN: "Pressure Test", Tags: []string{"test_evidence"}, Sort: 11},
|
||||
{ID: "E12", Category: "test", LabelDE: "Laermmessung", LabelEN: "Noise Measurement", Tags: []string{"test_evidence"}, Sort: 12},
|
||||
{ID: "E13", Category: "test", LabelDE: "Vibrationsmessung", LabelEN: "Vibration Measurement", Tags: []string{"test_evidence"}, Sort: 13},
|
||||
{ID: "E14", Category: "test", LabelDE: "Software-Testprotokoll", LabelEN: "Software Test Protocol", Tags: []string{"test_evidence", "software_safety_measure"}, Sort: 14},
|
||||
{ID: "E15", Category: "test", LabelDE: "KI-Validierungsbericht", LabelEN: "AI Validation Report", Tags: []string{"test_evidence", "ai_risk"}, Sort: 15},
|
||||
{ID: "E16", Category: "cyber", LabelDE: "Penetrationstest-Bericht", LabelEN: "Penetration Test Report", Tags: []string{"cyber_evidence", "test_evidence"}, Sort: 16},
|
||||
{ID: "E17", Category: "cyber", LabelDE: "Netzwerk-Segmentierungsnachweis", LabelEN: "Network Segmentation Evidence", Tags: []string{"cyber_evidence"}, Sort: 17},
|
||||
{ID: "E18", Category: "cyber", LabelDE: "SBOM (Software Bill of Materials)", LabelEN: "SBOM", Tags: []string{"cyber_evidence"}, Sort: 18},
|
||||
{ID: "E19", Category: "cyber", LabelDE: "Patch-Management-Nachweis", LabelEN: "Patch Management Evidence", Tags: []string{"cyber_evidence"}, Sort: 19},
|
||||
{ID: "E20", Category: "inspection", LabelDE: "Abnahmeprotokoll", LabelEN: "Acceptance Protocol", Tags: []string{"inspection_evidence"}, Sort: 20},
|
||||
{ID: "E21", Category: "inspection", LabelDE: "Wartungscheckliste (ausgefuellt)", LabelEN: "Maintenance Checklist (completed)", Tags: []string{"inspection_evidence", "operational_evidence"}, Sort: 21},
|
||||
{ID: "E22", Category: "inspection", LabelDE: "CE-Konformitaetserklaerung", LabelEN: "CE Declaration of Conformity", Tags: []string{"certification_evidence"}, Sort: 22},
|
||||
{ID: "E23", Category: "inspection", LabelDE: "Typenpruefzertifikat", LabelEN: "Type Examination Certificate", Tags: []string{"certification_evidence"}, Sort: 23},
|
||||
{ID: "E24", Category: "training", LabelDE: "Schulungsnachweis Bediener", LabelEN: "Operator Training Record", Tags: []string{"training_evidence"}, Sort: 24},
|
||||
{ID: "E25", Category: "training", LabelDE: "Sicherheitsunterweisung (Protokoll)", LabelEN: "Safety Briefing Record", Tags: []string{"training_evidence"}, Sort: 25},
|
||||
}
|
||||
}
|
||||
92
ai-compliance-sdk/internal/iace/tag_resolver_test.go
Normal file
92
ai-compliance-sdk/internal/iace/tag_resolver_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package iace
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTagResolver_ResolveComponentTags_Roboterarm(t *testing.T) {
|
||||
tr := NewTagResolver()
|
||||
tags := tr.ResolveComponentTags([]string{"C001"}) // Roboterarm
|
||||
if len(tags) == 0 {
|
||||
t.Fatal("expected tags for C001 (Roboterarm), got none")
|
||||
}
|
||||
tagSet := toSet(tags)
|
||||
if !tagSet["moving_part"] {
|
||||
t.Error("expected 'moving_part' tag for Roboterarm")
|
||||
}
|
||||
if !tagSet["rotating_part"] {
|
||||
t.Error("expected 'rotating_part' tag for Roboterarm")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagResolver_ResolveComponentTags_Schaltschrank(t *testing.T) {
|
||||
tr := NewTagResolver()
|
||||
tags := tr.ResolveComponentTags([]string{"C061"}) // Schaltschrank
|
||||
tagSet := toSet(tags)
|
||||
if !tagSet["high_voltage"] {
|
||||
t.Error("expected 'high_voltage' tag for Schaltschrank")
|
||||
}
|
||||
if !tagSet["electrical_part"] {
|
||||
t.Error("expected 'electrical_part' tag for Schaltschrank")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagResolver_ResolveEnergyTags(t *testing.T) {
|
||||
tr := NewTagResolver()
|
||||
tags := tr.ResolveEnergyTags([]string{"EN01", "EN04"})
|
||||
tagSet := toSet(tags)
|
||||
if !tagSet["kinetic"] {
|
||||
t.Error("expected 'kinetic' tag for EN01")
|
||||
}
|
||||
if !tagSet["electrical_energy"] {
|
||||
t.Error("expected 'electrical_energy' tag for EN04")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagResolver_ResolveTags_Merged(t *testing.T) {
|
||||
tr := NewTagResolver()
|
||||
tags := tr.ResolveTags(
|
||||
[]string{"C001"}, // Roboterarm → moving_part, rotating_part, high_force
|
||||
[]string{"EN01"}, // Kinetische Energie → kinetic, translational
|
||||
[]string{"custom_tag"},
|
||||
)
|
||||
tagSet := toSet(tags)
|
||||
if !tagSet["moving_part"] {
|
||||
t.Error("missing component tag 'moving_part'")
|
||||
}
|
||||
if !tagSet["kinetic"] {
|
||||
t.Error("missing energy tag 'kinetic'")
|
||||
}
|
||||
if !tagSet["custom_tag"] {
|
||||
t.Error("missing custom tag")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagResolver_ResolveTags_NoDuplicates(t *testing.T) {
|
||||
tr := NewTagResolver()
|
||||
// C001 and C003 both have "moving_part"
|
||||
tags := tr.ResolveTags([]string{"C001", "C003"}, nil, nil)
|
||||
count := 0
|
||||
for _, t := range tags {
|
||||
if t == "moving_part" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count != 1 {
|
||||
t.Errorf("expected 'moving_part' exactly once, got %d", count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagResolver_ResolveComponentTags_UnknownID(t *testing.T) {
|
||||
tr := NewTagResolver()
|
||||
tags := tr.ResolveComponentTags([]string{"UNKNOWN_ID"})
|
||||
if len(tags) != 0 {
|
||||
t.Errorf("expected no tags for unknown ID, got %v", tags)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagResolver_ResolveComponentTags_Empty(t *testing.T) {
|
||||
tr := NewTagResolver()
|
||||
tags := tr.ResolveComponentTags(nil)
|
||||
if len(tags) != 0 {
|
||||
t.Errorf("expected no tags for nil input, got %v", tags)
|
||||
}
|
||||
}
|
||||
118
ai-compliance-sdk/internal/iace/tag_taxonomy.go
Normal file
118
ai-compliance-sdk/internal/iace/tag_taxonomy.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package iace
|
||||
|
||||
// TagEntry represents a tag in the taxonomy with its domain and description.
|
||||
type TagEntry struct {
|
||||
ID string `json:"id"`
|
||||
Domain string `json:"domain"`
|
||||
DescriptionDE string `json:"description_de"`
|
||||
DescriptionEN string `json:"description_en"`
|
||||
}
|
||||
|
||||
// GetTagTaxonomy returns the complete tag taxonomy (~85 tags in 5 domains).
|
||||
func GetTagTaxonomy() []TagEntry {
|
||||
return []TagEntry{
|
||||
// ── Domain: component (~30 tags) ────────────────────────────────────
|
||||
{ID: "moving_part", Domain: "component", DescriptionDE: "Bewegtes Maschinenteil", DescriptionEN: "Moving machine part"},
|
||||
{ID: "rotating_part", Domain: "component", DescriptionDE: "Rotierendes Bauteil", DescriptionEN: "Rotating component"},
|
||||
{ID: "cutting_part", Domain: "component", DescriptionDE: "Schneidendes Werkzeug", DescriptionEN: "Cutting tool"},
|
||||
{ID: "clamping_part", Domain: "component", DescriptionDE: "Spannendes/Greifendes Bauteil", DescriptionEN: "Clamping/gripping part"},
|
||||
{ID: "structural_part", Domain: "component", DescriptionDE: "Tragendes/Strukturelles Bauteil", DescriptionEN: "Structural/supporting part"},
|
||||
{ID: "hydraulic_part", Domain: "component", DescriptionDE: "Hydraulikkomponente", DescriptionEN: "Hydraulic component"},
|
||||
{ID: "pneumatic_part", Domain: "component", DescriptionDE: "Pneumatikkomponente", DescriptionEN: "Pneumatic component"},
|
||||
{ID: "electrical_part", Domain: "component", DescriptionDE: "Elektrische Komponente", DescriptionEN: "Electrical component"},
|
||||
{ID: "sensor_part", Domain: "component", DescriptionDE: "Sensorisches Bauteil", DescriptionEN: "Sensor component"},
|
||||
{ID: "actuator_part", Domain: "component", DescriptionDE: "Aktor/Stellglied", DescriptionEN: "Actuator part"},
|
||||
{ID: "safety_device", Domain: "component", DescriptionDE: "Sicherheitseinrichtung", DescriptionEN: "Safety device"},
|
||||
{ID: "security_device", Domain: "component", DescriptionDE: "IT-Sicherheitsgeraet", DescriptionEN: "IT security device"},
|
||||
{ID: "guard", Domain: "component", DescriptionDE: "Schutzeinrichtung (trennend)", DescriptionEN: "Guard (separating)"},
|
||||
{ID: "interlocked", Domain: "component", DescriptionDE: "Verriegelt/Ueberwacht", DescriptionEN: "Interlocked/monitored"},
|
||||
{ID: "emergency_stop", Domain: "component", DescriptionDE: "Not-Halt-Funktion", DescriptionEN: "Emergency stop function"},
|
||||
{ID: "high_voltage", Domain: "component", DescriptionDE: "Hochspannung (>50V AC / >120V DC)", DescriptionEN: "High voltage (>50V AC / >120V DC)"},
|
||||
{ID: "high_force", Domain: "component", DescriptionDE: "Hohe Kraft/Drehmoment", DescriptionEN: "High force/torque"},
|
||||
{ID: "high_speed", Domain: "component", DescriptionDE: "Hohe Geschwindigkeit/Drehzahl", DescriptionEN: "High speed/rpm"},
|
||||
{ID: "high_pressure", Domain: "component", DescriptionDE: "Hoher Druck", DescriptionEN: "High pressure"},
|
||||
{ID: "high_temperature", Domain: "component", DescriptionDE: "Hohe Temperatur", DescriptionEN: "High temperature"},
|
||||
{ID: "has_software", Domain: "component", DescriptionDE: "Enthaelt Software", DescriptionEN: "Contains software"},
|
||||
{ID: "has_ai", Domain: "component", DescriptionDE: "Enthaelt KI-Modell", DescriptionEN: "Contains AI model"},
|
||||
{ID: "programmable", Domain: "component", DescriptionDE: "Programmierbar", DescriptionEN: "Programmable"},
|
||||
{ID: "networked", Domain: "component", DescriptionDE: "Vernetzt/Netzwerkfaehig", DescriptionEN: "Networked"},
|
||||
{ID: "wireless", Domain: "component", DescriptionDE: "Drahtlose Kommunikation", DescriptionEN: "Wireless communication"},
|
||||
{ID: "it_component", Domain: "component", DescriptionDE: "IT-Infrastruktur-Komponente", DescriptionEN: "IT infrastructure component"},
|
||||
{ID: "user_interface", Domain: "component", DescriptionDE: "Benutzerschnittstelle", DescriptionEN: "User interface"},
|
||||
{ID: "noise_source", Domain: "component", DescriptionDE: "Laermquelle", DescriptionEN: "Noise source"},
|
||||
{ID: "vibration_source", Domain: "component", DescriptionDE: "Vibrationsquelle", DescriptionEN: "Vibration source"},
|
||||
{ID: "radiation_risk", Domain: "component", DescriptionDE: "Strahlungsquelle", DescriptionEN: "Radiation source"},
|
||||
|
||||
// ── Domain: energy (~15 tags) ───────────────────────────────────────
|
||||
{ID: "kinetic", Domain: "energy", DescriptionDE: "Kinetische Energie", DescriptionEN: "Kinetic energy"},
|
||||
{ID: "translational", Domain: "energy", DescriptionDE: "Translatorische Bewegung", DescriptionEN: "Translational motion"},
|
||||
{ID: "rotational", Domain: "energy", DescriptionDE: "Rotatorische Bewegung", DescriptionEN: "Rotational motion"},
|
||||
{ID: "potential", Domain: "energy", DescriptionDE: "Potentielle Energie", DescriptionEN: "Potential energy"},
|
||||
{ID: "gravitational", Domain: "energy", DescriptionDE: "Schwerkraftbedingt", DescriptionEN: "Gravitational"},
|
||||
{ID: "electrical_energy", Domain: "energy", DescriptionDE: "Elektrische Energie", DescriptionEN: "Electrical energy"},
|
||||
{ID: "hydraulic_pressure", Domain: "energy", DescriptionDE: "Hydraulischer Druck", DescriptionEN: "Hydraulic pressure"},
|
||||
{ID: "pneumatic_pressure", Domain: "energy", DescriptionDE: "Pneumatischer Druck", DescriptionEN: "Pneumatic pressure"},
|
||||
{ID: "thermal", Domain: "energy", DescriptionDE: "Thermische Energie", DescriptionEN: "Thermal energy"},
|
||||
{ID: "stored_energy", Domain: "energy", DescriptionDE: "Gespeicherte Energie", DescriptionEN: "Stored energy"},
|
||||
{ID: "radiation", Domain: "energy", DescriptionDE: "Strahlung", DescriptionEN: "Radiation"},
|
||||
{ID: "electromagnetic", Domain: "energy", DescriptionDE: "Elektromagnetische Strahlung", DescriptionEN: "Electromagnetic radiation"},
|
||||
{ID: "acoustic", Domain: "energy", DescriptionDE: "Schallenergie", DescriptionEN: "Acoustic energy"},
|
||||
{ID: "vibration", Domain: "energy", DescriptionDE: "Vibration", DescriptionEN: "Vibration"},
|
||||
{ID: "chemical", Domain: "energy", DescriptionDE: "Chemische Energie", DescriptionEN: "Chemical energy"},
|
||||
{ID: "magnetic", Domain: "energy", DescriptionDE: "Magnetische Energie", DescriptionEN: "Magnetic energy"},
|
||||
{ID: "cyber", Domain: "energy", DescriptionDE: "Cyber/Daten-Energie", DescriptionEN: "Cyber/data energy"},
|
||||
{ID: "ai_model", Domain: "energy", DescriptionDE: "KI-Modell", DescriptionEN: "AI model"},
|
||||
{ID: "ergonomic", Domain: "energy", DescriptionDE: "Ergonomische Belastung", DescriptionEN: "Ergonomic load"},
|
||||
|
||||
// ── Domain: hazard (~20 tags) ───────────────────────────────────────
|
||||
{ID: "crush_risk", Domain: "hazard", DescriptionDE: "Quetschgefahr", DescriptionEN: "Crush risk"},
|
||||
{ID: "shear_risk", Domain: "hazard", DescriptionDE: "Schergefahr", DescriptionEN: "Shear risk"},
|
||||
{ID: "cut_risk", Domain: "hazard", DescriptionDE: "Schnittgefahr", DescriptionEN: "Cut risk"},
|
||||
{ID: "entanglement_risk", Domain: "hazard", DescriptionDE: "Einzugsgefahr", DescriptionEN: "Entanglement risk"},
|
||||
{ID: "impact_risk", Domain: "hazard", DescriptionDE: "Stossgefahr", DescriptionEN: "Impact risk"},
|
||||
{ID: "gravity_risk", Domain: "hazard", DescriptionDE: "Absturzgefahr / Herabfallen", DescriptionEN: "Fall/drop risk"},
|
||||
{ID: "pinch_point", Domain: "hazard", DescriptionDE: "Klemmstelle", DescriptionEN: "Pinch point"},
|
||||
{ID: "crush_point", Domain: "hazard", DescriptionDE: "Quetschstelle", DescriptionEN: "Crush point"},
|
||||
{ID: "electric_shock_risk", Domain: "hazard", DescriptionDE: "Stromschlaggefahr", DescriptionEN: "Electric shock risk"},
|
||||
{ID: "burn_risk", Domain: "hazard", DescriptionDE: "Verbrennungsgefahr", DescriptionEN: "Burn risk"},
|
||||
{ID: "pressure_risk", Domain: "hazard", DescriptionDE: "Druckgefahr", DescriptionEN: "Pressure risk"},
|
||||
{ID: "noise_risk", Domain: "hazard", DescriptionDE: "Laermgefahr", DescriptionEN: "Noise risk"},
|
||||
{ID: "vibration_risk", Domain: "hazard", DescriptionDE: "Vibrationsgefahr", DescriptionEN: "Vibration risk"},
|
||||
{ID: "ergonomic_risk", Domain: "hazard", DescriptionDE: "Ergonomie-Risiko", DescriptionEN: "Ergonomic risk"},
|
||||
{ID: "chemical_risk", Domain: "hazard", DescriptionDE: "Gefahrstoffrisiko", DescriptionEN: "Chemical risk"},
|
||||
{ID: "cyber_risk", Domain: "hazard", DescriptionDE: "Cyber-Sicherheitsrisiko", DescriptionEN: "Cyber security risk"},
|
||||
{ID: "ai_risk", Domain: "hazard", DescriptionDE: "KI-spezifisches Risiko", DescriptionEN: "AI-specific risk"},
|
||||
{ID: "software_risk", Domain: "hazard", DescriptionDE: "Software-Fehlerrisiko", DescriptionEN: "Software fault risk"},
|
||||
{ID: "communication_risk", Domain: "hazard", DescriptionDE: "Kommunikationsausfall-Risiko", DescriptionEN: "Communication failure risk"},
|
||||
{ID: "emc_risk", Domain: "hazard", DescriptionDE: "EMV-Stoerungsrisiko", DescriptionEN: "EMC interference risk"},
|
||||
|
||||
// ── 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"},
|
||||
{ID: "force_limit_measure", Domain: "measure", DescriptionDE: "Kraftbegrenzungsmassnahme", DescriptionEN: "Force limiting measure"},
|
||||
{ID: "safety_function_measure", Domain: "measure", DescriptionDE: "Sicherheitsfunktion (STO/SLS/SOS)", DescriptionEN: "Safety function (STO/SLS/SOS)"},
|
||||
{ID: "software_safety_measure", Domain: "measure", DescriptionDE: "Software-Sicherheitsmassnahme", DescriptionEN: "Software safety measure"},
|
||||
{ID: "cyber_security_measure", Domain: "measure", DescriptionDE: "Cyber-Sicherheitsmassnahme", DescriptionEN: "Cyber security measure"},
|
||||
{ID: "pressure_relief_measure", Domain: "measure", DescriptionDE: "Druckentlastungsmassnahme", DescriptionEN: "Pressure relief measure"},
|
||||
{ID: "thermal_protection_measure", Domain: "measure", DescriptionDE: "Thermische Schutzmassnahme", DescriptionEN: "Thermal protection measure"},
|
||||
{ID: "ppe_measure", Domain: "measure", DescriptionDE: "Persoenliche Schutzausruestung", DescriptionEN: "Personal protective equipment"},
|
||||
{ID: "training_measure", Domain: "measure", DescriptionDE: "Schulungsmassnahme", DescriptionEN: "Training measure"},
|
||||
|
||||
// ── Domain: evidence (~10 tags) ─────────────────────────────────────
|
||||
{ID: "design_evidence", Domain: "evidence", DescriptionDE: "Konstruktionsnachweis", DescriptionEN: "Design evidence"},
|
||||
{ID: "test_evidence", Domain: "evidence", DescriptionDE: "Testnachweis", DescriptionEN: "Test evidence"},
|
||||
{ID: "analysis_evidence", Domain: "evidence", DescriptionDE: "Analysenachweis", DescriptionEN: "Analysis evidence"},
|
||||
{ID: "inspection_evidence", Domain: "evidence", DescriptionDE: "Inspektionsnachweis", DescriptionEN: "Inspection evidence"},
|
||||
{ID: "cyber_evidence", Domain: "evidence", DescriptionDE: "Cyber-Security-Nachweis", DescriptionEN: "Cyber security evidence"},
|
||||
{ID: "simulation_evidence", Domain: "evidence", DescriptionDE: "Simulationsnachweis", DescriptionEN: "Simulation evidence"},
|
||||
{ID: "certification_evidence", Domain: "evidence", DescriptionDE: "Zertifizierungsnachweis", DescriptionEN: "Certification evidence"},
|
||||
{ID: "training_evidence", Domain: "evidence", DescriptionDE: "Schulungsnachweis", DescriptionEN: "Training evidence"},
|
||||
{ID: "operational_evidence", Domain: "evidence", DescriptionDE: "Betriebsnachweis", DescriptionEN: "Operational evidence"},
|
||||
{ID: "audit_evidence", Domain: "evidence", DescriptionDE: "Auditnachweis", DescriptionEN: "Audit evidence"},
|
||||
}
|
||||
}
|
||||
|
||||
// ValidTagDomains returns the list of valid tag domains.
|
||||
func ValidTagDomains() []string {
|
||||
return []string{"component", "energy", "hazard", "measure", "evidence"}
|
||||
}
|
||||
Reference in New Issue
Block a user