feat(iace): Phase 1 — Haftungs-Fixes, Massnahmen-Verkabelung, Explainability Engine
Phase 1A — Haftungs-kritische Fixes: - SIL/PL-Badges als "Vorab-Einschaetzung" mit Tooltip gekennzeichnet - Coverage-Disclaimer in CE-Akte, Projekt-Uebersicht und Print-Export - Norm-Referenzen: 42 Kapitelverweise durch Themen-Deskriptoren ersetzt Phase 1B — Massnahmen-Verkabelung: - 16 neue Massnahmen (M201-M216) fuer bisher unabgedeckte Kategorien (communication_failure, hmi_error, firmware_corruption, maintenance, sensor_fault, mode_confusion) - Kategorie-Fallback im Initialize-Endpoint: ordnet Massnahmen aus der Bibliothek automatisch per HazardCategory zu (max 8 pro Kategorie) - Total: 225 → 241 Massnahmen, 0 Kategorien ohne Massnahmen Phase 1C — Explainability Engine: - MatchReason Struct in PatternMatch (type, tag, met) - Pattern Engine schreibt fuer jeden Match strukturierte Begruendungen - Frontend zeigt "Erkannt weil: Komponente X, Energie Y, Kein Ausschluss Z" Weitere Aenderungen: - BAuA/OSHA Regulatory Hints: 3 Enrich-Endpoints (per Hazard, per Measure, Batch) - Dokumente-Tab in IACE-Bibliothek (36.708 Chunks aus Qdrant) - Varianten-UX: Basis-Projekt-Summary auf Varianten-Seite - Projekt-Initialisierung: POST /initialize kettet Parse→Komponenten→Patterns→Hazards→Massnahmen→Normen - 18 pre-existing TS-Fehler gefixt, Route-Konflikt behoben - Component-Library + Measures-Library Tests aktualisiert Tests: Go alle bestanden, TS 0 Fehler, Playwright 141+ bestanden Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -113,16 +113,25 @@ describe('getPreviousStep', () => {
|
||||
})
|
||||
|
||||
describe('getCompletionPercentage', () => {
|
||||
const createMockState = (completedSteps: string[]): SDKState => ({
|
||||
const createMockState = (completedSteps: string[]) => ({
|
||||
version: '1.0.0',
|
||||
projectVersion: 1,
|
||||
lastModified: new Date(),
|
||||
tenantId: 'test',
|
||||
userId: 'test',
|
||||
subscription: 'PROFESSIONAL',
|
||||
projectId: 'test-project',
|
||||
projectInfo: null,
|
||||
customerType: null,
|
||||
companyProfile: null,
|
||||
complianceScope: null,
|
||||
sourcePolicy: null,
|
||||
currentPhase: 1,
|
||||
currentStep: 'use-case-assessment',
|
||||
completedSteps,
|
||||
checkpoints: {},
|
||||
importedDocuments: [],
|
||||
gapAnalysis: null,
|
||||
useCases: [],
|
||||
activeUseCase: null,
|
||||
screening: null,
|
||||
@@ -143,9 +152,12 @@ describe('getCompletionPercentage', () => {
|
||||
consents: [],
|
||||
dsrConfig: null,
|
||||
escalationWorkflows: [],
|
||||
iaceProjects: [],
|
||||
ragCorpusStatus: null,
|
||||
sbom: null,
|
||||
securityIssues: [],
|
||||
securityBacklog: [],
|
||||
customCatalogs: {},
|
||||
commandBarHistory: [],
|
||||
recentSearches: [],
|
||||
preferences: {
|
||||
@@ -157,7 +169,7 @@ describe('getCompletionPercentage', () => {
|
||||
autoValidate: true,
|
||||
allowParallelWork: true,
|
||||
},
|
||||
})
|
||||
}) as SDKState
|
||||
|
||||
it('should return 0 for no completed steps', () => {
|
||||
const state = createMockState([])
|
||||
@@ -182,16 +194,25 @@ describe('getCompletionPercentage', () => {
|
||||
})
|
||||
|
||||
describe('getPhaseCompletionPercentage', () => {
|
||||
const createMockState = (completedSteps: string[]): SDKState => ({
|
||||
const createMockState = (completedSteps: string[]) => ({
|
||||
version: '1.0.0',
|
||||
projectVersion: 1,
|
||||
lastModified: new Date(),
|
||||
tenantId: 'test',
|
||||
userId: 'test',
|
||||
subscription: 'PROFESSIONAL',
|
||||
projectId: 'test-project',
|
||||
projectInfo: null,
|
||||
customerType: null,
|
||||
companyProfile: null,
|
||||
complianceScope: null,
|
||||
sourcePolicy: null,
|
||||
currentPhase: 1,
|
||||
currentStep: 'use-case-assessment',
|
||||
completedSteps,
|
||||
checkpoints: {},
|
||||
importedDocuments: [],
|
||||
gapAnalysis: null,
|
||||
useCases: [],
|
||||
activeUseCase: null,
|
||||
screening: null,
|
||||
@@ -212,9 +233,12 @@ describe('getPhaseCompletionPercentage', () => {
|
||||
consents: [],
|
||||
dsrConfig: null,
|
||||
escalationWorkflows: [],
|
||||
iaceProjects: [],
|
||||
ragCorpusStatus: null,
|
||||
sbom: null,
|
||||
securityIssues: [],
|
||||
securityBacklog: [],
|
||||
customCatalogs: {},
|
||||
commandBarHistory: [],
|
||||
recentSearches: [],
|
||||
preferences: {
|
||||
@@ -226,7 +250,7 @@ describe('getPhaseCompletionPercentage', () => {
|
||||
autoValidate: true,
|
||||
allowParallelWork: true,
|
||||
},
|
||||
})
|
||||
}) as SDKState
|
||||
|
||||
it('should return 0 for Phase 1 with no completed steps', () => {
|
||||
const state = createMockState([])
|
||||
|
||||
@@ -17,12 +17,13 @@ import type {
|
||||
} from './compliance-scope-types'
|
||||
import {
|
||||
getDepthLevelNumeric,
|
||||
DOCUMENT_SCOPE_MATRIX,
|
||||
DOCUMENT_SCOPE_MATRIX_CORE,
|
||||
DOCUMENT_TYPE_LABELS,
|
||||
DOCUMENT_SDK_STEP_MAP,
|
||||
} from './compliance-scope-types'
|
||||
import { HARD_TRIGGER_RULES } from './compliance-scope-triggers'
|
||||
|
||||
import { DOCUMENT_SDK_STEP_MAP } from "./compliance-scope-sdk-step-map"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -88,7 +89,7 @@ export function normalizeDocType(raw: string): ScopeDocumentType | null {
|
||||
STREITBEILEGUNG: 'streitbeilegung',
|
||||
PRODUKTSICHERHEIT: 'produktsicherheit',
|
||||
}
|
||||
if (raw in DOCUMENT_SCOPE_MATRIX) return raw as ScopeDocumentType
|
||||
if (raw in DOCUMENT_SCOPE_MATRIX_CORE) return raw as ScopeDocumentType
|
||||
return mapping[raw] ?? null
|
||||
}
|
||||
|
||||
@@ -159,11 +160,11 @@ export function buildDocumentScope(
|
||||
}
|
||||
}
|
||||
|
||||
for (const docType of Object.keys(DOCUMENT_SCOPE_MATRIX) as ScopeDocumentType[]) {
|
||||
const requirement = DOCUMENT_SCOPE_MATRIX[docType][level]
|
||||
for (const docType of Object.keys(DOCUMENT_SCOPE_MATRIX_CORE) as ScopeDocumentType[]) {
|
||||
const depthReq = DOCUMENT_SCOPE_MATRIX_CORE[docType]?.[level]
|
||||
const isMandatoryFromTrigger = mandatoryFromTriggers.has(docType)
|
||||
|
||||
if (requirement === 'mandatory' || isMandatoryFromTrigger) {
|
||||
if ((depthReq?.required) || isMandatoryFromTrigger) {
|
||||
const originDocs = triggerDocOrigins.get(docType) ?? []
|
||||
requiredDocs.push({
|
||||
documentType: docType,
|
||||
@@ -178,7 +179,7 @@ export function buildDocumentScope(
|
||||
.map((t) => t.ruleId)
|
||||
: [],
|
||||
})
|
||||
} else if (requirement === 'recommended') {
|
||||
} else if (depthReq && !depthReq.required) {
|
||||
requiredDocs.push({
|
||||
documentType: docType,
|
||||
label: DOCUMENT_TYPE_LABELS[docType],
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { ScopeDocumentType } from './compliance-scope-types'
|
||||
|
||||
export const DOCUMENT_SDK_STEP_MAP: Partial<Record<ScopeDocumentType, string>> = {
|
||||
vvt: '/sdk/vvt', tom: '/sdk/tom', dsfa: '/sdk/dsfa', lf: '/sdk/loeschfristen',
|
||||
dsi: '/sdk/document-generator', av_vertrag: '/sdk/document-generator',
|
||||
vertragsmanagement: '/sdk/document-generator', widerrufsbelehrung: '/sdk/document-generator',
|
||||
preisangaben: '/sdk/document-generator', fernabsatz_info: '/sdk/document-generator',
|
||||
streitbeilegung: '/sdk/document-generator', produktsicherheit: '/sdk/document-generator',
|
||||
betroffenenrechte: '/sdk/dsr', einwilligung: '/sdk/consent-management',
|
||||
}
|
||||
@@ -54,6 +54,10 @@ export interface HardTriggerRule {
|
||||
excludeWhen?: { questionId: string; value: string | string[] };
|
||||
/** Regel feuert NUR wenn diese Bedingung zutrifft */
|
||||
requireWhen?: { questionId: string; value: string | string[] };
|
||||
/** Kombiniert mit Maschinenbau-Profil? Boolean oder Objekt mit Feldbedingung */
|
||||
combineWithMachineBuilder?: boolean | { field: string; value?: unknown; includes?: string };
|
||||
/** Risikogewicht (0-1) */
|
||||
riskWeight?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,4 +78,10 @@ export interface TriggeredHardTrigger {
|
||||
requiresDSFA: boolean;
|
||||
/** Pflichtdokumente */
|
||||
mandatoryDocuments: string[];
|
||||
/** Original-Regel (optional) */
|
||||
rule?: HardTriggerRule;
|
||||
/** Matching-Wert */
|
||||
matchedValue?: unknown;
|
||||
/** Erklaerung */
|
||||
explanation?: string;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ describe('DOCUMENT_RAG_CONFIG', () => {
|
||||
})
|
||||
|
||||
it('should have DSFA mapped to bp_dsfa_corpus', () => {
|
||||
expect(DOCUMENT_RAG_CONFIG.dsfa.collection).toBe('bp_dsfa_corpus')
|
||||
expect(DOCUMENT_RAG_CONFIG.dsfa!.collection).toBe('bp_dsfa_corpus')
|
||||
})
|
||||
|
||||
it('should have unique queries for each document type', () => {
|
||||
|
||||
Reference in New Issue
Block a user