a6f1020b2c
Add commercial-dishwasher hazard patterns (HP2200-HP2206): hot-water/steam scald on door opening, hot surfaces, hot ware, corrosive detergent/rinse-aid burn, respiratory irritation, door pinch and wet-floor slip — each gated by dom_warewashing so they never leak into other machine classes. Add the matching warewashing protective measures (M2200-M2208). Tighten capability-domain gating: emit dom_flame/dom_glue and add welding surface-form gate terms (schweissarbeitsplatz, schweissfunke, lichtbogenzone, ...) so the welding/flame/glue burn patterns stop leaking into thermal-capable machines such as a dishwasher. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
113 lines
4.1 KiB
Go
113 lines
4.1 KiB
Go
package iace
|
|
|
|
import "testing"
|
|
|
|
// firedSet runs the engine for the given custom tags and returns the set of
|
|
// fired pattern IDs.
|
|
func firedSet(customTags []string) map[string]bool {
|
|
engine := NewPatternEngine()
|
|
out := engine.Match(MatchInput{CustomTags: customTags})
|
|
fired := make(map[string]bool, len(out.MatchedPatterns))
|
|
for _, m := range out.MatchedPatterns {
|
|
fired[m.PatternID] = true
|
|
}
|
|
return fired
|
|
}
|
|
|
|
// A warewashing narrative emits these capability + functional tags.
|
|
var warewashingTags = []string{
|
|
"dom_warewashing", "steam_emission", "hot_water", "high_temperature",
|
|
"corrosive_chemical", "access_door", "rotating_part",
|
|
}
|
|
|
|
func TestWarewashing_PatternsFireForDishwasher(t *testing.T) {
|
|
fired := firedSet(warewashingTags)
|
|
want := []string{"HP2200", "HP2201", "HP2202", "HP2203", "HP2204", "HP2205", "HP2206"}
|
|
for _, id := range want {
|
|
if !fired[id] {
|
|
t.Errorf("expected warewashing pattern %s to fire for a dishwasher, but it did not", id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWarewashing_PatternsDoNotLeakIntoOtherMachines(t *testing.T) {
|
|
// A machine with thermal + electrical + chemical capability but NOT a
|
|
// dishwasher must never produce warewashing hazards (dom_warewashing gate).
|
|
fired := firedSet([]string{"high_temperature", "electrical_part", "chemical_risk", "rotating_part", "moving_part"})
|
|
for _, id := range []string{"HP2200", "HP2201", "HP2202", "HP2203", "HP2204", "HP2205", "HP2206"} {
|
|
if fired[id] {
|
|
t.Errorf("warewashing pattern %s leaked into a non-dishwasher machine", id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWarewashing_WeldingAndGlueDoNotLeakIntoDishwasher(t *testing.T) {
|
|
// The gate-term additions must stop the welding/flame/glue burn patterns
|
|
// from firing for a dishwasher (they previously leaked via high_temperature
|
|
// / electrical_part). dom_welding/dom_flame/dom_glue are absent here.
|
|
fired := firedSet(warewashingTags)
|
|
leak := map[string]string{
|
|
"HP530": "Lichtbogen-Verbrennung (Schweissen)",
|
|
"HP532": "Schweissrauch",
|
|
"HP533": "Brand durch Schweissfunken (Schweissen)",
|
|
}
|
|
for id, name := range leak {
|
|
if fired[id] {
|
|
t.Errorf("cross-domain pattern %s (%s) leaked into a dishwasher", id, name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWarewashing_MeasureIDsExist(t *testing.T) {
|
|
lib := GetProtectiveMeasureLibrary()
|
|
have := make(map[string]bool, len(lib))
|
|
for _, m := range lib {
|
|
have[m.ID] = true
|
|
}
|
|
for _, p := range GetWarewashingPatterns() {
|
|
for _, mid := range p.SuggestedMeasureIDs {
|
|
if !have[mid] {
|
|
t.Errorf("pattern %s references measure %s which is not in the library", p.ID, mid)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWarewashing_NarrativeEmitsTags(t *testing.T) {
|
|
// Closes the loop: a realistic dishwasher description must emit the tags
|
|
// the warewashing patterns gate on (otherwise the patterns are dead).
|
|
narrative := "Gewerbliche Untertisch-Geschirrspuelmaschine mit Heisswasser-Boiler " +
|
|
"und Nachspuelung ca. 85 Grad C, Spuelpumpe mit rotierenden Spuelfeldern, " +
|
|
"Dampf-/Wrasenabgabe beim Oeffnen, Reiniger und Klarspueler ueber Dosiergeraet, " +
|
|
"Tuer mit Sicherheitsschalter, Eingreifen in die Spuelkammer."
|
|
res := ParseNarrative(narrative, "Gewerbliche Geschirrspuelmaschine")
|
|
got := make(map[string]bool, len(res.CustomTags))
|
|
for _, tag := range res.CustomTags {
|
|
got[tag] = true
|
|
}
|
|
for _, want := range []string{"dom_warewashing", "steam_emission", "hot_water", "corrosive_chemical", "access_door", "rotating_part"} {
|
|
if !got[want] {
|
|
t.Errorf("narrative did not emit expected tag %q (got %v)", want, res.CustomTags)
|
|
}
|
|
}
|
|
// And it must NOT emit any welding/flame/glue domain that would re-open leaks.
|
|
for _, bad := range []string{"dom_welding", "dom_flame", "dom_glue"} {
|
|
if got[bad] {
|
|
t.Errorf("dishwasher narrative unexpectedly emitted cross-domain tag %q", bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWarewashing_NewMeasuresPresent(t *testing.T) {
|
|
lib := GetProtectiveMeasureLibrary()
|
|
have := make(map[string]bool, len(lib))
|
|
for _, m := range lib {
|
|
have[m.ID] = true
|
|
}
|
|
for _, mid := range []string{"M2200", "M2201", "M2202", "M2203", "M2204", "M2205", "M2206", "M2207", "M2208"} {
|
|
if !have[mid] {
|
|
t.Errorf("expected warewashing measure %s to be registered in the library", mid)
|
|
}
|
|
}
|
|
}
|