# Dok 05d — Traceability-Matrix: Anforderung ↔ Risiko ↔ Code ↔ Verifikation (v0)

**Bezug:** IEC 62304 §5.1.1 (Software-Entwicklungsplan — Traceability), §5.5.2
(Verifikation je Anforderung), §7.4 (Risikokontrollmaßnahmen ↔ Software)
**Norm-Kontext:** ISO 14971 Risikomanagement, MDR Anh. I (GSPR §17 — Software)
**Status:** Entwurf v0 — **maschinell aus dem Code-/Doc-Knowledge-Graph abgeleitet**
(graphify). Kein formaler, signierter Traceability-Record.
**Drafting:** Claude (aus Code + Dossier). Validierung durch Regulatory-/QM-Profi
ausstehend.
**Einordnung:** Schließt die in **Dok 05b §4.2** als *kritisch / DiGA-blockierend*
markierte Lücke **„Fehlende Traceability-Matrix (Tests ↔ Anforderungen ↔ Risiken)"**
— in dieser v0 für die sicherheitskritischsten Stränge: **(a) Lyra/Krise**
(Dok 04 R-LYRA-01), **(b) Schutz/Selbstbindung** (R-FALSE-01, R-BYP-03),
**(c) Mail-Schutz** (R-MAIL-01/02/03) und **(d) Anonymität** (R-DATA-07).
Andockpunkte: Dok 03 (Requirements), Dok 04 (Risiko-Akte), Dok 05c (Lyra-Eval),
Spec Protection Coverage & Streak.

---

## 0. Ehrliche Einordnung (bitte zuerst lesen)

Diese Matrix ist **kein** geprüfter Verifikationsnachweis. Sie ist eine aus dem
Knowledge-Graph (`graphify-out/graph.json`) abgeleitete **Erst-Verknüpfung** zwischen
Dossier-Artefakten und tatsächlichen Code-/Test-Symbolen. Jede Zeile trägt ein
Konfidenz-Flag:

- **EXTRACTED (1.0)** — die Quelle benennt das Artefakt **wörtlich** (z. B. nennt die
  Risiko-Akte die Datei `crisis-filter.ts`). Belastbar.
- **INFERRED (0.8–0.95)** — **Modell-Schlussfolgerung** aus funktionaler Übereinstimmung.
  Plausibel, aber **durch einen Menschen zu bestätigen**, bevor sie als Nachweis gilt.

Was hier **fehlt** und für einen formalen IEC-62304-Record noch nötig ist
(vgl. Dok 05b §4.2): Soll-Ergebnis-Definition je Testfall, archiviertes Pass/Fail-
Protokoll mit Build-Version + Datum, sowie die Ausweitung auf die restlichen Stränge
(Onboarding/Streak-Vollabdeckung, Auth/Geräte-Limit). **Der Mail- (§2a) und der
Anonymitäts-Strang (§2c) sind in dieser v0 neu verdrahtet** — beim Anonymitäts-Strang
mit einem ausdrücklich markierten **GAP** (siehe §2c), beim Mail-Strang mit offener
Live-Run-/Provider-Verifikation.

---

## 1. Traceability-Logik (IEC 62304)

```
Anforderung (Dok 03)
  └─ Risiko + Risikomaßnahme (Dok 04, ISO 14971)
        └─ Code-Artefakt (Implementierung der Maßnahme)
              └─ Verifikation (Test + Soll-Metrik, Dok 05b/05c)
```

Für den Lyra-/Krisen-Strang konkret:

```
REQ-LYRA  (Dok 03 — Lyra KI-Coach & Krisen-Behandlung, höchste Sicherheitsrelevanz)
  └─ R-LYRA-01  (Dok 04 — verpasste Krise/Suizidalität, S4, Top-Risiko)
        └─ Maßnahme: Deterministischer Krisen-Keyword-Pre-Filter (crisis-filter.ts)
             ├─ detectCrisis()        backend/server/utils/crisis-filter.ts
             ├─ getCrisisFallback()   backend/server/utils/crisis-filter.ts
             └─ SAFETY-REQ-LLM-001  (Dok 05c — Krisenreferenz-Pflicht, Recall 100 %)
                  └─ Verifikation: crisis-filter.test.ts → Metrik „Crisis-Detection-Recall" (Ziel 100 %)

REQ-LYRA wird realisiert in:
  ├─ CoachScreen()         apps/rebreak-native/app/lyra.tsx        (UI)
  ├─ parseLyraResponse()   apps/rebreak-native/lib/lyraResponse.ts (Reply-Parsing)
  └─ sos-session.post.ts   backend/server/api/coach/               (SOS-Coach-API)
```

