f534b52817
Add cmd/iace-audit CLI with 5 deterministic methods that find engine gaps without ground truth: - A reachability: 1058 patterns vs achievable tag universe - B consistency: components vs their declared hazard categories - C vocabulary: limits-form tokens vs keyword dictionary - D echo: limits-form sentences vs generated hazards (jaccard) - E hierarchy: hazards vs ISO 12100 design/protection/info levels Library fixes triggered by A+B+C findings: - tag_resolver: synonym map for electrical/pneumatic/hydraulic aliases - component_library: crush_point + EN03 (gravitational) on C014/C128 (Hubwerk family) - fixes HP1014/1015/1017/1018 which were silently weakly_reachable. noise_source added on 7 components (C006/C011/ C017/C020/C031/C041/C096). electrical_part on 8 drive components (C031/C032/C033/C034/C035/C036/C037/C038/C077/C092). cyber tag on 10 sensors (C081-C090) + 3 IT components (C111/C112/C116) + KI module C119 (ai_model added). pneumatic_part+hydraulic_part on valves C091/C093, hydraulic_part+chemical_risk on pump C097, moving_part on motion controller C075 - keyword_dictionary: EN03 added to aufzug/lift/hubwerk/hubgeraet (was wrongly EN04-only). New keyword entries for hub-action verbs: absenken/senken/anheben/heben + hubhoehe/hubweg/hubgeschwindig Audit impact: - A: weakly_reachable 409 -> 358 (-51 patterns now fully reachable) - B: incomplete components 46 -> 30 (-16, -33%) - HP1018 (Person unter absenkendem Maschinenteil eingeklemmt): weakly_reachable -> reachable Why: methods A/B/C surfaced that the Kistenhubgeraet test project generated 0 crush-under-load hazards despite OSHA 1910.212(a)(3) + EN ISO 12100 6.3.5.5 explicitly requiring them. Three orthogonal bugs (missing crush_point tag, wrong energy source mapping, missing action verbs in dictionary) silently disabled the entire lift crush pattern family.
63 lines
1006 B
Go
63 lines
1006 B
Go
package audit
|
|
|
|
import "strconv"
|
|
|
|
func appendUnique(list []string, item string) []string {
|
|
for _, x := range list {
|
|
if x == item {
|
|
return list
|
|
}
|
|
}
|
|
return append(list, item)
|
|
}
|
|
|
|
func toBoolSet(list []string) map[string]bool {
|
|
s := make(map[string]bool, len(list))
|
|
for _, x := range list {
|
|
s[x] = true
|
|
}
|
|
return s
|
|
}
|
|
|
|
func dedup(list []string) []string {
|
|
seen := map[string]bool{}
|
|
var out []string
|
|
for _, x := range list {
|
|
if !seen[x] {
|
|
seen[x] = true
|
|
out = append(out, x)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func removeOne(list []string, item string) []string {
|
|
out := make([]string, 0, len(list))
|
|
for _, x := range list {
|
|
if x != item {
|
|
out = append(out, x)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func joinFirst(list []string, n int) string {
|
|
if len(list) <= n {
|
|
return joinAll(list)
|
|
}
|
|
return joinAll(list[:n]) + ", ..."
|
|
}
|
|
|
|
func joinAll(list []string) string {
|
|
s := ""
|
|
for i, x := range list {
|
|
if i > 0 {
|
|
s += ", "
|
|
}
|
|
s += x
|
|
}
|
|
return s
|
|
}
|
|
|
|
func itoa(n int) string { return strconv.Itoa(n) }
|