6 supplementary measures (M410-M420) were silently overwritten by
metalworking duplicates in measureByID lookups, so robot-cell electrical
patterns resolved to chip-extraction/cleaning fallbacks instead of
equipotential bonding, creepage, EMC, or hose-burst protection. Rename
supplementary IDs to M475-M480 and rewire 13 affected pattern references
in robot_cell + robot_cell_ext.
HP1640 (direct contact with live parts, GT 2.2): priority 98->99, drop
RequiredEnergyTags gate so it fires in robot cells without an electrical
tag, expand mitigations to 5 concrete TRBS 2131 / IEC 60204-1 / EN 61140
measures (basic protection, double insulation, earthing, insulation
monitoring, equipotential bonding) — was previously losing to HP1688
even though HP1688 describes a different scenario.
HP1688 (touch voltage from potential differences): priority 98->96 so it
no longer outranks HP1640 for the direct-contact case; mitigations
expanded from M410-only to 4 concrete electrical measures.
Add regression tests pinning HP1640 contact-protection resolution and
M475 = Potentialausgleich. Existing TestGetProtectiveMeasureLibrary_-
UniqueIDs now actually enforces uniqueness (previously masked by
last-wins map override).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
KSS, EMV, ESD, DCS, PLR, SIL, HMI, SPS, RCD, LOTO, PSA are
abbreviations that should NOT trigger the relevance filter.
bersten, platzen, abspringen, spritzen, einatmen, ausrutschen,
herabfallen, durchschlaegen, wegschleudern are action words that
appear in many patterns and don't indicate a specific machine.
Fixes: HP1633-HP1675 (KSS patterns) were filtered out because
"kss" was not in the narrative but also not in genericSafetyTerms.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Robot cell patterns now fire BEFORE generic patterns (Priority 96-99
vs generic 85-95). This ensures pattern-specific SuggestedMeasureIDs
(M420 for KSS, M410 for Potentialausgleich) reach the hazard.
Removed debug fmt.Println statements.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When multiple patterns match the same category+zone, the first creates
the hazard and later patterns add their SuggestedMeasureIDs to the
existing hazard. This ensures KSS-specific measures (M420) reach the
hazard even if a generic pattern created it first.
seenCatZone changed from map[string]bool to map[string]uuid.UUID
to track which hazard ID was created for each dedupKey.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each hazard now gets measures from its SOURCE PATTERN first
(SuggestedMeasureIDs), then category fallback for remaining slots.
Previously all mechanical hazards got the same generic top-5 measures
(Gefahrstelle eliminieren, Sicherheitsabstaende, Scharfe Kanten...).
Now a KSS-Schlauch hazard gets M420 (Druckfeste Auslegung) first.
SuggestedMeasureIDs added to PatternMatch struct and passed through
from pattern definition to hazard creation to measure assignment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every ScenarioDE now describes how a PERSON is affected, not just
what happens to the machine. Every HarmDE describes the INJURY,
not just the technical effect.
Examples:
- "Peitscheneffekt des Schlauchs" → "Person wird von abspringendem
Schlauch getroffen. KSS-Spritzer verletzen Haut und Augen."
- "Kurzschluss, Brand" → "Person wird durch Brand oder toxische
Rauchgase verletzt. Verbrennungen, Rauchvergiftung."
Rule: Risikobeurteilung bewertet Gefahr fuer PERSONEN.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HP1606: Quetschen/Scheren durch Greifer im Einrichtbetrieb (GT 1.14)
HP1634: KSS-Pumpe spritzt bei geoeffneter Schutztuer (GT 1.38)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HP1605: Stoss durch Werkzeug/Greifer im Einrichtbetrieb (GT 1.14)
HP1633: KSS-Versorgungsschlauch platzt oder reisst ab (GT 1.35)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Energy tag "electrical" doesn't match resolved tags (which are
"high_voltage", "electrical_part", etc.). Patterns HP1685-HP1699
now fire without energy tag requirement — they fire for any
project that has the right component tags.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When GT has two entries for the same zone with different scenarios
(e.g. "eingeklemmt" vs "getroffen"), we need separate engine patterns.
HP1700: Getroffen von bewegtem Werkzeug/Greifer (vs HP1652 eingeklemmt)
HP1701: Greifer/Werkzeug durchschlaegt Zaun (vs HP1654 Werkstueck)
HP1702: KSS-Schlauch platzt (vs HP1675 springt ab)
HP1703: KSS-Bettspuelung bei offener Tuer (vs HP1670 allgemein)
HP1704: Brand durch KSS auf elektrische Komponenten
Extended synonym sets for potential/EMV matching.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
scenarioSimilarity now uses synonym-set cross-matching: if GT says
"durchschlaegt" and Engine says "schleuder", the synonym set recognizes
them as related. Added significantWordOverlap fallback when no action
words found. Extended action terms: schlauch/druck/kuehlschmierstoff,
pumpe/bettspuel, potential/bezugspotential, stoerung/emv.
Moved extractActionWords to benchmark_synonyms.go (458+119 lines).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4-signal matcher: category (0.2), keywords (0.2), zone (0.3),
scenario similarity (0.3). Scenario signal extracts action words
(eingeklemmt vs herabfallend vs durchschlaegt) to differentiate
similar-looking hazards at the same component.
Split benchmark_synonyms.go (70 lines) from benchmark_matcher.go
(516→450 lines) to stay under 500-line cap.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sort matches by specificity first (zone overlap), then by score.
Prevents generic matches from consuming specific Engine patterns
that should match more specific GT entries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Threshold 0.25→0.20 to recover matches lost by keyword penalty.
New synonym sets: eingeschlossen/wiederanlauf, zentriergreifer,
beladetuer/schutztuer, ergonom/bedienelemente, spritzer/auge, bersten.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Patterns for playground, escalator, wind turbine, glass washing,
laundry, crane, lathe, rotary transfer, press now require matching
MachineTypes — they no longer fire for unrelated projects.
Neutralized zone texts in base patterns HP006/HP008 (removed
"Pressenraum", "Kran-/Hebezeugbereich").
Fixes: Spielplatz, Fahrtreppe, Windturbine etc. appearing in robot cell.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaced category-broadcast logic with per-hazard loop:
each hazard gets up to 5 measures (pattern-suggested first, then
category fallback). Expected: 108 × 5 = max 540 total.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pattern-suggested measures go to all hazards in category (correct).
Category-based fallback only for hazards WITHOUT pattern suggestions
(max 3 per hazard). Prevents 1654 mitigations explosion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
hazardIDsByCategory changed from map[string]uuid.UUID to
map[string][]uuid.UUID — measures are now distributed to every
hazard in a category, not just the last one created.
Previously 94/108 hazards had no measures, now all get them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Store ALL applicable lifecycles (comma-separated) not just first
- Frontend maps internal keys to German labels (normal_operation ->
Automatikbetrieb, maintenance -> Wartung, etc.)
- Show Betroffene Personen in engine detail column
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend: HazardSummary now includes lifecycle_phase and affected_person
Frontend: Engine detail column shows Lebensphasen and Betroffene Personen
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Systematic refactoring of all hazard_patterns_*.go files:
- Removed lifecycle phase words from NameDE and ScenarioDE
(67 fixes across 20 files)
- Phases belong in ApplicableLifecycles, not in text
- "bei Wartung/Reinigung/Montage/..." removed from names
- Scenarios rewritten to be phase-neutral
- Lifecycle-specific concepts preserved when they define the hazard
(e.g. LOTO, Betriebsartenwahlschalter)
Rule: Gefaehrdung + Szenario NEUTRAL, Lebensphasen SEPARAT.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Removed HP1601 (duplicate of HP1600 with narrower scope)
- HP1600 now covers ALL lifecycle phases, not just teach mode
- All pattern texts neutral: no lifecycle phase references in
NameDE, ScenarioDE, TriggerDE — phases only in ApplicableLifecycles
- Formulierungsregel documented in file header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ApplicableLifecycles field in HazardPattern: patterns now declare which
lifecycle phases the hazard applies to (Output, not just filter)
- Init handler writes first applicable lifecycle into Hazard.LifecyclePhase
- Robot cell patterns HP1600-1601 broadened: "Betrieb, Einrichten, Reinigung,
Wartung, Fehlersuche" instead of only "Teach-Betrieb"
- All robot cell patterns get ApplicableLifecycles for proper phase display
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend: HazardSummary now includes description, scenario, possible_harm,
trigger_event, and mitigations[] for side-by-side comparison.
Frontend: Each matched pair row is now clickable/expandable showing
two-column detail view:
- Left (GT): hazard type, cause, zone, lifecycle phases, risk values
(F/W/P/S->R), residual risk, measures, type (KM/TM/BI), norms, comment
- Right (Engine): name, scenario, zone, possible harm, trigger, measures
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- hazard_blocks.go: ComputeHazardBlocks() groups hazards by category +
component + zone. Parent = highest risk in group. Children covered by
parent's measures are flagged (no separate assessment needed).
- iace_handler_blocks.go: GET /projects/:id/hazard-blocks endpoint
with summary stats (blocks, covered children, assessments saved)
Frontend:
- HazardBlockView.tsx: Expandable block view with summary cards,
parent-child hierarchy, coverage badges, and "abgedeckt" indicators
- hazards/page.tsx: New "Bloecke" tab alongside "Hazard-Liste" and
"Risikobewertung"
No database schema changes — grouping is computed at runtime.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add synonym sets for isolation/grounding, creepage/surface, EMV/radiation
to improve matching of GT entries 2.5, 2.6, and 6.1.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace machine-specific term blacklist with generic vocabulary overlap:
- Extract significant words (>=5 chars, not generic safety terms) from
pattern zone/scenario
- If pattern has specific words but NONE appear in narrative → filter
- genericSafetyTerms whitelist with ~50 terms that appear in all assessments
- Truly generic approach: works for any machine type without maintenance
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- isPatternRelevant() filters patterns whose zone/scenario mentions
machine-specific terms (extruder, stanzpresse, spielplatz, etc.)
absent from the actual machine narrative
- normalizeZoneKey() clusters similar zones for smarter dedup
(e.g. "Schaltschrank, Sammelschiene" = "Schaltschrank-Innenraum")
- machineSpecificTerms list with 40+ terms for generic filtering
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Erklaerteil-Template fuer Risikobeurteilungen (risk_assessment_template.go)
in PDF-Export, Markdown-Export und Frontend ReportPrintView eingebaut
- Ground Truth Benchmark-System: Datenmodell, Fuzzy-Matching-Engine,
3 API Endpoints (import-gt, benchmark, benchmark/summary)
- Frontend Benchmark-Tab mit Score-Cards, Kategorie-Breakdown,
Hazard-Vergleichstabelle (Zugeordnet/Fehlend/Extra), Business Impact
- Erster Benchmark: 13.3% Coverage (Baseline) gegen 60 GT-Eintraege
- Dedup-Fix: seenCat[cat] -> seenCatZone[cat+zone] erlaubt mehrere
Gefaehrdungen pro Kategorie an verschiedenen Gefahrenstellen
- Komponenten-spezifische Hazard-Namen und Zone-basierte Zuordnung
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mac Mini M4 needs more time for qwen3:30b. Reduced batch from 10→5
MCs and increased timeout from 20→45s to give LLM a fair chance.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single LLM calls per MC caused 2min+ timeouts. Now batches up to 10
MCs in one prompt with 20s timeout. LLM failure falls through to
deterministic derivation gracefully. Proxy timeout increased to 60s.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Changes the compile flow to always query Master Controls from DB first:
1. doc_check_controls → Mode A (deterministic)
2. LLM generation via Ollama/Claude → Mode B
3. Derive from MC name → fallback
4. Template hardcoded questions → absolute fallback
Previously, templates with pre-defined questions just returned those
without ever hitting the DB. Now MC-compiled questions take priority
and template questions fill gaps for uncovered topics.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
POST /projects/:id/components/:cid/suggest-fms
- Baut FMEA-Experten-Prompt aus Komponentenname + Maschinenkontext
- LLM antwortet mit 5 FMs als JSON (Mode, Effect, S/O/D)
- Fallback auf Bibliotheks-FMs wenn LLM nicht verfuegbar
- Nutzt ProviderRegistry (Ollama primary, Anthropic fallback)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>