feat(iace): generic cross-domain leak gates + norm vocab reconciliation

- Domain-gate ~15 foreign machine classes (pool, amusement, paint booth,
  tank farm, reactor, lathe/chips, saw, film/carton, robot, mobile cab,
  asbestos, playground swing) in pattern_domain_gates.go so ungated hazard
  patterns stop leaking into unrelated machines; matching emit keywords
  added in keyword_dictionary.go (gate+emit share one vocabulary).
- Extend the cross-domain precision guard to 6 machine classes (press,
  cobot, motor, welding + the 2 GTs) with per-case homeDomains, so a
  machine's own domain terms are never flagged. GT coverage stays 100%.
- Reconcile the fine-grained norm machine-type vocabulary (455 keys) with
  the 68 canonical dropdown keys via canonicalMachineType() family folding
  in matchNorm — welding 0->17, robotics_cobot 0->6, press 8->13,
  circular_saw 1->35 machine-specific C-norms. Pattern gating left strict.
- Fix initialize?force=true summary index-shift that mislabeled counts
  (reported matched-patterns as "hazards"); now uses named step vars.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-10 22:29:10 +02:00
parent b7a7e70731
commit 005a2ed711
10 changed files with 656 additions and 9 deletions
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# Re-initialise all 6 IACE projects (4 Grenzen-only machines + 2 GTs) with the
# new domain-gated engine, then check for the specific foreign-domain leak
# signatures we set out to eliminate. Run AFTER the ai-sdk container is rebuilt.
# (bash 3.2 compatible — no associative arrays.)
set -uo pipefail
API="https://macmini:8093/sdk/v1/iace"
TEN="9282a473-5c95-4b3a-bf78-0ecc0ec71d3e"
PSQL='/usr/local/bin/docker exec bp-core-postgres psql -U breakpilot -d breakpilot_db -At -F"|"'
PROJECTS="
Kniehebelpresse:1e00ca16-ed0f-456d-80dd-b3035e413370
Eigenbauzelle:1f17051e-5ed1-4f56-a734-1bbcdc5c0c48
Elektromotoren:79566165-1561-43c7-97bf-4b6421a0641d
Schwingarm:00a573ec-caa0-4b7e-8af6-0acf3ed62989
Kistenhub_GT:1646d728-a6cb-4275-b147-44ca282bb6f0
Bremse_GT:f9347149-3d03-4c12-8a8e-0f8e32a71a91
"
echo "########## RE-INIT (force=true) — Summary vs DB ##########"
for row in $PROJECTS; do
name="${row%%:*}"; pid="${row##*:}"
resp=$(curl -sk -X POST -H "X-Tenant-ID: $TEN" "$API/projects/$pid/initialize?force=true")
sum=$(echo "$resp" | python3 -c "import sys,json
try:
s=json.load(sys.stdin).get('summary',{})
print(f\"comp={s.get('components')} pat={s.get('patterns')} haz={s.get('hazards')} mit={s.get('mitigations')} norm={s.get('norms')}\")
except Exception as e: print('(keine summary)')" 2>/dev/null)
hz=$(ssh macmini "$PSQL -c \"SELECT count(*) FROM compliance.iace_hazards WHERE project_id='$pid';\"" 2>/dev/null)
# Konsistenz: summary.haz muss == DB-Hazards sein (Summary-Bug-Check)
shz=$(echo "$sum" | sed -nE 's/.*haz=([0-9]+).*/\1/p')
ok="OK"; [ "$shz" = "$hz" ] || ok="!! MISMATCH"
printf " %-16s summary[%s] DB-Hazards=%s -> %s\n" "$name" "$sum" "$hz" "$ok"
done
echo
echo "########## LEAK-SIGNATUR-CHECK (Grenzen-Maschinen, sollte 0 sein) ##########"
LEAKS="Schwimmbecken|Massageduesen|Nassbereich|Karussell|Fahrersitz|Lackier|Loesemitteldampf|Tanklager|Reaktor|Sauerstoffanreicherung|Spannfutterbacke|Bandsaege|Folienwickler|Blasformwerkzeug|Asbest|Roboterzelle|Schwenkbereich Roboter|Spaeneflug|Spanflug"
for row in $PROJECTS; do
name="${row%%:*}"; pid="${row##*:}"
case "$name" in *_GT) continue;; esac
echo "=== $name ==="
ssh macmini "$PSQL -c \"SELECT category||' | '||name FROM compliance.iace_hazards WHERE project_id='$pid' AND (name ~* '($LEAKS)' OR hazardous_zone ~* '($LEAKS)') ORDER BY name;\"" 2>/dev/null \
| sed 's/^/ LEAK: /'
cnt=$(ssh macmini "$PSQL -c \"SELECT count(*) FROM compliance.iace_hazards WHERE project_id='$pid' AND (name ~* '($LEAKS)' OR hazardous_zone ~* '($LEAKS)');\"" 2>/dev/null)
echo " -> Leak-Treffer: $cnt"
done