feat(iace): cross-domain precision overhaul + component review + schema reconcile

Engine precision (stop foreign-machine patterns leaking into a project):
- Wire project.MachineType into the engine machine-type gate (empty input no
  longer fires every machine class — press/cnc/excavator/crane/medical...).
- Capability-domain gating extended by 7 domains (outdoor, ventilation,
  machining, bulk, palletizer, playground, fitness) so domain-specific hazards
  only fire when the narrative names that domain; emitted via keyword_dictionary.
- Relevance backstop moved into iace (single gating contract, testable), and its
  dominant false-anchor class removed (a long pattern word no longer matches a
  short common token; prepositions/leitung added to the generic stoplist).
- New guard tests: TestCrossDomainPrecision (full pipeline, 0 foreign per GT) and
  TestPatternReachability now asserts 0 dead patterns. Both GTs keep coverage 1.0.

Reachability fix: the 51 dead patterns required electrical/pneumatic/hydraulic
tags nothing produced — renamed to the canonical electrical_energy/
pneumatic_pressure/hydraulic_pressure/hydraulic_part.

Component review (negation is best-effort + expert-correctable):
- Parser surfaces negated components (ComponentMatch.Negated) instead of dropping
  them; negated contribute no tags/energy → no phantom hazards.
- presence_status (vorhanden|nicht_vorhanden|geloescht) + ce_marked on components;
  only `vorhanden` feed matching. CE+safety-relevant flags the PL/SIL obligation.
- Force re-seed preserves the expert's component decisions instead of wiping them.
- Tag-based component→hazard assignment (was: all on the first component).
- Negation-aware narrative parsing ("keine Pneumatik" no longer extracts it).

Local-dev DB: ai-sdk sets search_path=compliance,core,public; reconcile migrations
152-156 bring the consolidated local iace tables to the current schema + add the
presence_status/ce_marked columns. Machine-type vocabulary endpoint for the form.

[migration-approved]

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-10 17:15:55 +02:00
parent 3bd4e0aaaf
commit afb3f83f30
47 changed files with 1275 additions and 169 deletions
@@ -69,6 +69,13 @@ func GetKeywordDictionary() []KeywordEntry {
{Keywords: []string{"maehdrescher", "ballenpresse", "feldhaecksler", "traktor"}, ExtraTags: []string{"dom_agri"}},
{Keywords: []string{"rolltreppe", "fahrtreppe", "fahrsteig"}, ExtraTags: []string{"dom_escalator"}},
{Keywords: []string{"glasschneid", "glasbearbeitung", "flachglas", "glasscheibe", "glaskante", "glasmaschine"}, ExtraTags: []string{"dom_glass"}},
{Keywords: []string{"im freien", "freigelaende", "ausseneinsatz", "aussenarbeit", "witterung", "forstarbeit", "freiland", "aussengelaende", "winterdienst"}, ExtraTags: []string{"dom_outdoor"}},
{Keywords: []string{"lueftungsanlage", "lueftungskanal", "klimaanlage", "feuchtraum"}, ExtraTags: []string{"dom_ventilation"}},
{Keywords: []string{"kuehlschmierstoff", "kss-anlage", "kss-kreislauf", "kss-aufbereitung", "bearbeitungszentrum", "kuehlturm"}, ExtraTags: []string{"dom_machining"}},
{Keywords: []string{"silo", "schuettgut", "gaerbehaelter", "getreidesilo", "mehlsilo", "schuettgutfoerder"}, ExtraTags: []string{"dom_bulk"}},
{Keywords: []string{"palettierer", "palettieranlage", "palettierroboter"}, ExtraTags: []string{"dom_palletizer"}},
{Keywords: []string{"spielplatz", "klettergeraet", "spielgeraet", "spielturm"}, ExtraTags: []string{"dom_playground"}},
{Keywords: []string{"kraftstation", "fitnessgeraet", "trainingsgeraet", "kraftgeraet", "langhantel"}, ExtraTags: []string{"dom_fitness"}},
// Ghost-Closure (Emit-Seite): macht die 34 toten Required-Tags
// emittierbar, jeweils NUR via domaenenspezifische Keywords -> die 120
// Ghost-Patterns feuern wieder, aber nur fuer ihre echte Maschine (kein
@@ -193,7 +200,11 @@ func GetKeywordDictionary() []KeywordEntry {
{Keywords: []string{"greifer", "gripper"}, ComponentIDs: []string{"C002"}, ExtraTags: []string{"clamping_part", "pinch_point"}},
{Keywords: []string{"spindel", "spindle"}, ComponentIDs: []string{"C006"}, EnergyIDs: []string{"EN02"}, ExtraTags: []string{"rotating_part", "high_speed"}},
{Keywords: []string{"saege", "saw"}, ComponentIDs: []string{"C007"}, ExtraTags: []string{"cutting_part"}},
{Keywords: []string{"walze", "roller"}, ComponentIDs: []string{"C009"}, EnergyIDs: []string{"EN02"}, ExtraTags: []string{"rotating_part", "entanglement_risk"}},
// "roller" (English) removed: as a bare substring it false-matches
// German compounds like "Bodenroller" (a floor dolly) and "Controller",
// wrongly creating a rotating mill-roller component. "walze" and its
// compounds are the precise German terms for C009.
{Keywords: []string{"walze", "kalanderwalze", "walzwerk"}, ComponentIDs: []string{"C009"}, EnergyIDs: []string{"EN02"}, ExtraTags: []string{"rotating_part", "entanglement_risk"}},
{Keywords: []string{"kette", "chain"}, ComponentIDs: []string{"C010"}, ExtraTags: []string{"entanglement_risk"}},
{Keywords: []string{"bremse", "brake"}, ComponentIDs: []string{"C013"}, ExtraTags: []string{"safety_device"}},
{Keywords: []string{"schweiss", "weld"}, ComponentIDs: []string{"C016"}, EnergyIDs: []string{"EN05"}, ExtraTags: []string{"high_temperature"}},