Files
breakpilot-compliance/ai-compliance-sdk/internal/iace/architecture.go
T
Benjamin Admin 755ea44343 feat(iace): refresh architecture tab + data-flow diagram + E1 ingest script
- architecture.go: DataSources now reflect the real ingested set (ESAW 2023,
  BLS CFOI, OSHA OTM, PRISM, cobot CC-BY, HSE) with their RAG collections;
  risk stage cites BLS + the searchable RAG layer; matrix stage now mentions
  the distance-benchmark dimension.
- Architektur & Datenfluss tab: new DataFlowDiagram — 4 lanes (input →
  knowledge/RAG-evidence → deterministic engine → outputs) with live counts.
- scripts/ingest_iace_kb.sh: idempotent E1 ingest — creates the 2 collections
  and uploads the 6 datasources docs against a configurable RAG_URL (for prod
  Qdrant), with retry.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 09:18:03 +02:00

171 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package iace
// Data-driven self-description of the IACE engine for the "Architektur &
// Datenfluss" explainer. Counts are LIVE (derived from the running engine) so
// the diagram can never drift from reality; the stage/source prose is curated.
// Purpose: let an auditor see WHERE each datum comes from and HOW a risk
// assessment is reached — every gate, library and data source, in order.
// ArchStage is one step of the deterministic pipeline.
type ArchStage struct {
ID string `json:"id"`
Title string `json:"title"`
Summary string `json:"summary"`
Input string `json:"input"`
Logic string `json:"logic"`
DataSource string `json:"data_source"` // code/library it draws from
Example string `json:"example"`
}
// ArchLibrary is one knowledge base with a LIVE entry count.
type ArchLibrary struct {
Name string `json:"name"`
Count int `json:"count"`
SourceFile string `json:"source_file"`
Description string `json:"description"`
}
// ArchDataSource is an external statistic/standard with its license + status.
type ArchDataSource struct {
Name string `json:"name"`
License string `json:"license"`
Usage string `json:"usage"`
Status string `json:"status"` // "verwendet" | "ausgeschlossen"
}
// Architecture is the full self-description returned by GET /iace/architecture.
type Architecture struct {
Stages []ArchStage `json:"stages"`
Libraries []ArchLibrary `json:"libraries"`
DataSources []ArchDataSource `json:"data_sources"`
NormMatching []string `json:"norm_matching"`
Evidence []RiskEvidence `json:"evidence"`
}
// distinctDomainGates counts the distinct dom_* capability tags the engine gates on.
func distinctDomainGates() int {
seen := map[string]bool{}
for _, tag := range domainGateTerms {
seen[tag] = true
}
return len(seen)
}
// BuildArchitecture assembles the engine self-description with live counts.
func BuildArchitecture() Architecture {
return Architecture{
Stages: []ArchStage{
{
ID: "grenzen", Title: "1 · Grenzen-Formular",
Summary: "Maschinenbeschreibung nach EN ISO 12100 (Verwendungs-, räumliche, zeitliche Grenzen).",
Input: "17 Felder: Beschreibung, Verwendung, Fehlanwendung, Schnittstellen (elektrisch/mechanisch/pneumatisch-hydraulisch), Umgebung, Personen …",
Logic: "Alle Felder werden zu einer Narrative zusammengeführt (kein Whitelist — jedes Feld ist eine potenzielle Gefährdungsquelle).",
DataSource: "project.metadata.limits_form",
Example: "„Hubantrieb über Kette … 230 V … keine pneumatischen Schnittstellen.“",
},
{
ID: "parse", Title: "2 · ParseNarrative",
Summary: "Deterministische Extraktion von Komponenten, Energiequellen, Domänen-Tags und Negationen.",
Input: "Narrative-Text + Maschinentyp",
Logic: "Keyword-Wörterbuch (Substring, umlaut-normalisiert) → Komponenten + Energie + dom_*-Tags. Negation („keine Pneumatik“) ⇒ Komponente als verneint markiert, liefert KEINE Tags.",
DataSource: "keyword_dictionary.go",
Example: "„Kette“→Komponente, „230 V“→electrical_energy, „Presse“→dom_press.",
},
{
ID: "match", Title: "3 · Pattern-Engine (Gates)",
Summary: "Jedes Gefährdungsmuster wird gegen die Maschine geprüft — harte UND-Gates.",
Input: "Komponenten-Tags, Energie-Tags, Lebensphasen, Maschinentyp, dom_*-Tags",
Logic: "patternMatches: MachineType ∧ Required-Component-Tags ∧ Required-Energy-Tags ∧ Lifecycle ∧ Operational-States. Capability-Domain-Gates (dom_*) verhindern Cross-Domänen-Leaks (z. B. Schwimmbad-Muster feuert nicht für eine Presse). Default-open, wenn ein Gate-Input leer ist.",
DataSource: "pattern_engine.go + pattern_domain_gates.go + hazard_patterns_*.go",
Example: "Presse-Muster feuert nur, wenn machine_type∈Presse-Familie UND high_force-Tag vorhanden.",
},
{
ID: "relevance", Title: "4 · Relevanz-Backstop",
Summary: "Generischer Filter gegen Rest-Leaks ungegateter Muster.",
Input: "Gefeuertes Muster + Narrative + Komponenten-Namen",
Logic: "IsPatternRelevant: Token-Grenzen + Stoppwort-Liste — ein Muster wird verworfen, wenn sein spezifischer Anker nicht in der Narrative vorkommt.",
DataSource: "pattern_relevance.go",
Example: "Verwirft „Bandsäge“-Hazard, wenn die Narrative keine Säge nennt.",
},
{
ID: "caps", Title: "5 · Kategorie-Caps",
Summary: "Begrenzung der Gefährdungen je Kategorie (skaliert mit Komponentenzahl).",
Input: "Gefeuerte Muster je Gefährdungskategorie",
Logic: "categoryHazardCap: pro Kategorie ein Maximum (verhindert Über-Flutung); Dedupe über Kategorie × Zone.",
DataSource: "iace_handler_init.go",
Example: "max. N mechanical_hazard-Gefährdungen je Projekt.",
},
{
ID: "hazards", Title: "6 · Gefährdungen",
Summary: "Die erzeugten Gefährdungen (Szenario, Auslöser, Schaden, Zone, betroffene Person).",
Input: "Überlebende Muster + zugeordnete Komponente",
Logic: "Pro Muster: Szenario/Trigger/Harm/Zone aus dem Muster; Komponentenzuordnung tag-basiert (pickComponentForPattern).",
DataSource: "iace_hazards (DB)",
Example: "„Quetschen im Werkzeugeinbauraum zwischen Ober- und Unterwerkzeug.“",
},
{
ID: "measures", Title: "7 · Maßnahmen",
Summary: "Schutzmaßnahmen je Gefährdung — kategorie-gefiltert, KEINE generischen Defaults.",
Input: "Gefährdung + musterspezifische Suggested-Measure-IDs",
Logic: "Nur Maßnahmen, deren Kategorie zur Gefährdung passt (isCategoryCompatible). Ohne passende Maßnahme ⇒ 0 Maßnahmen + Coverage-Gap (ehrlich, statt Unsinn).",
DataSource: "measures_library*.go",
Example: "Sharp-edge-Gefährdung ⇒ keine „Rotation vermeiden“-Maßnahme.",
},
{
ID: "risk", Title: "8 · Risiko (S/F/W/P + Konfidenz)",
Summary: "Konfidenz-bewusste Risikoschätzung je Gefährdung — als Bereich, nicht Punktwert.",
Input: "Gefährdungskategorie + Szenario (Kontaktart) + Lebensphasen",
Logic: "EstimateSeverity/Frequency/ProbabilityW/AvoidabilityP → R = S×(F+W+P), Band + Bereich (±1 je validierter Genauigkeit) + Konfidenz (Verletzungsmechanismus eindeutig?). W verankert am ESAW-2023-Kontaktmodus-Ranking, Schwere zusätzlich an BLS-CFOI; eigenes Modell, KEINE Norm-Tabelle. Belege durchsuchbar im RAG (bp_iace_accident_stats).",
DataSource: "risk_estimation.go + risk_data_sources.go (ESAW hsw_ph3_08 2023 + BLS CFOI) + RAG bp_iace_accident_stats",
Example: "Elektrischer Schlag: R≈32 (Bereich 2145, mittelkritisch), Konfidenz hoch.",
},
{
ID: "norms", Title: "9 · Normen (A/B/C + Familien-Matching)",
Summary: "Passende Normen je Maschinentyp und Gefährdung; DIN/ISO/OSHA-Vokabular versöhnt.",
Input: "Maschinentyp + Gefährdungskategorien + Tags",
Logic: "SuggestNorms: C-Normen exakt per Maschinentyp-FAMILIE (canonicalMachineType: welding_machine→welding); B-Normen per Gefährdungskategorie/Tags; A-Normen gelten immer. Normen werden nur referenziert, Tabellen nie reproduziert.",
DataSource: "norms_engine.go + machine_type_families.go + norms_library*.go",
Example: "Schweißanlage ⇒ EN 60974-x (Lichtbogenschweißen), obwohl Norm auf „welding_machine“ getaggt.",
},
{
ID: "matrix", Title: "10 · Risiko-Matrix / GT-Benchmark",
Summary: "Projektweite Risiko-Matrix (Schwere × Wahrscheinlichkeit), Abgleich gegen Experten-GT inkl. Abstands-/Geschwindigkeits-Maße.",
Input: "Alle Gefährdungen + (optional) GT-Projekt",
Logic: "BuildRiskMatrix aggregiert je Zelle; Benchmark vergleicht Tool-S/F/W/P + Fine-Kinney gegen Fachmann-GT (within±1, Rang-Konkordanz) UND die mm-/mm-s-Maße (CompareDistances: matched / Lücken / Extras + Agreement-%).",
DataSource: "risk_matrix.go + risk_benchmark.go + distance_benchmark.go",
Example: "Kistenhub: Gefährdungs-Coverage hoch; Abstands-Maße nach Lückenfüllung 4/4 (100 %).",
},
},
Libraries: []ArchLibrary{
{Name: "Hazard-Pattern-Bibliothek", Count: len(AllPatterns()), SourceFile: "hazard_patterns_*.go", Description: "Gefährdungsmuster mit Gates (MachineType/Tags/Energy/Lifecycle) + Szenario/Trigger/Harm/Zone."},
{Name: "Maßnahmen-Bibliothek", Count: len(GetProtectiveMeasureLibrary()), SourceFile: "measures_library*.go", Description: "Schutzmaßnahmen mit Reduktionstyp + Norm-Referenzen, kategorie-gefiltert."},
{Name: "Normen-Bibliothek (A/B/C)", Count: len(collectAllNorms()), SourceFile: "norms_library*.go", Description: "A-/B-/C-Normen mit Maschinentypen, Gefährdungskategorien und Tags."},
{Name: "Komponenten-Bibliothek", Count: len(GetComponentLibrary()), SourceFile: "component_library.go", Description: "Bauteiltypen mit Capability-Tags für das Pattern-Gating."},
{Name: "Energiequellen", Count: len(GetEnergySources()), SourceFile: "component_library.go", Description: "Energiearten (elektrisch/pneumatisch/hydraulisch …) für Energie-Gates."},
{Name: "Maschinentyp-Vokabular", Count: len(MachineTypeVocabulary()), SourceFile: "machine_types.go", Description: "Kanonische Dropdown-Maschinentypen, auf die Patterns gaten."},
{Name: "Domänen-Capability-Gates", Count: distinctDomainGates(), SourceFile: "pattern_domain_gates.go", Description: "dom_*-Tags, die domänenspezifische Muster auf ihre echte Maschine begrenzen (Leak-Schutz)."},
{Name: "Kontaktmodus-Tiers", Count: len(contactModeTable), SourceFile: "risk_estimation.go", Description: "Verletzungsmechanismen mit W/P/S-Tiers (ESAW-verankert, GT-kalibriert)."},
{Name: "Kontaktmodus-Evidenz", Count: len(contactModeEvidence), SourceFile: "risk_data_sources.go", Description: "Belegte öffentliche Statistik-Quoten (ESAW) als Zitat-/Audit-Schicht."},
{Name: "OSHA-Mindestabstände", Count: len(GetOSHAMinimumDistances()), SourceFile: "minimum_distances.go", Description: "OSHA 29 CFR 1910 Sicherheitsabstände (Public Domain) + Maßnahmen-Verknüpfung; EU-Normen nur referenziert."},
},
DataSources: []ArchDataSource{
{Name: "Eurostat ESAW (Kontaktmodus, hsw_ph3_08, 2023)", License: "CC BY 4.0", Usage: "Anker für W-Tiers + zitierbare Quoten → RAG bp_iace_accident_stats", Status: "verwendet"},
{Name: "US BLS CFOI (tödliche Arbeitsunfälle 202324)", License: "Public Domain", Usage: "US-Schwere-Anker (Contact = führend in Manufacturing) → RAG bp_iace_accident_stats", Status: "verwendet"},
{Name: "OSHA Technical Manual / eTools (Roboter, Mindestabstände)", License: "Public Domain", Usage: "250 mm/s Teach-Anker + 29 CFR 1910 Sicherheitsabstände → minimum_distances.go + RAG bp_iace_safety_kb", Status: "verwendet"},
{Name: "OPSS PRISM (Severity × Probability Risikomatrix)", License: "Open Government Licence v3", Usage: "Methodik-Anker für S×W → Risiko-Level (RAPEX-aligned) → RAG bp_iace_safety_kb", Status: "verwendet"},
{Name: "Cobot-Schmerzschwellen (Behrens 2022 / Park 2019)", License: "CC BY 4.0", Usage: "Kraft/Druck-Limits je Körperregion (Daten hinter ISO/TS 15066, nicht die Norm) → RAG bp_iace_safety_kb", Status: "verwendet"},
{Name: "UK HSE Beispiel-Risikobeurteilungen", License: "Open Government Licence v3", Usage: "qualitative Gefährdung→Maßnahme-Struktur → RAG bp_iace_safety_kb", Status: "verwendet"},
{Name: "DGUV/IFA-Statistik & -Tabellen", License: "nur redaktionell, keine Bearbeitung", Usage: "—", Status: "ausgeschlossen"},
{Name: "DIN/Beuth/ISO/IEC Norm- & Risikograph-Tabellen", License: "urheberrechtlich", Usage: "Nur als Referenz genannt, NIE reproduziert (ISO-15066-Werte nur via CC-BY-Papers)", Status: "ausgeschlossen"},
},
NormMatching: []string{
"C-Normen (maschinenspezifisch): Match nur über die kanonische Maschinentyp-FAMILIE — `canonicalMachineType` faltet das feingranulare Normen-Vokabular (455 Keys: welding_machine, band_saw, mobile_crane …) auf die 68 Dropdown-Keys. Ohne Familien-Match wird die C-Norm verworfen (kein Tag/Kategorie-Fallback → keine Fremd-Domänen-Normen).",
"B-Normen (gefährdungsspezifisch): Match über Gefährdungskategorie und Komponenten-/Energie-Tags.",
"A-Normen (Grundnormen): gelten immer (z. B. EN ISO 12100).",
"DIN/ISO/OSHA-Versöhnung: Normen tragen teils OSHA-/ISO-/DIN-nahe Maschinen-Keys; die Familien-Faltung sorgt dafür, dass z. B. eine „welding_machine“-Norm für eine „welding“-Maschine matched.",
"Lizenz-Leitplanke: Norm-Tabellen/Risikographen werden NIE reproduziert — nur Norm-Referenzen ausgegeben.",
},
Evidence: AllRiskEvidence(),
}
}