Compare commits
2 Commits
407a9503e4
...
128967fa3d
| Author | SHA1 | Date | |
|---|---|---|---|
| 128967fa3d | |||
| baca0f6b80 |
@@ -46,7 +46,7 @@ function groupChecks(checks: CheckItem[]): GroupedCheck[] {
|
||||
}))
|
||||
}
|
||||
|
||||
function CheckIcon({ passed, skipped }: { passed: boolean; skipped?: boolean }) {
|
||||
function CheckIcon({ passed, skipped, isInfo }: { passed: boolean; skipped?: boolean; isInfo?: boolean }) {
|
||||
if (skipped) {
|
||||
return (
|
||||
<svg className="w-4 h-4 text-gray-300 mt-0.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
@@ -61,6 +61,13 @@ function CheckIcon({ passed, skipped }: { passed: boolean; skipped?: boolean })
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
if (isInfo) {
|
||||
return (
|
||||
<svg className="w-4 h-4 text-gray-400 mt-0.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<svg className="w-4 h-4 text-red-500 mt-0.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
@@ -104,8 +111,9 @@ export function ChecklistView({ results }: { results: DocResult[] }) {
|
||||
const typeLabel = DOC_TYPE_LABELS[r.doc_type] || r.doc_type
|
||||
const grouped = groupChecks(r.checks)
|
||||
const l1Checks = r.checks.filter(c => (c.level ?? 1) === 1)
|
||||
const l1Scoreable = l1Checks.filter(c => c.severity !== 'INFO')
|
||||
const l2Active = r.checks.filter(c => (c.level ?? 1) === 2 && !c.skipped)
|
||||
const l1Passed = l1Checks.filter(c => c.passed).length
|
||||
const l1Passed = l1Scoreable.filter(c => c.passed).length
|
||||
const l2Passed = l2Active.filter(c => c.passed).length
|
||||
|
||||
return (
|
||||
@@ -126,7 +134,7 @@ export function ChecklistView({ results }: { results: DocResult[] }) {
|
||||
<div className="text-sm font-medium text-gray-900 truncate">{r.label}</div>
|
||||
<div className="text-xs text-gray-500 truncate">
|
||||
{l1Checks.length > 0
|
||||
? `${l1Passed}/${l1Checks.length} Pflichtangaben`
|
||||
? `${l1Passed}/${l1Scoreable.length} Pflichtangaben`
|
||||
+ (l2Active.length > 0 ? `, ${l2Passed}/${l2Active.length} Detailpruefungen` : '')
|
||||
: r.url}
|
||||
</div>
|
||||
@@ -164,13 +172,18 @@ export function ChecklistView({ results }: { results: DocResult[] }) {
|
||||
<p className="text-sm text-red-600">{r.error}</p>
|
||||
) : (
|
||||
<div className="space-y-1">
|
||||
{grouped.map((g) => (
|
||||
{grouped.map((g) => {
|
||||
const l1Info = g.check.severity === 'INFO' && !g.check.passed
|
||||
return (
|
||||
<div key={g.check.id}>
|
||||
{/* L1 check */}
|
||||
<div className="flex items-start gap-2">
|
||||
<CheckIcon passed={g.check.passed} />
|
||||
<CheckIcon passed={g.check.passed} isInfo={l1Info} />
|
||||
<div className="flex-1">
|
||||
<div className={`text-sm ${g.check.passed ? 'text-gray-700' : 'text-red-700 font-medium'}`}>
|
||||
<div className={`text-sm ${
|
||||
g.check.passed ? 'text-gray-700'
|
||||
: l1Info ? 'text-gray-500' : 'text-red-700 font-medium'
|
||||
}`}>
|
||||
{g.check.label}
|
||||
{g.children.length > 0 && <L2Summary>{g.children}</L2Summary>}
|
||||
</div>
|
||||
@@ -180,7 +193,7 @@ export function ChecklistView({ results }: { results: DocResult[] }) {
|
||||
</div>
|
||||
)}
|
||||
{!g.check.passed && g.check.hint && (
|
||||
<div className="text-xs text-red-600/80 mt-0.5">
|
||||
<div className={`text-xs mt-0.5 ${l1Info ? 'text-gray-400' : 'text-red-600/80'}`}>
|
||||
{g.check.hint}
|
||||
</div>
|
||||
)}
|
||||
@@ -190,13 +203,16 @@ export function ChecklistView({ results }: { results: DocResult[] }) {
|
||||
{/* L2 children — always visible */}
|
||||
{g.children.length > 0 && (
|
||||
<div className="ml-6 mt-0.5 mb-1 space-y-0.5 border-l-2 border-gray-200 pl-3">
|
||||
{g.children.map((ch) => (
|
||||
{g.children.map((ch) => {
|
||||
const chInfo = ch.severity === 'INFO' && !ch.passed && !ch.skipped
|
||||
return (
|
||||
<div key={ch.id} className="flex items-start gap-2">
|
||||
<CheckIcon passed={ch.passed} skipped={ch.skipped} />
|
||||
<CheckIcon passed={ch.passed} skipped={ch.skipped} isInfo={chInfo} />
|
||||
<div className="flex-1">
|
||||
<div className={`text-xs ${
|
||||
ch.skipped ? 'text-gray-400 italic'
|
||||
: ch.passed ? 'text-gray-600' : 'text-red-600 font-medium'
|
||||
: ch.passed ? 'text-gray-600'
|
||||
: chInfo ? 'text-gray-400' : 'text-red-600 font-medium'
|
||||
}`}>
|
||||
{ch.label}
|
||||
{ch.skipped && ' (uebersprungen)'}
|
||||
@@ -207,17 +223,19 @@ export function ChecklistView({ results }: { results: DocResult[] }) {
|
||||
</div>
|
||||
)}
|
||||
{!ch.passed && !ch.skipped && ch.hint && (
|
||||
<div className="text-xs text-red-500/80 mt-0.5">
|
||||
<div className={`text-xs mt-0.5 ${chInfo ? 'text-gray-400' : 'text-red-500/80'}`}>
|
||||
{ch.hint}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
{r.word_count > 0 && (
|
||||
<div className="text-xs text-gray-400 mt-2 pt-2 border-t border-gray-200">
|
||||
{r.word_count} Woerter analysiert
|
||||
|
||||
@@ -6,6 +6,56 @@
|
||||
|
||||
---
|
||||
|
||||
## Bestehende Use Cases (WICHTIG — darauf aufbauen!)
|
||||
|
||||
Wir haben bereits 3 Use Cases gebaut, jeder mit anderem Ansatz:
|
||||
|
||||
### 1. IACE CE-Compliance (`/sdk/iace`)
|
||||
- **Ansatz:** Deterministisch, kein LLM
|
||||
- **Technologie:** Tag-basiertes Pattern Matching (Go), 1.114 Hazard Patterns, 476 Maßnahmen
|
||||
- **Flow:** Narrative Text → Parser → Tags → PatternEngine → Hazards → Mitigations → Tech-File
|
||||
- **Pfad:** `ai-compliance-sdk/internal/iace/`
|
||||
- **Learnings:** Pattern Matching skaliert und ist reproduzierbar. Kein LLM nötig für strukturierte Domänen.
|
||||
|
||||
### 2. Doc-Check Agent (`/sdk/agent`)
|
||||
- **Ansatz:** LLM-gesteuert (ZeroClaw-artig)
|
||||
- **Technologie:** LLM mit Tool Calling, RAG-Suche, binäre Prüffragen
|
||||
- **Flow:** Dokument hochladen → LLM prüft gegen Controls → pass/fail pro Frage → Report
|
||||
- **Pfad:** `backend-compliance/compliance/api/agent_doc_check_routes.py`
|
||||
- **Learnings:** LLM kann Dokumente intelligent prüfen, braucht aber klare check_questions um präzise zu sein.
|
||||
|
||||
### 3. Gap-Analyse (`/sdk/gap-analysis`)
|
||||
- **Ansatz:** Regelbasiert, kein LLM
|
||||
- **Technologie:** Go Classifier + SQL-Queries gegen MCs + Priority Engine
|
||||
- **Flow:** Produkt-Profil → Regulatory Classification → MC-Filter → IST-Zustand Assessment → Prioritätsliste
|
||||
- **Pfad:** `ai-compliance-sdk/internal/gap/`
|
||||
- **Learnings:** IST-Zustand (Normen, Zertifizierungen, Prozesse) reduziert Gaps massiv. Ohne IST = 500 Gaps, mit IST = 308.
|
||||
|
||||
### Was der Use-Case Compiler davon übernimmt
|
||||
|
||||
| Von | Übernehmen |
|
||||
|-----|-----------|
|
||||
| **IACE** | Deterministisches Pattern Matching für strukturierte Fragen, Completeness Gates als Vorlage |
|
||||
| **Doc-Check Agent** | LLM-basierte Verifikation für unstrukturierte Fragen, Tool Calling Pattern |
|
||||
| **Gap-Analyse** | MC-Filtering nach Regulation + Scope, IST-Zustand Assessment, Priority Engine |
|
||||
| **Alle drei** | Das generische Frontend-Pattern (Wizard → Fragebogen → Result) |
|
||||
|
||||
### Der Compiler ist die GENERALISIERUNG
|
||||
|
||||
IACE funktioniert nur für CE/Maschinen. Doc-Check nur für Dokumente. Gap-Analyse zeigt Gaps aber keine konkreten Fragen. Der Use-Case Compiler kombiniert alle drei Ansätze in einem generischen System das JEDEN Use Case bedienen kann:
|
||||
|
||||
```
|
||||
IACE (deterministisch) + Doc-Check (LLM) + Gap-Analyse (regelbasiert)
|
||||
↓ ↓ ↓
|
||||
Pattern Matching LLM-Verifikation MC-Filtering + IST
|
||||
↓ ↓ ↓
|
||||
└──────────── Use-Case Compiler ──────────────────────┘
|
||||
↓
|
||||
Generischer Fragebogen für JEDEN Use Case
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
Die 13.588 MCs sind eine Wissensbasis, aber kein Produkt. Wenn ein Nutzer "Vendor Check" machen will, bekommt er 4.036 Controls — aber keine konkreten Fragen, keinen Fragebogen, keine Nachweissammlung.
|
||||
|
||||
Reference in New Issue
Block a user