fix(iace): Delta + FMEA — derive component tags from names when library_id missing
Build + Deploy / build-admin-compliance (push) Successful in 2m7s
Build + Deploy / build-backend-compliance (push) Successful in 3m42s
Build + Deploy / build-ai-sdk (push) Successful in 48s
Build + Deploy / build-developer-portal (push) Successful in 1m8s
Build + Deploy / build-tts (push) Successful in 1m38s
Build + Deploy / build-document-crawler (push) Successful in 1m0s
Build + Deploy / build-dsms-gateway (push) Successful in 29s
Build + Deploy / build-dsms-node (push) Successful in 19s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / loc-budget (push) Failing after 15s
CI / secret-scan (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m36s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 51s
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 25s
CI / test-python-dsms-gateway (push) Successful in 21s
CI / validate-canonical-controls (push) Successful in 15s
Build + Deploy / trigger-orca (push) Successful in 3m28s

Auto-created components have no library_id. Delta analysis and FMEA now
derive pattern-engine-compatible tags from component names (e.g. "Roboter"
→ cobot/robot_arm, "SPS" → controller/plc, "Scanner" → sensor).

Also: new E2E test file iace-extensions.spec.ts (FMEA, Knowledge Graph,
Delta API, Failure Modes API).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-12 08:26:15 +02:00
parent df15f6f098
commit 6586d2cb5e
3 changed files with 282 additions and 25 deletions
@@ -52,21 +52,7 @@ export function useFMEA(projectId: string) {
})
)
// Load failure modes for each component type (deduplicated)
const types = [...new Set(components.map((c) => c.component_type))]
const fmByType: Record<string, FailureMode[]> = {}
await Promise.all(
types.map(async (type) => {
const res = await fetch(`/api/sdk/v1/iace/failure-modes?component_type=${type}`)
if (res.ok) {
const json = await res.json()
fmByType[type] = json.failure_modes || []
}
})
)
// Also load general failure modes (no type filter)
// Load ALL failure modes, then match by component type + name keywords
const allRes = await fetch('/api/sdk/v1/iace/failure-modes')
let allFMs: FailureMode[] = []
if (allRes.ok) {
@@ -74,12 +60,33 @@ export function useFMEA(projectId: string) {
allFMs = json.failure_modes || []
}
// Derive the best FM component_type from component name keywords
const nameToFMTypes: Record<string, string[]> = {
sensor: ['sensor'], scanner: ['sensor'], kamera: ['sensor'],
motor: ['actuator', 'electrical'], antrieb: ['actuator'],
steuerung: ['controller'], sps: ['controller'], plc: ['controller'],
software: ['software'], firmware: ['software'],
ventil: ['actuator', 'mechanical'], greifer: ['actuator', 'mechanical'],
roboter: ['actuator', 'mechanical'], hydraulik: ['actuator'],
netzwerk: ['network'], ethernet: ['network'],
}
function getFMTypesForComp(comp: Component): string[] {
const types = [comp.component_type]
const nameLower = comp.name.toLowerCase()
for (const [kw, fmTypes] of Object.entries(nameToFMTypes)) {
if (nameLower.includes(kw)) types.push(...fmTypes)
}
return [...new Set(types)]
}
// Build FMEA rows: each component × its matching failure modes
const fmeaRows: FMEARow[] = []
for (const comp of components) {
const compFMs = fmByType[comp.component_type] || []
// Use type-specific FMs, or fallback to first 3 general FMs
const relevantFMs = compFMs.length > 0 ? compFMs : allFMs.slice(0, 3)
const compTypes = getFMTypesForComp(comp)
const compFMs = allFMs.filter((fm) => compTypes.includes(fm.component_type))
// Use matched FMs, or fallback to mechanical FMs
const relevantFMs = compFMs.length > 0 ? compFMs : allFMs.filter((fm) => fm.component_type === 'mechanical').slice(0, 3)
for (const fm of relevantFMs) {
const s = fm.default_severity || 5