---

## 2. Traceability-Matrix — Lyra-/Krisen-Strang (v0)

| DiGA-Artefakt (Anforderung / Risiko / Metrik) | Quelle | → Code-/Test-Artefakt | Datei | Relation | Konfidenz |
|---|---|---|---|---|---|
| REQ-LYRA — Lyra KI-Coach & Krisen-Behandlung | `03-requirements-v0.md` | `detectCrisis()` | `backend/server/utils/crisis-filter.ts` | implementiert durch | INFERRED (0.90) |
| REQ-LYRA — Lyra KI-Coach & Krisen-Behandlung | `03-requirements-v0.md` | `sos-session.post.ts` | `backend/server/api/coach/sos-session.post.ts` | implementiert durch | INFERRED (0.85) |
| REQ-LYRA — Lyra KI-Coach & Krisen-Behandlung | `03-requirements-v0.md` | `CoachScreen()` | `apps/rebreak-native/app/lyra.tsx` | implementiert durch | INFERRED (0.85) |
| REQ-LYRA — Lyra KI-Coach & Krisen-Behandlung | `03-requirements-v0.md` | `parseLyraResponse()` | `apps/rebreak-native/lib/lyraResponse.ts` | implementiert durch | INFERRED (0.85) |
| R-LYRA-01 — verpasste Krise/Suizidalität (S4) | `04-risiko-akte-v0.md` | `detectCrisis()` | `backend/server/utils/crisis-filter.ts` | mitigiert durch | INFERRED (0.95) |
| Maßnahme: Krisen-Keyword-Pre-Filter (`crisis-filter.ts`) | `04-risiko-akte-v0.md` | `crisis-filter.ts` | `backend/server/utils/crisis-filter.ts` | implementiert durch | **EXTRACTED (1.0)** |
| Maßnahme: Krisen-Keyword-Pre-Filter (`crisis-filter.ts`) | `04-risiko-akte-v0.md` | `detectCrisis()` | `backend/server/utils/crisis-filter.ts` | implementiert durch | **EXTRACTED (1.0)** |
| SAFETY-REQ-LLM-001 — Krisenreferenz-Pflicht (Recall 100 %) | `05c-lyra-eval-v0.md` | `detectCrisis()` | `backend/server/utils/crisis-filter.ts` | implementiert durch | INFERRED (0.95) |
| SAFETY-REQ-LLM-001 — Krisenreferenz-Pflicht (Recall 100 %) | `05c-lyra-eval-v0.md` | `getCrisisFallback()` | `backend/server/utils/crisis-filter.ts` | implementiert durch | INFERRED (0.95) |
| Crisis-Detection-Recall — Haupt-Metrik (Ziel 100 %) | `05c-lyra-eval-v0.md` | `crisis-filter.test.ts` | `backend/tests/crisis/crisis-filter.test.ts` | verifiziert durch | INFERRED (0.95) |
| Lyra Persona — Single Source of Truth | `ops/LYRA_PERSONA.md` | `CoachScreen()` | `apps/rebreak-native/app/lyra.tsx` | realisiert in | INFERRED (0.80) |

**Lesart:** „implementiert durch" = das Code-Symbol setzt die Anforderung um;
„mitigiert durch" = das Code-Symbol ist die Risikokontrollmaßnahme (ISO 14971);
„verifiziert durch" = der Test weist die Soll-Metrik nach.

---

## 2a. Traceability-Matrix — Mail-Schutz-Strang (REQ-MAIL, v0)

