feat(ai-sdk): interlocked-enclosure model — guard-open re-scoping of contact hazards
Class C (phase-aware, generic EN ISO 14120). A contact/entanglement hazard from a moving part is removed during NORMAL operation when the part is behind an interlocked guard; it remains only when the guard is open (maintenance/cleaning). - New HazardPattern.GuardableByEnclosure flag; set on HP096 (friction at rotating surfaces) and HP101 (entanglement of hair/clothing). - Narrative emits interlocked_enclosure for an interlocked door/hood. - pattern_enclosure.go: suppressedByEnclosure (drop in normal-op-only contexts) + guardedLifecycles (re-scope to maintenance/cleaning). - GT #3 gains the maintenance-phase entanglement/friction rows. Generic + regression-safe: machines that do not emit interlocked_enclosure are unaffected. GT #3 recall 80% -> 82.4%, one false positive removed (Aufwickeln). Kistenhub 97.1% and all 26 Bremse pinned mappings unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package iace
|
||||
|
||||
// Interlocked-enclosure model (EN ISO 14120 / EN ISO 12100).
|
||||
//
|
||||
// A contact or entanglement hazard from a moving part is removed during NORMAL
|
||||
// operation when that part is inaccessible behind an interlocked guard. The
|
||||
// hazard then remains only when the guard is open — maintenance, cleaning or
|
||||
// fault clearing. Patterns flagged GuardableByEnclosure express this; a project
|
||||
// emits the "interlocked_enclosure" tag (interlocked door/hood, see
|
||||
// keyword_dictionary.go) to declare the guard.
|
||||
//
|
||||
// This is GENERIC: it applies to every enclosed machine (dishwasher spray arm,
|
||||
// enclosed mixer, centrifuge ...) and is regression-safe — machines that do not
|
||||
// emit interlocked_enclosure are unaffected.
|
||||
|
||||
const (
|
||||
phaseMaintenance = "maintenance"
|
||||
phaseCleaning = "cleaning"
|
||||
phaseFaultClearing = "fault_clearing"
|
||||
)
|
||||
|
||||
// suppressedByEnclosure reports whether a guardable hazard must be dropped: the
|
||||
// part is enclosed AND none of the project's lifecycle phases opens the guard.
|
||||
func suppressedByEnclosure(p HazardPattern, tagSet map[string]bool, lifecycles []string) bool {
|
||||
if !p.GuardableByEnclosure || !tagSet["interlocked_enclosure"] || len(lifecycles) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, lc := range lifecycles {
|
||||
if lc == phaseMaintenance || lc == phaseCleaning || lc == phaseFaultClearing {
|
||||
return false // guard is open in some phase → hazard remains there
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// guardedLifecycles re-scopes a guardable hazard to the guard-open phases when
|
||||
// the project declares an interlocked enclosure, so it is documented as a
|
||||
// maintenance/cleaning hazard rather than a normal-operation one.
|
||||
func guardedLifecycles(p HazardPattern, tagSet map[string]bool) []string {
|
||||
if p.GuardableByEnclosure && tagSet["interlocked_enclosure"] {
|
||||
return []string{phaseMaintenance, phaseCleaning}
|
||||
}
|
||||
return p.ApplicableLifecycles
|
||||
}
|
||||
Reference in New Issue
Block a user