feat(iace): unified FailureKnowledge ontology + NASA starter (FMEA P2)
The source-agnostic failure ontology shared by the FMEA library and the CE hazard side: Component → FailureMode → Mechanism → Effect → Hazard → Harm → Control, each row source+licence tagged. A licence ALLOWLIST (FailureKnowledgeLicenseAllowed) rejects copyrighted/proprietary/NC sources up front (© IITRI, DIN/ISO, AIAG, OREDA, CC-BY-NC) — the discipline learned from the FMD-91/NPRD-91 licence finding. Seeded with a curated NASA NTRS lessons-learned starter (5 real entries, public domain). GET /iace/failure-knowledge (+ ?domain=). Tests pin the governance invariant: every entry must carry a commercially-usable licence. Next: Playwright+OCR bulk loader (NTRS API → PDF/OCR → tuple extraction) to grow the corpus from NASA/OSHA/CPSC/MAUDE/NTSB. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package iace
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFailureKnowledgeLicenseAllowed(t *testing.T) {
|
||||
accept := []string{
|
||||
"Public Domain (NASA NTRS, GOV_PUBLIC_USE_PERMITTED)",
|
||||
"US Public Domain",
|
||||
"CC BY 4.0",
|
||||
"CC BY-SA 4.0",
|
||||
"Open Government Licence v3.0",
|
||||
"MIT",
|
||||
}
|
||||
for _, l := range accept {
|
||||
if !FailureKnowledgeLicenseAllowed(l) {
|
||||
t.Errorf("license should be ALLOWED: %q", l)
|
||||
}
|
||||
}
|
||||
reject := []string{
|
||||
"© 1991, IIT Research Institute. All Rights Reserved.", // FMD-91/NPRD-91
|
||||
"CC BY-NC 4.0",
|
||||
"proprietary (Quanterion)",
|
||||
"DIN EN ISO 13849 table",
|
||||
"AIAG-VDA handbook",
|
||||
"OREDA member-only",
|
||||
"CC BY-ND",
|
||||
"",
|
||||
}
|
||||
for _, l := range reject {
|
||||
if FailureKnowledgeLicenseAllowed(l) {
|
||||
t.Errorf("license should be REJECTED: %q", l)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNASAFailureKnowledge_Integrity(t *testing.T) {
|
||||
seen := map[string]bool{}
|
||||
nasa := GetNASAFailureKnowledge()
|
||||
if len(nasa) == 0 {
|
||||
t.Fatal("NASA starter set is empty")
|
||||
}
|
||||
for _, fk := range nasa {
|
||||
if seen[fk.ID] {
|
||||
t.Errorf("duplicate FK id %q", fk.ID)
|
||||
}
|
||||
seen[fk.ID] = true
|
||||
if fk.ID == "" || fk.Component == "" || fk.FailureMode == "" || fk.Effect == "" ||
|
||||
fk.Control == "" || fk.Source == "" || fk.License == "" || fk.Attribution == "" {
|
||||
t.Errorf("%s: empty required field: %+v", fk.ID, fk)
|
||||
}
|
||||
if fk.URL == "" {
|
||||
t.Errorf("%s: NASA entry missing source URL", fk.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Governance invariant: EVERY curated entry must carry a commercially-usable
|
||||
// licence — this is the gate that keeps copyrighted/proprietary data out.
|
||||
func TestAllFailureKnowledge_LicensesAllowed(t *testing.T) {
|
||||
for _, fk := range AllFailureKnowledge() {
|
||||
if !FailureKnowledgeLicenseAllowed(fk.License) {
|
||||
t.Errorf("%s carries a non-allowed licence %q", fk.ID, fk.License)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailureKnowledgeByDomain(t *testing.T) {
|
||||
all := AllFailureKnowledge()
|
||||
if len(all) == 0 {
|
||||
t.Fatal("no failure knowledge")
|
||||
}
|
||||
d := all[0].Domain
|
||||
got := FailureKnowledgeByDomain(d)
|
||||
if len(got) == 0 {
|
||||
t.Errorf("expected entries for domain %q", d)
|
||||
}
|
||||
for _, fk := range got {
|
||||
if fk.Domain != d {
|
||||
t.Errorf("domain filter leaked %q into %q", fk.Domain, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user