Strang: die Echtzeit-Entfernung von Trigger-/Casino-Mails (Dok 03 §3,
REQ-MAIL-001…007) mit den Fehlfunktions-Risiken R-MAIL-01 (False Negative →
Trigger erreicht Nutzer), R-MAIL-02 (False Positive → irreversibler Verlust
legitimer Mail) und R-MAIL-03 (LLM-Mittelband). Code-Seite: der deterministische
Klassifikator (`mail-classifier.ts`) und der IMAP-IDLE-Daemon (`imap-idle/index.mjs`).

```
REQ-MAIL-001/002  (Dok 03 — Echtzeit-Überwachung + Entfernung vor Geräte-Notify)
  ├─ imap-idle/index.mjs : runSession() / triggerScan()   (IDLE-Daemon, kein Polling)
  └─ mail/scan-internal.post.ts                            (Scan-Trigger-Endpoint)
        └─ R-MAIL-01  (Dok 04 — Trigger-Mail nicht erkannt, False Negative)

REQ-MAIL-003  (Dok 03 — primär deterministisch; Hard-Block ab Score ≥ 80)
  ├─ classifyMail()           backend/server/utils/mail-classifier.ts
  ├─ computeScore()           backend/server/utils/mail-classifier.ts
  └─ matchesGamblingBrand()   backend/server/utils/mail-classifier.ts
        └─ R-MAIL-03  (Dok 04 — nicht-deterministisches LLM-Mittelband, Score 25–79)

REQ-MAIL-004  (Dok 03 — Whitelist verhindert Löschen legitimer Mail)
  └─ classifyMail() / Whitelist-Pfad (Whitelist-Hit → Score 0)
        └─ R-MAIL-02  (Dok 04 — False Positive, irreversibles Löschen)

REQ-MAIL-006  (Dok 03 — Scan nur nach ausdrücklicher Einwilligung consent_at)
  └─ mail-connections/consent.post.ts                      (Consent-Gate)
        └─ R-DATA-03  (Dok 04/08 — Postfach-Scan ohne Einwilligung)
```

| DiGA-Artefakt (Anforderung / Risiko) | Quelle | → Code-/Test-Artefakt | Datei | Relation | Konfidenz |
|---|---|---|---|---|---|
| REQ-MAIL-001 — Echtzeit-Postfach-Überwachung (IMAP-IDLE, kein Polling) | `03-requirements-v0.md` | `runSession()` | `backend/imap-idle/index.mjs` | implementiert durch | INFERRED (0.85) |
| REQ-MAIL-001 — Echtzeit-Postfach-Überwachung | `03-requirements-v0.md` | `triggerScan()` | `backend/imap-idle/index.mjs` | implementiert durch | INFERRED (0.85) |
| REQ-MAIL-001/002 — Scan bei neuer Mail, alle Ordner | `03-requirements-v0.md` | `scan-internal.post.ts` | `backend/server/api/mail/scan-internal.post.ts` | implementiert durch | INFERRED (0.85) |
| REQ-MAIL-003 — primär deterministische Klassifikation | `03-requirements-v0.md` | `classifyMail()` | `backend/server/utils/mail-classifier.ts` | implementiert durch | INFERRED (0.90) |
| REQ-MAIL-003 — gewichteter Score, Hard-Block ≥ 80 | `03-requirements-v0.md` | `computeScore()` | `backend/server/utils/mail-classifier.ts` | implementiert durch | INFERRED (0.90) |
| REQ-MAIL-003 — Brand-Token-Matching (Glücksspiel-Marken) | `03-requirements-v0.md` | `matchesGamblingBrand()` | `backend/server/utils/mail-classifier.ts` | implementiert durch | INFERRED (0.85) |
| R-MAIL-01 — Trigger-Mail nicht erkannt (False Negative) | `04-risiko-akte-v0.md` | `classifyMail()` | `backend/server/utils/mail-classifier.ts` | mitigiert durch | INFERRED (0.85) |
| R-MAIL-02 — legitime Mail gelöscht (False Positive) | `04-risiko-akte-v0.md` | `classifyMail()` (Whitelist-Pfad, Whitelist-Hit → Score 0) | `backend/server/utils/mail-classifier.ts` | mitigiert durch | INFERRED (0.80) |
| R-MAIL-03 — LLM-Mittelband (Score 25–79) | `04-risiko-akte-v0.md` | `computeScore()` (Schwellen `SCORE_WEIGHTS`) | `backend/server/utils/mail-classifier.ts` | mitigiert durch | INFERRED (0.80) |
| REQ-MAIL-006 — Scan nur nach Einwilligung (`consent_at`) | `03-requirements-v0.md` | `consent.post.ts` | `backend/server/api/mail-connections/consent.post.ts` | implementiert durch | INFERRED (0.85) |
| R-DATA-03 — Postfach-Scan ohne tragfähige Einwilligung | `04-risiko-akte-v0.md` | `consent.post.ts` | `backend/server/api/mail-connections/consent.post.ts` | mitigiert durch | INFERRED (0.80) |
| Mail-Klassifikation — Verifikation (False-Positive/Negative-Verhalten) | `05b` / `03-requirements-v0.md` | `mail-classifier.test.ts` (`MockMailbox`, `filterScannable()`) | `backend/tests/mail/mail-classifier.test.ts` | verifiziert durch | INFERRED (0.85) |

