feat(cra): Maßnahmen-Provenienz + Lizenzklasse je Normquelle

Jede Normreferenz einer Maßnahme wird lizenzklassifiziert (eu_law /
public_domain / open / paid_reference) — paid-reference-Normen werden nur als
Verweis geführt, nie im Text gespeichert (idea/expression). Kuratierte
Maßnahmen tragen Tier 'core', KI-/Fallback-Maßnahmen 'review' (indikativ).
Frontend zeigt Quellen-Badges + "indikativ"-Kennzeichnung. Methodik in
docs-src/development/mapping-methodology.md (Szenario C, Due-Diligence).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-16 10:10:20 +02:00
parent 6c619ecc42
commit 7a4f086151
8 changed files with 204 additions and 3 deletions
@@ -48,8 +48,23 @@ function FindingDetail({ f, measuresById }: { f: CRAFinding; measuresById: Recor
return (
<li key={mid} className="text-sm text-gray-700 dark:text-gray-200">
<span className="font-medium">{m ? m.name : mid}</span>
{m?.tier === 'review' && (
<span title="KI-vorgeschlagen mit DSB/Auditor verifizieren" className="ml-1 rounded bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300 px-1 py-0.5 text-[11px]">indikativ</span>
)}
{m?.description ? <span className="text-gray-500"> — {m.description}</span> : null}
{m?.norm_refs?.length ? <span className="text-gray-400"> · {m.norm_refs.join(', ')}</span> : null}
{m?.norm_sources?.length ? (
<span className="mt-1 flex flex-wrap gap-1">
{m.norm_sources.map((s) => (
<span key={s.ref} title={s.label}
className={`rounded px-1.5 py-0.5 text-[11px] ${
s.license_class === 'paid_reference'
? 'bg-amber-50 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300'
: 'bg-emerald-50 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300'}`}>
{s.ref}{s.license_class === 'paid_reference' ? ' · nur Verweis' : ''}
</span>
))}
</span>
) : (m?.norm_refs?.length ? <span className="text-gray-400"> · {m.norm_refs.join(', ')}</span> : null)}
</li>
)
})}
@@ -72,6 +72,9 @@ function merge(live: any): CRADemo {
name: om.name || DEMO_SCENARIO.open_measures.find((d) => d.id === om.id)?.name || om.id,
description: om.description || '',
norm_refs: om.norm_refs || [],
norm_sources: om.norm_sources || [],
tier: om.tier,
provenance: om.provenance,
}))
return {
@@ -39,11 +39,16 @@ export interface CRAFinding {
objective?: string
}
export interface NormSource { ref: string; license_class: string; label: string }
export interface Measure {
id: string
name: string
description: string
norm_refs: string[]
norm_sources?: NormSource[] // license-classified refs (provenance)
tier?: string // core (validated) | review (indicative)
provenance?: string
}
export interface CrossLink {