@euconform/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/LICENSE +21 -0
  3. package/dist/fairness-metrics.d.ts +65 -0
  4. package/dist/fairness-metrics.d.ts.map +1 -0
  5. package/dist/fairness-metrics.js +394 -0
  6. package/dist/index.d.ts +14 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +17 -0
  9. package/dist/inference/browser-inference.d.ts +60 -0
  10. package/dist/inference/browser-inference.d.ts.map +1 -0
  11. package/dist/inference/browser-inference.js +221 -0
  12. package/dist/inference/capability-detection.d.ts +183 -0
  13. package/dist/inference/capability-detection.d.ts.map +1 -0
  14. package/dist/inference/capability-detection.js +552 -0
  15. package/dist/inference/index.d.ts +43 -0
  16. package/dist/inference/index.d.ts.map +1 -0
  17. package/dist/inference/index.js +97 -0
  18. package/dist/inference/inference-factory.d.ts +73 -0
  19. package/dist/inference/inference-factory.d.ts.map +1 -0
  20. package/dist/inference/inference-factory.js +175 -0
  21. package/dist/inference/ollama-client.d.ts +114 -0
  22. package/dist/inference/ollama-client.d.ts.map +1 -0
  23. package/dist/inference/ollama-client.js +386 -0
  24. package/dist/legal-checks/annex-iv-report.d.ts +131 -0
  25. package/dist/legal-checks/annex-iv-report.d.ts.map +1 -0
  26. package/dist/legal-checks/annex-iv-report.js +62 -0
  27. package/dist/legal-checks/bias-metrics.d.ts +162 -0
  28. package/dist/legal-checks/bias-metrics.d.ts.map +1 -0
  29. package/dist/legal-checks/bias-metrics.js +408 -0
  30. package/dist/legal-checks/data-governance.d.ts +30 -0
  31. package/dist/legal-checks/data-governance.d.ts.map +1 -0
  32. package/dist/legal-checks/data-governance.js +99 -0
  33. package/dist/legal-checks/human-oversight-logging.d.ts +27 -0
  34. package/dist/legal-checks/human-oversight-logging.d.ts.map +1 -0
  35. package/dist/legal-checks/human-oversight-logging.js +106 -0
  36. package/dist/legal-checks/index.d.ts +13 -0
  37. package/dist/legal-checks/index.d.ts.map +1 -0
  38. package/dist/legal-checks/index.js +6 -0
  39. package/dist/legal-checks/risk-classifier.d.ts +35 -0
  40. package/dist/legal-checks/risk-classifier.d.ts.map +1 -0
  41. package/dist/legal-checks/risk-classifier.js +234 -0
  42. package/dist/legal-checks/robustness-transparency.d.ts +45 -0
  43. package/dist/legal-checks/robustness-transparency.d.ts.map +1 -0
  44. package/dist/legal-checks/robustness-transparency.js +111 -0
  45. package/dist/metrics/crows-pairs-bias.d.ts +41 -0
  46. package/dist/metrics/crows-pairs-bias.d.ts.map +1 -0
  47. package/dist/metrics/crows-pairs-bias.js +172 -0
  48. package/dist/metrics/index.d.ts +6 -0
  49. package/dist/metrics/index.d.ts.map +1 -0
  50. package/dist/metrics/index.js +5 -0
  51. package/dist/metrics/stereotype-bias.d.ts +89 -0
  52. package/dist/metrics/stereotype-bias.d.ts.map +1 -0
  53. package/dist/metrics/stereotype-bias.js +157 -0
  54. package/dist/risk-engine.d.ts +23 -0
  55. package/dist/risk-engine.d.ts.map +1 -0
  56. package/dist/risk-engine.js +451 -0
  57. package/dist/types.d.ts +131 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +5 -0
  60. package/package.json +28 -0
  61. package/src/fairness-metrics.ts +498 -0
  62. package/src/index.ts +150 -0
  63. package/src/inference/browser-inference.ts +258 -0
  64. package/src/inference/capability-detection.ts +714 -0
  65. package/src/inference/index.ts +156 -0
  66. package/src/inference/inference-factory.ts +222 -0
  67. package/src/inference/ollama-client.ts +514 -0
  68. package/src/inference/transformers.d.ts +62 -0
  69. package/src/legal-checks/annex-iv-report.ts +157 -0
  70. package/src/legal-checks/bias-metrics.ts +590 -0
  71. package/src/legal-checks/data-governance.ts +148 -0
  72. package/src/legal-checks/human-oversight-logging.ts +135 -0
  73. package/src/legal-checks/index.ts +55 -0
  74. package/src/legal-checks/risk-classifier.ts +285 -0
  75. package/src/legal-checks/robustness-transparency.ts +162 -0
  76. package/src/metrics/crows-pairs-bias.ts +245 -0
  77. package/src/metrics/index.ts +22 -0
  78. package/src/metrics/stereotype-bias.ts +267 -0
  79. package/src/risk-engine.ts +525 -0
  80. package/src/types.ts +154 -0
  81. package/tests/annex-iv-report.test.ts +323 -0
  82. package/tests/crows-pairs-bias.test.ts +342 -0
  83. package/tests/fairness-metrics.test.ts +187 -0
  84. package/tests/integration/bias-calculation.integration.test.ts +688 -0
  85. package/tests/legal-checks.test.ts +53 -0
  86. package/tests/ollama-client.test.ts +427 -0
  87. package/tests/risk-engine.test.ts +149 -0
  88. package/tsconfig.json +11 -0
  89. package/vitest.config.ts +17 -0
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Article 10(3–4) – Data Governance & Data Quality Checklist (evidence-oriented)
3
+ *
4
+ * This produces a structured checklist that can be included in Annex IV documentation.
5
+ * It is not a legal determination.
6
+ */
7
+
8
+ import type { Citation } from "./bias-metrics";
9
+
10
+ export type ChecklistStatus = "yes" | "no" | "partial" | "unknown";
11
+
12
+ export interface DataGovernanceChecklistItem {
13
+ id: string;
14
+ question: string;
15
+ rationale: string;
16
+ status: ChecklistStatus;
17
+ evidence?: string;
18
+ risksIfNo: string[];
19
+ }
20
+
21
+ export interface DataGovernanceChecklistResult {
22
+ timestamp: string;
23
+ items: DataGovernanceChecklistItem[];
24
+ overall: {
25
+ missingCriticalCount: number;
26
+ notes: string[];
27
+ };
28
+ sources: Citation[];
29
+ }
30
+
31
+ export function runDataGovernanceChecklist(input: {
32
+ statuses: Record<string, ChecklistStatus>;
33
+ evidence?: Record<string, string>;
34
+ }): DataGovernanceChecklistResult {
35
+ const sources: Citation[] = [
36
+ { label: "EU AI Act", reference: "Verordnung (EU) 2024/1689" },
37
+ {
38
+ label: "Art. 10(3–4)",
39
+ reference:
40
+ "Data governance / data quality expectations (repräsentativ, fehlerarm, dokumentiert)",
41
+ },
42
+ {
43
+ label: "Recital 54",
44
+ reference: "Schutz vor Diskriminierung & historische Bias/Feedback-Loops",
45
+ },
46
+ ];
47
+
48
+ const items: Omit<DataGovernanceChecklistItem, "status" | "evidence">[] = [
49
+ {
50
+ id: "representativeness",
51
+ question:
52
+ "Ist das Trainings-/Validierungsdataset für den vorgesehenen Einsatzkontext repräsentativ?",
53
+ rationale:
54
+ "Nicht-repräsentative Daten erhöhen Fehlerraten und können Diskriminierung verstärken (insb. unterrepräsentierte Gruppen).",
55
+ risksIfNo: [
56
+ "Systematische Fehlklassifikation für Teilpopulationen",
57
+ "Disparate impact / unfaire Fehlerverteilung",
58
+ "Fehlende Generalisierung im Deployment-Kontext",
59
+ ],
60
+ },
61
+ {
62
+ id: "data_quality_errors",
63
+ question:
64
+ "Sind Datenqualität (Fehler, Duplikate, Ausreißer, Missingness) gemessen und adressiert?",
65
+ rationale:
66
+ "Mess-/Label-Fehler und fehlende Daten sind häufige Ursachen für Bias und Instabilität in Modellen.",
67
+ risksIfNo: [
68
+ "Verzerrte Lernsignale und spurious correlations",
69
+ "Instabile Performance bei Drift",
70
+ "Unklare Fehlerursachen im Incident-Fall",
71
+ ],
72
+ },
73
+ {
74
+ id: "labeling_process",
75
+ question:
76
+ "Ist der Labeling-/Annotation- und QA-Prozess dokumentiert (Guidelines, Inter-Annotator Agreement)?",
77
+ rationale:
78
+ "Reproduzierbarkeit und Auditierbarkeit hängen von nachvollziehbarer Annotation ab.",
79
+ risksIfNo: [
80
+ "Nicht-reproduzierbare Labels",
81
+ "Bias durch uneinheitliche Annotation",
82
+ "Schwierige Fehleranalyse im Betrieb",
83
+ ],
84
+ },
85
+ {
86
+ id: "sensitive_attributes_handling",
87
+ question:
88
+ "Ist der Umgang mit sensiblen Attributen (z. B. Geschlecht, Ethnie, Alter, Behinderung, Religion, sexuelle Orientierung) definiert und begründet?",
89
+ rationale:
90
+ "Für Bias-Analysen sind Gruppenproxies/Attribute oft nötig; zugleich müssen Verarbeitung und Minimierung begründet und dokumentiert werden.",
91
+ risksIfNo: [
92
+ "Bias bleibt unmessbar / unsichtbar",
93
+ "Fehlende Nachvollziehbarkeit der Fairness-Tests",
94
+ "Unklare Proxy-Risiken und Messfehler",
95
+ ],
96
+ },
97
+ {
98
+ id: "feedback_loops",
99
+ question: "Sind historische Bias und mögliche Feedback-Loops identifiziert und mitigiert?",
100
+ rationale:
101
+ "Modelle können bestehende Ungleichheiten verstärken, wenn Outputs in die Datenerzeugung zurückfließen.",
102
+ risksIfNo: [
103
+ "Self-fulfilling bias / reinforcement",
104
+ "Verschlechterung über Zeit trotz kurzfristiger Performance",
105
+ "Fehlender Nachweis wirksamer Mitigation",
106
+ ],
107
+ },
108
+ {
109
+ id: "dataset_documentation",
110
+ question:
111
+ "Existiert eine Dataset-Dokumentation (Herkunft, Zeiträume, Lizenz, Sampling, Preprocessing, Versionierung, Known Limitations)?",
112
+ rationale:
113
+ "Annex-IV-fähige Dokumentation erfordert nachvollziehbare Datenherkunft und Versionsstände.",
114
+ risksIfNo: [
115
+ "Nicht-auditierbare Datenpipeline",
116
+ "Unklare Lizenz-/Nutzungsrisiken",
117
+ "Nicht reproduzierbare Trainingsläufe",
118
+ ],
119
+ },
120
+ ];
121
+
122
+ const evidence = input.evidence ?? {};
123
+ const built: DataGovernanceChecklistItem[] = items.map((it) => ({
124
+ ...it,
125
+ status: input.statuses[it.id] ?? "unknown",
126
+ evidence: evidence[it.id],
127
+ }));
128
+
129
+ const missingCriticalCount = built.filter(
130
+ (i) => i.status === "no" || i.status === "unknown"
131
+ ).length;
132
+ const notes: string[] = [];
133
+ if (missingCriticalCount > 0) {
134
+ notes.push(
135
+ "Mehrere Data-Governance-Punkte sind offen/negativ. Für Annex-IV-Dokumentation sollten Evidenzen, Messmethoden und Mitigationen ergänzt werden."
136
+ );
137
+ }
138
+ notes.push(
139
+ "Hinweis: Historische Bias und Feedback-Loops sollten explizit beschrieben und mit Monitoring adressiert werden."
140
+ );
141
+
142
+ return {
143
+ timestamp: new Date().toISOString(),
144
+ items: built,
145
+ overall: { missingCriticalCount, notes },
146
+ sources,
147
+ };
148
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Article 12 + 14 – Logging & Human Oversight (templates + prompts for evidence)
3
+ *
4
+ * Output is intentionally operational/technical. It is not legal advice.
5
+ */
6
+
7
+ import type { RiskLevel } from "../types";
8
+ import type { Citation } from "./bias-metrics";
9
+
10
+ export interface LoggingTemplate {
11
+ retention: {
12
+ recommendedMinimum: string;
13
+ note: string;
14
+ };
15
+ fields: Array<{
16
+ key: string;
17
+ type: string;
18
+ description: string;
19
+ required: boolean;
20
+ }>;
21
+ }
22
+
23
+ export interface HumanOversightRecommendation {
24
+ level: RiskLevel;
25
+ recommendations: string[];
26
+ loggingTemplate: LoggingTemplate;
27
+ sources: Citation[];
28
+ }
29
+
30
+ export function getHumanOversightAndLoggingTemplate(
31
+ level: RiskLevel
32
+ ): HumanOversightRecommendation {
33
+ const sources: Citation[] = [
34
+ { label: "EU AI Act", reference: "Verordnung (EU) 2024/1689" },
35
+ { label: "Art. 14", reference: "Human oversight (wirksame Aufsicht, Override, Kompetenz)" },
36
+ { label: "Art. 12", reference: "Logging / Ereignisprotokollierung (Nachvollziehbarkeit)" },
37
+ ];
38
+
39
+ const baseLogging: LoggingTemplate = {
40
+ retention: {
41
+ recommendedMinimum: "6 Monate (Template-Empfehlung)",
42
+ note: "Aufbewahrungsdauer ist kontextabhängig; dieses Tool gibt keine Rechtsberatung.",
43
+ },
44
+ fields: [
45
+ {
46
+ key: "timestamp",
47
+ type: "string (ISO-8601)",
48
+ description: "Zeitpunkt der Entscheidung",
49
+ required: true,
50
+ },
51
+ {
52
+ key: "system_version",
53
+ type: "string",
54
+ description: "Modell/Artefakt-Version, Hash, Konfiguration",
55
+ required: true,
56
+ },
57
+ {
58
+ key: "input_reference",
59
+ type: "string",
60
+ description: "Referenz auf Input (pseudonymisiert/ID), nicht Rohdaten",
61
+ required: true,
62
+ },
63
+ {
64
+ key: "output",
65
+ type: "object|string",
66
+ description: "Systemoutput (Entscheidung/Score/Antwort)",
67
+ required: true,
68
+ },
69
+ {
70
+ key: "confidence",
71
+ type: "number",
72
+ description: "Konfidenz/Score falls vorhanden",
73
+ required: false,
74
+ },
75
+ {
76
+ key: "protected_attribute_proxy_used",
77
+ type: "boolean",
78
+ description: "Wurden Proxies für Fairness-Messung genutzt?",
79
+ required: false,
80
+ },
81
+ {
82
+ key: "human_review",
83
+ type: "object",
84
+ description: "Human-in-the-loop: reviewer_id, action, rationale",
85
+ required: false,
86
+ },
87
+ {
88
+ key: "override",
89
+ type: "boolean",
90
+ description: "Wurde die AI-Ausgabe überstimmt?",
91
+ required: false,
92
+ },
93
+ {
94
+ key: "override_reason",
95
+ type: "string",
96
+ description: "Begründung für Override",
97
+ required: false,
98
+ },
99
+ {
100
+ key: "appeal_or_complaint",
101
+ type: "boolean",
102
+ description: "Gab es Einspruch/Beschwerde?",
103
+ required: false,
104
+ },
105
+ {
106
+ key: "incident_flag",
107
+ type: "boolean",
108
+ description: "Incident/Anomaly markiert",
109
+ required: false,
110
+ },
111
+ ],
112
+ };
113
+
114
+ const recs: Record<RiskLevel, string[]> = {
115
+ unacceptable: [
116
+ "System nicht deployen, bis Red-Flags geklärt sind (technischer Hinweis, keine Rechtsberatung).",
117
+ "Dokumentieren: welche Art.-5-Red-Flags betroffen sind, welche Evidenzen dagegen/ dafür sprechen.",
118
+ ],
119
+ high: [
120
+ "Human-in-the-loop bei allen hochwirksamen Entscheidungen: Review/Override möglich und praktisch nutzbar.",
121
+ "Rollen/Kompetenzen dokumentieren: wer darf überstimmen, Schulung, Eskalationspfade.",
122
+ "Monitoring + Incident-Response: Drift, Bias-Regression, Security, Fehlerraten nach Gruppen.",
123
+ "Logging so gestalten, dass Post-hoc-Audit und Root-Cause-Analyse möglich sind (ohne unnötige personenbezogene Rohdaten).",
124
+ ],
125
+ limited: [
126
+ "Transparenz im UX: Nutzer informieren, wann/wie AI beteiligt ist; klare Feedback-Kanäle.",
127
+ "Stichprobenartige Human Review für Qualitäts-/Bias-Monitoring einplanen.",
128
+ ],
129
+ minimal: [
130
+ "Gute Praxis: Versionierung, grundlegendes Logging (Fehler/Incidents) und periodische Qualitätschecks.",
131
+ ],
132
+ };
133
+
134
+ return { level, recommendations: recs[level], loggingTemplate: baseLogging, sources };
135
+ }
@@ -0,0 +1,55 @@
1
+ export type { AnnexIIIAnswer, AnnexIIIRiskResult } from "./risk-classifier";
2
+ export {
3
+ ANNEX_III_QUESTIONS,
4
+ PROHIBITED_AI_SCREENING_QUESTIONS,
5
+ classifyAnnexIIIRisk,
6
+ getAnnexIIIQuestions,
7
+ getProhibitedAIScreeningQuestions,
8
+ } from "./risk-classifier";
9
+
10
+ export type {
11
+ Citation,
12
+ CounterfactualPair,
13
+ CrowsPairsLogProbOptions,
14
+ CrowsPairsLogProbResult,
15
+ GroupTextSample,
16
+ RegardResult,
17
+ RegardScorer,
18
+ SensitiveAttribute,
19
+ ToxicityResult,
20
+ ToxicityScorer,
21
+ } from "./bias-metrics";
22
+ export {
23
+ AI_ACT_SOURCES,
24
+ METRIC_SOURCES,
25
+ createPerspectiveApiToxicityScorer,
26
+ createTransformersRegardScorer,
27
+ createTransformersToxicityScorer,
28
+ counterfactualFairness,
29
+ demographicParityDifference,
30
+ equalizedOddsDifference,
31
+ runArticle10NumericBiasSuite,
32
+ runCrowsPairsLogProbTest,
33
+ runRegardTest,
34
+ runToxicityTest,
35
+ } from "./bias-metrics";
36
+
37
+ export type { ChecklistStatus, DataGovernanceChecklistResult } from "./data-governance";
38
+ export { runDataGovernanceChecklist } from "./data-governance";
39
+
40
+ export type {
41
+ RobustnessResult,
42
+ RobustnessTestCase,
43
+ Perturbation,
44
+ PredictTextFn,
45
+ } from "./robustness-transparency";
46
+ export {
47
+ defaultTextPerturbations,
48
+ runTextPerturbationRobustnessTest,
49
+ } from "./robustness-transparency";
50
+
51
+ export type { HumanOversightRecommendation, LoggingTemplate } from "./human-oversight-logging";
52
+ export { getHumanOversightAndLoggingTemplate } from "./human-oversight-logging";
53
+
54
+ export type { AnnexIVStructuredReportV1 } from "./annex-iv-report";
55
+ export { buildAnnexIVReportV1 } from "./annex-iv-report";
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Annex III (EU AI Act 2024/1689) High-Risk Classifier
3
+ *
4
+ * Implements:
5
+ * - Article 6–7: risk classification logic (high-risk if any Annex III category applies)
6
+ * - Annex III: 8 high-risk categories (questionnaire)
7
+ * - Article 5: optional prohibited-AI “red flag” screening (informational only)
8
+ *
9
+ * IMPORTANT: This module provides technical orientation, not legal advice.
10
+ */
11
+
12
+ import type { HighRiskCategory, QuizAnswer, QuizQuestion, RiskFlag, RiskLevel } from "../types";
13
+
14
+ export type AnnexIIIAnswer = "yes" | "no" | "unsure";
15
+
16
+ export interface AnnexIIIRiskResult {
17
+ level: RiskLevel;
18
+ matchedCategories: HighRiskCategory[];
19
+ prohibitedFlags: RiskFlag[];
20
+ legalBasis: string[];
21
+ notes: string[];
22
+ }
23
+
24
+ /**
25
+ * Exactly the 8 Annex III high-risk categories as a yes/no questionnaire.
26
+ * If any answer is "yes" -> high-risk.
27
+ *
28
+ * NOTE: The wording is intentionally neutral and evidence-oriented.
29
+ */
30
+ export const ANNEX_III_QUESTIONS: QuizQuestion[] = [
31
+ {
32
+ id: "annexIII-biometric-identification",
33
+ question: "Annex III: Biometrische Identifizierung/Kategorisierung?",
34
+ description:
35
+ "Wird das System für biometrische Identifizierung oder biometrische Kategorisierung von natürlichen Personen eingesetzt (z. B. Gesicht, Stimme, Gang)?",
36
+ options: [
37
+ { value: "yes", label: "Ja", riskIndicator: "high" },
38
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
39
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
40
+ ],
41
+ },
42
+ {
43
+ id: "annexIII-critical-infrastructure",
44
+ question: "Annex III: Kritische Infrastruktur?",
45
+ description:
46
+ "Wird das System für Betrieb/Management kritischer Infrastruktur eingesetzt (z. B. Energie, Wasser, Verkehr), wo Fehlfunktionen Leben/Gesundheit gefährden können?",
47
+ options: [
48
+ { value: "yes", label: "Ja", riskIndicator: "high" },
49
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
50
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
51
+ ],
52
+ },
53
+ {
54
+ id: "annexIII-education-training",
55
+ question: "Annex III: Bildung & berufliche Ausbildung?",
56
+ description:
57
+ "Unterstützt das System Entscheidungen in Bildung/Training (z. B. Zulassung, Bewertung, Prüfung), die den Bildungsweg wesentlich beeinflussen?",
58
+ options: [
59
+ { value: "yes", label: "Ja", riskIndicator: "high" },
60
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
61
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
62
+ ],
63
+ },
64
+ {
65
+ id: "annexIII-employment-workers",
66
+ question: "Annex III: Beschäftigung/Recruiting/Worker Management?",
67
+ description:
68
+ "Wird das System in Recruiting, Personalentscheidungen, Leistungsbewertung oder Arbeitssteuerung eingesetzt (mit erheblichem Einfluss auf Beschäftigte/Bewerbende)?",
69
+ options: [
70
+ { value: "yes", label: "Ja", riskIndicator: "high" },
71
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
72
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
73
+ ],
74
+ },
75
+ {
76
+ id: "annexIII-essential-services",
77
+ question: "Annex III: Zugang zu wesentlichen Diensten/Vorteilen?",
78
+ description:
79
+ "Wird das System für Zugang/Anspruch/Preisgestaltung wesentlicher privater/öffentlicher Dienste genutzt (z. B. Kredit, Versicherung, Sozialleistungen, Gesundheitsversorgung)?",
80
+ options: [
81
+ { value: "yes", label: "Ja", riskIndicator: "high" },
82
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
83
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
84
+ ],
85
+ },
86
+ {
87
+ id: "annexIII-law-enforcement",
88
+ question: "Annex III: Strafverfolgung?",
89
+ description:
90
+ "Wird das System in Strafverfolgung eingesetzt (z. B. Risiko-/Gefährdungsbewertung, Beweismittelanalyse, Priorisierung von Ermittlungen)?",
91
+ options: [
92
+ { value: "yes", label: "Ja", riskIndicator: "high" },
93
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
94
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
95
+ ],
96
+ },
97
+ {
98
+ id: "annexIII-migration-asylum",
99
+ question: "Annex III: Migration/Asyl/Grenzkontrolle?",
100
+ description:
101
+ "Wird das System in Migration, Asyl oder Grenzkontrolle eingesetzt (z. B. Risiko-/Eligibility-Bewertungen, Dokumentenprüfung, Priorisierung)?",
102
+ options: [
103
+ { value: "yes", label: "Ja", riskIndicator: "high" },
104
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
105
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
106
+ ],
107
+ },
108
+ {
109
+ id: "annexIII-justice-democracy",
110
+ question: "Annex III: Justiz & demokratische Prozesse?",
111
+ description:
112
+ "Wird das System in der Rechtspflege oder demokratischen Prozessen eingesetzt (z. B. gerichtliche/administrative Entscheidungen, Unterstützung von Rechtsanwendung)?",
113
+ options: [
114
+ { value: "yes", label: "Ja", riskIndicator: "high" },
115
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
116
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
117
+ ],
118
+ },
119
+ ];
120
+
121
+ const QUESTION_ID_TO_CATEGORY: Record<string, HighRiskCategory> = {
122
+ "annexIII-biometric-identification": "biometric-identification",
123
+ "annexIII-critical-infrastructure": "critical-infrastructure",
124
+ "annexIII-education-training": "education-training",
125
+ "annexIII-employment-workers": "employment-workers",
126
+ "annexIII-essential-services": "essential-services",
127
+ "annexIII-law-enforcement": "law-enforcement",
128
+ "annexIII-migration-asylum": "migration-asylum",
129
+ "annexIII-justice-democracy": "justice-democracy",
130
+ };
131
+
132
+ /**
133
+ * Optional “red-flag” screening for potential Article 5 prohibited practices.
134
+ * This is NOT exhaustive and is not a legal determination.
135
+ */
136
+ export const PROHIBITED_AI_SCREENING_QUESTIONS: QuizQuestion[] = [
137
+ {
138
+ id: "art5-subliminal",
139
+ question: "Art. 5: Subliminale/manipulative Techniken?",
140
+ description:
141
+ "Nutzen Sie Techniken außerhalb des Bewusstseins, um Verhalten zu manipulieren, sodass Personen (voraussichtlich) Schaden erleiden könnten?",
142
+ options: [
143
+ { value: "yes", label: "Ja", riskIndicator: "unacceptable" },
144
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
145
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
146
+ ],
147
+ },
148
+ {
149
+ id: "art5-vulnerability",
150
+ question: "Art. 5: Ausnutzung von Vulnerabilität?",
151
+ description:
152
+ "Zielt das System darauf ab, Vulnerabilitäten (z. B. Alter, Behinderung, soziale/ökonomische Lage) auszunutzen, sodass (voraussichtlich) Schaden entsteht?",
153
+ options: [
154
+ { value: "yes", label: "Ja", riskIndicator: "unacceptable" },
155
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
156
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
157
+ ],
158
+ },
159
+ {
160
+ id: "art5-social-scoring",
161
+ question: "Art. 5: Social Scoring durch öffentliche Stellen?",
162
+ description:
163
+ "Wird (oder würde) das System für Social Scoring durch öffentliche Stellen eingesetzt, das zu nachteiliger Behandlung führt?",
164
+ options: [
165
+ { value: "yes", label: "Ja", riskIndicator: "unacceptable" },
166
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
167
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
168
+ ],
169
+ },
170
+ {
171
+ id: "art5-rbi",
172
+ question: "Art. 5: Echtzeit-RBI im öffentlichen Raum ohne Rechtsgrundlage?",
173
+ description:
174
+ "Nutzen Sie Echtzeit-Fernbiometrie-Identifizierung im öffentlichen Raum ohne die dafür vorgesehenen engen Voraussetzungen?",
175
+ options: [
176
+ { value: "yes", label: "Ja", riskIndicator: "unacceptable" },
177
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
178
+ { value: "unsure", label: "Unklar", riskIndicator: "limited" },
179
+ ],
180
+ },
181
+ ];
182
+
183
+ export function getAnnexIIIQuestions(): QuizQuestion[] {
184
+ return ANNEX_III_QUESTIONS;
185
+ }
186
+
187
+ export function getProhibitedAIScreeningQuestions(): QuizQuestion[] {
188
+ return PROHIBITED_AI_SCREENING_QUESTIONS;
189
+ }
190
+
191
+ export function classifyAnnexIIIRisk(answers: QuizAnswer[]): AnnexIIIRiskResult {
192
+ const prohibitedFlags = detectProhibitedRedFlags(answers);
193
+ const matchedCategories: HighRiskCategory[] = [];
194
+
195
+ for (const a of answers) {
196
+ const cat = QUESTION_ID_TO_CATEGORY[a.questionId];
197
+ if (!cat) continue;
198
+ if (a.value === "yes") matchedCategories.push(cat);
199
+ }
200
+
201
+ const isHighRisk = matchedCategories.length > 0;
202
+ const legalBasis: string[] = [];
203
+ const notes: string[] = [];
204
+
205
+ if (prohibitedFlags.length > 0) {
206
+ legalBasis.push("Verordnung (EU) 2024/1689 – Art. 5 (Prohibited AI)");
207
+ notes.push(
208
+ "Hinweis: Art.-5-Flags sind ein technischer Red-Flag-Screen. Für eine rechtsverbindliche Einordnung ist eine eigenständige Prüfung erforderlich."
209
+ );
210
+ }
211
+
212
+ if (isHighRisk) {
213
+ legalBasis.push("Verordnung (EU) 2024/1689 – Art. 6–7 (Risikoklassifizierung)");
214
+ legalBasis.push("Verordnung (EU) 2024/1689 – Annex III (High-Risk Use Cases)");
215
+ notes.push(
216
+ "Logik: Wenn mindestens eine Annex-III-Kategorie zutrifft (Antwort 'Ja'), wird das System hier als High-Risk eingestuft (technische Orientierung)."
217
+ );
218
+ notes.push(
219
+ "Zeitplan-Hinweis: High-Risk-Pflichten treten gestaffelt in Kraft (u. a. ab 2027). Bitte aktuelle Umsetzungsfristen/Guidance prüfen."
220
+ );
221
+ }
222
+
223
+ // This module focuses on Annex III vs. not. “limited” is used for “unsure” signals.
224
+ const anyUnsure = answers.some(
225
+ (a) =>
226
+ a.value === "unsure" &&
227
+ (a.questionId in QUESTION_ID_TO_CATEGORY || a.questionId.startsWith("art5-"))
228
+ );
229
+
230
+ const level: RiskLevel =
231
+ prohibitedFlags.length > 0
232
+ ? "unacceptable"
233
+ : isHighRisk
234
+ ? "high"
235
+ : anyUnsure
236
+ ? "limited"
237
+ : "minimal";
238
+
239
+ return {
240
+ level,
241
+ matchedCategories,
242
+ prohibitedFlags,
243
+ legalBasis,
244
+ notes,
245
+ };
246
+ }
247
+
248
+ function detectProhibitedRedFlags(answers: QuizAnswer[]): RiskFlag[] {
249
+ const flags: RiskFlag[] = [];
250
+ const byId = new Map(answers.map((a) => [a.questionId, a.value] as const));
251
+
252
+ if (byId.get("art5-subliminal") === "yes") {
253
+ flags.push({
254
+ type: "critical",
255
+ message:
256
+ "Möglicher Art.-5-Red-Flag: subliminale/manipulative Techniken mit Schädigungspotential.",
257
+ articleReference: "Art. 5",
258
+ });
259
+ }
260
+ if (byId.get("art5-vulnerability") === "yes") {
261
+ flags.push({
262
+ type: "critical",
263
+ message: "Möglicher Art.-5-Red-Flag: Ausnutzung von Vulnerabilität mit Schädigungspotential.",
264
+ articleReference: "Art. 5",
265
+ });
266
+ }
267
+ if (byId.get("art5-social-scoring") === "yes") {
268
+ flags.push({
269
+ type: "critical",
270
+ message:
271
+ "Möglicher Art.-5-Red-Flag: Social Scoring (öffentliche Stellen) mit nachteiliger Behandlung.",
272
+ articleReference: "Art. 5",
273
+ });
274
+ }
275
+ if (byId.get("art5-rbi") === "yes") {
276
+ flags.push({
277
+ type: "critical",
278
+ message:
279
+ "Möglicher Art.-5-Red-Flag: Echtzeit-Fernbiometrie-Identifizierung im öffentlichen Raum ohne enge Voraussetzungen.",
280
+ articleReference: "Art. 5",
281
+ });
282
+ }
283
+
284
+ return flags;
285
+ }