> **Offene Verifikations-Lücke (Mail):** Die `mail-classifier.test.ts` deckt die
> Score-/Klassifikations-Logik unit-seitig ab; ein **dokumentierter Live-Run gegen
> reale Provider-Postfächer** (Löschverhalten je Provider — Outlook/GMX/Gmail, vgl.
> R-MAIL-02 „je Provider prüfen", Dok 05b §2.7) ist als Verifikations-Record **noch
> nicht** archiviert. Die LLM-Mittelband-Eval (R-MAIL-03) fehlt analog zur Lyra-Eval.

---

## 2b. Traceability-Matrix — Schutz-/Selbstbindungs-Strang (v0)

Zweiter Strang: die geräteweite Zugangserschwerung (REQ-PROT), die Selbstbindung
(REQ-MAGIC), der manipulationssichere Cooldown und die zugehörigen Risiken
R-FALSE-01 (falsche Sicherheit bei inaktivem Schutz) und R-BYP-03 (Selbstbindung
wird zur Falle).

```
REQ-PROT  (Dok 03 — geräteweite Zugangserschwerung)
  ├─ Android: DnsFilter.process()        (DNS-NXDOMAIN-Blocking)
  ├─ iOS:     RebreakProtectionModule.applyWebContentLayer()  (NEFilter)
  ├─ Setup:   SetupFlows.tsx             (Schutz-Aktivierung)
  └─ State:   protection / isAllLayersOn()  (Layer-Status)
        └─ R-FALSE-01  (Dok 04 — falsche Sicherheit bei inaktivem Schutz)
             ├─ isAllLayersOn()              (erkennt teil-/inaktiven Schutz)
             └─ wasProtectionEverActiveHere() (Bypass-Detection-Flag)

REQ-MAGIC (Dok 03 — Selbstbindung, 24h-Cooldown)
  ├─ register.post.ts / findActiveDeviceLock()   (Bindung)
  └─ R-BYP-03  (Dok 04 — legitimer Ausstieg scheitert)
        └─ requestDeviceRelease() / request-release.post.ts   (Mitigation: Release-Pfad)

Server-time-authoritativer Cooldown (Dok 03 — Uhr-Manipulation-Schutz)
  └─ signCooldownToken() / verifyCooldownToken()   (backend/server/utils/cooldownToken.ts)

Spec Protection Coverage & Streak (DiGA-Kernmetrik)
  ├─ streak.ts                 (Streak-DB-Layer)
  └─ addStreakEvent()          (append-only protection_state_log)
```

| DiGA-Artefakt (Anforderung / Risiko / Metrik) | Quelle | → Code-Artefakt | Datei | Relation | Konfidenz |
|---|---|---|---|---|---|
| REQ-PROT — Schutz/Blocker (geräteweite Zugangserschwerung) | `03-requirements-v0.md` | `protection` | `apps/rebreak-native/lib/protection.ts` | implementiert durch | INFERRED (0.85) |
| REQ-PROT — Schutz/Blocker (geräteweite Zugangserschwerung) | `03-requirements-v0.md` | `isAllLayersOn()` | `apps/rebreak-native/lib/protection.ts` | implementiert durch | INFERRED (0.85) |
| REQ-PROT — Schutz/Blocker (geräteweite Zugangserschwerung) | `03-requirements-v0.md` | `.applyWebContentLayer()` | `…/ios/RebreakProtectionModule.swift` | implementiert durch | INFERRED (0.80) |
| REQ-PROT — Schutz/Blocker (geräteweite Zugangserschwerung) | `03-requirements-v0.md` | `.process()` | `…/android/…/filter/DnsFilter.kt` | implementiert durch | INFERRED (0.85) |
| REQ-PROT — Schutz/Blocker (geräteweite Zugangserschwerung) | `03-requirements-v0.md` | `SetupFlows.tsx` | `apps/rebreak-native/components/blocker/SetupFlows.tsx` | implementiert durch | INFERRED (0.80) |
| R-FALSE-01 — falsche Sicherheit bei inaktivem Schutz | `04-risiko-akte-v0.md` | `isAllLayersOn()` | `apps/rebreak-native/lib/protection.ts` | mitigiert durch | INFERRED (0.90) |
| R-FALSE-01 — falsche Sicherheit bei inaktivem Schutz | `04-risiko-akte-v0.md` | `wasProtectionEverActiveHere()` | `apps/rebreak-native/lib/protection.ts` | mitigiert durch | INFERRED (0.85) |
| REQ-MAGIC — Selbstbindung (Lock-Modus, 24h-Cooldown) | `03-requirements-v0.md` | `findActiveDeviceLock()` | `backend/server/db/devices.ts` | implementiert durch | INFERRED (0.85) |
| REQ-MAGIC — Selbstbindung (Lock-Modus, 24h-Cooldown) | `03-requirements-v0.md` | `register.post.ts` | `backend/server/api/magic/register.post.ts` | implementiert durch | INFERRED (0.85) |
| R-BYP-03 — Selbstbindung wird zur Falle | `04-risiko-akte-v0.md` | `requestDeviceRelease()` | `backend/server/db/devices.ts` | mitigiert durch | INFERRED (0.90) |
| R-BYP-03 — Selbstbindung wird zur Falle | `04-risiko-akte-v0.md` | `request-release.post.ts` | `backend/server/api/magic/devices/[deviceId]/request-release.post.ts` | mitigiert durch | INFERRED (0.85) |
| Server-time-authoritativer Cooldown (Uhr-Manipulation-Schutz) | `03-requirements-v0.md` | `signCooldownToken()` | `backend/server/utils/cooldownToken.ts` | implementiert durch | INFERRED (0.90) |
| Server-time-authoritativer Cooldown (Uhr-Manipulation-Schutz) | `03-requirements-v0.md` | `verifyCooldownToken()` | `backend/server/utils/cooldownToken.ts` | implementiert durch | INFERRED (0.90) |
| Spec Protection Coverage & Streak (DiGA-Kernmetrik) | `protection-coverage-streak.md` | `streak.ts` | `backend/server/db/streak.ts` | implementiert durch | INFERRED (0.80) |
| protection_state_log (append-only Schutz-Transitions-Log) | `protection-coverage-streak.md` | `addStreakEvent()` | `backend/server/db/streak.ts` | implementiert durch | INFERRED (0.85) |

---

## 2c. Traceability-Matrix — Anonymitäts-Strang (REQ-COMM-005, v0)

Strang: die Nickname-only-Invariante (Dok 03 §7, REQ-COMM-005) — Klarname/E-Mail/
Username dürfen in **keiner** API-Response, Realtime-Payload, Push oder Log
erscheinen — mit dem Anonymitätsbruch-Risiko R-DATA-07 (De-Anonymisierung eines
Sucht-Betroffenen; ein einziges Leck bricht den gesamten Schutz, Dok 04 §2.4).
Betroffene Code-Flächen: Community-Posts/-Kommentare, DM/Chat, Nickname-Vergabe.

```
REQ-COMM-005  (Dok 03 — Anonymitäts-Invariante: nur Nickname nach außen)
  ├─ profile/check-nickname.get.ts : isProfanity() / PROFANITY_BLOCKLIST  (Nickname-Vergabe)
  ├─ community/posts.get.ts   (Autor-Payload nach außen)  ⚠️ siehe GAP unten
  ├─ community/post.post.ts   (Post-Erstellung, isAnonymous-Flag)
  └─ chat/dm.post.ts          (DM-Payload)
        └─ R-DATA-07  (Dok 04 — Klarname/E-Mail leakt → De-Anonymisierung)
```

| DiGA-Artefakt (Anforderung / Risiko) | Quelle | → Code-/Test-Artefakt | Datei | Relation | Konfidenz |
|---|---|---|---|---|---|
| REQ-COMM-005 — Anonymitäts-Invariante (Nickname-only) | `03-requirements-v0.md` | Autor-Payload (`author: { nickname }`) | `backend/server/api/community/posts.get.ts` | implementiert durch (**mit GAP**) | INFERRED (0.75) |
| REQ-COMM-001 — anonyme Community, Nutzer nur per Nickname | `03-requirements-v0.md` | `post.post.ts` (`isAnonymous`-Flag) | `backend/server/api/community/post.post.ts` | implementiert durch | INFERRED (0.75) |
| REQ-COMM-002 — DM zwischen Nutzern (Realtime) | `03-requirements-v0.md` | `dm.post.ts` | `backend/server/api/chat/dm.post.ts` | implementiert durch | INFERRED (0.75) |
| Nickname-Vergabe (Eindeutigkeit/Profanity-Gate als Anonymitäts-Voraussetzung) | `03-requirements-v0.md` | `isProfanity()` / `PROFANITY_BLOCKLIST` | `backend/server/api/profile/check-nickname.get.ts` | implementiert durch | INFERRED (0.80) |
| R-DATA-07 — Anonymitätsbruch (PII in API/Realtime/Push/Log) | `04-risiko-akte-v0.md` | Autor-Serialisierung Community/Chat | `backend/server/api/community/posts.get.ts`, `backend/server/api/chat/dm.post.ts` | mitigiert durch (**unvollständig — GAP**) | INFERRED (0.70) |
| REQ-COMM-005 — Invarianz-Test (kein PII in Response) | `04-risiko-akte-v0.md` RM-4 | *(kein gezielter Anonymitäts-Invarianz-Test gefunden)* | — | **nicht verifiziert** | n/a |

> ⚠️ **GAP / load-bearing Befund — VERIFIZIERT + FIX ANGEWENDET (2026-06-10, Nacht-Session):**
> Die Autor-Serialisierung in `community/posts.get.ts` emittierte **neben** `nickname`
> auch ein Feld **`username`**; ebenso `social/profile/[userId].get.ts` (Fremdprofil-View).
> Backend-Verifikation hat die offene Frage geklärt: `username` ist der **Login-
> Identifikator** (Auth-E-Mail wird als `{username}@rebreak.internal` konstruiert,
> `auth/login.post.ts` L100) — **kein Pseudonym**. Beide Pfade verletzten damit
> REQ-COMM-005 und realisierten R-DATA-07; zusätzlich Credential-Exposure (halbes
> Login-Paar fremder Accounts).
> **Fix (lokal, noch nicht deployed — Deploy braucht User-GO):** `username`-Feld aus
> beiden Response-Payloads entfernt (`posts.get.ts`, `social/profile/[userId].get.ts`);
> totes Typ-Feld in `apps/rebreak-native/stores/community.ts` entfernt. Frontend
> rendert `username` nachweislich nirgends (grep-verifiziert).
> **Rest-Befund (offen, User-Entscheidung):** Die Nickname-Fallback-Ketten
> (`nickname: a?.nickname ?? a?.username`, ebenso `dm-conversations.get.ts`
> `partnerName`) zeigen bei Usern OHNE Nickname weiterhin den Login-Username an.
>
> Für einen formalen Nachweis fehlt ein **Anonymitäts-Invarianz-Test** (RM-4 / Dok 04
> §4): ein Test, der alle Community-/Chat-/Profile-Responses + Realtime-Payloads gegen
> das Vorkommen von Klarname/E-Mail/Username prüft. Bis dahin bleibt R-DATA-07
> **unverifiziert** (Dok 05b §2.3).

---

## 3. Herkunft & Reproduzierbarkeit

Die Lyra- (§2) und Schutz-/Selbstbindungs-Zeilen (§2b) sind 1:1 aus den
Traceability-Kanten in `graphify-out/graph.json` abgeleitet (Kanten-Feld
`traceability: true`, **27 Kanten** — 12 Lyra-/Krise, 15 Schutz-/Selbstbindung;
letztere mit `strand: "protection"`). Erzeugung: graphify-Knowledge-Graph über
`backend/`, `apps/rebreak-native/` und `docs/specs/diga/`. Vor der Verknüpfung lagen
Dossier-Schicht (LLM-extrahiert) und Code-Schicht (AST-extrahiert) in **getrennten
Graph-Komponenten** — exakt die in Dok 05b §3.2 beschriebene implizite, nicht
formalisierte Traceability. Nach Einzug dieser Kanten liegen `REQ-LYRA` und `REQ-PROT`
mit der gesamten nativen + Backend-Implementierung (SOS, DNS-/NEFilter, Device-Lock,
Cooldown, Streak) in **einer** Komponente.

**Mail-Strang (§2a) und Anonymitäts-Strang (§2c)** wurden ergänzend per
**Graph-Knotensuche** (Symbol-/Datei-Lookup in `graph.json`, ohne formalisierte
`traceability:true`-Kanten) erstellt und jede genannte Datei auf der Platte
**verifiziert** (existiert). Sie sind **noch nicht** als Graph-Kanten persistiert;
das ist — analog zu §2b für Lyra/Schutz — ein offener Schritt (`/graphify --update`
mit manueller Verdrahtung wie in `05d §4`). Der Anonymitäts-GAP (§2c) wurde durch
direktes Lesen von `community/posts.get.ts` belegt, nicht nur aus dem Graphen
inferiert.

> ⚠️ **Automatisch erzeugt ≠ validiert.** Die INFERRED-Zeilen müssen vor jeder
> Verwendung als Nachweis durch einen Regulatory-/QM-Profi bestätigt werden.

---

## 4. Offene Schritte (Richtung formaler IEC-62304-Record)

1. **INFERRED-Zeilen menschlich bestätigen** oder verwerfen (Regulatory-Review).
2. **Soll-Ergebnis je Testfall** als eigenständiges Artefakt definieren
   (Dok 05b §4.2 — bislang nur Assertions im Test).
3. **Ergebnis-Protokoll** pro Release: Build-Version, Datum, Pass/Fail je Test-ID
   (Vitest-/Maestro-JUnit-XML archivieren).
4. **Anonymitäts-GAP klären (§2c):** Backend/Hans prüfen, ob das in
   `community/posts.get.ts` ausgegebene Feld `username` ein Identifikator ist; falls ja,
   aus der Response entfernen und **R-DATA-07 mit einem Invarianz-Test (RM-4) verifizieren**.
5. **Restliche Stränge ergänzen:** Onboarding/Streak-Vollabdeckung,
   Auth/Geräte-Limit analog verknüpfen. *(Lyra, Schutz/Selbstbindung, Mail-Schutz und
   Anonymität sind in dieser v0 abgedeckt — Mail + Anonymität neu in §2a/§2c.)*
6. **Mail- und Anonymitäts-Strang als Graph-Kanten persistieren** (`traceability:true`),
   damit auch sie aus dem Graphen regenerierbar werden statt aus Knoten-Lookup.
7. **Test-ID-Rückverweise im Code** ergänzen (Vitest-`describe` / Maestro-YAML-
   Kommentar referenziert `REQ-XXX` / `R-XXX`), damit die Matrix künftig aus dem
   Code selbst regenerierbar ist statt aus Graph-Inferenz.

---

*v0-Erst-Entwurf. Deckt die sicherheitsrelevanten Stränge Lyra/Krise, Schutz/
Selbstbindung, Mail-Schutz und Anonymität ab. Die Konfidenz-Flags und der GAP-Hinweis
in §2c sind Teil des Dokuments und dürfen beim Übernehmen in die finale Akte nicht
entfernt werden, bevor die jeweilige Zeile validiert bzw. der GAP geschlossen ist.*
