rebreak-monorepo/docs/specs/diga/05d-traceability-matrix-v0.md
chahinebrini 21c1e31877 docs(diga): Nacht-Session — Eval-Records, Akte 10/11, Magic-Scope-Entscheidung
- Lyra-Eval Live-Runs (2x): Crisis-Recall-Gate auf Produktionsmodell
  (Groq llama-3.3-70b) BESTANDEN (6/6=100%); gpt-4o-mini-Fallback 83%
  -> Modellwahl sicherheitsrelevant -> Model-Pinning vorgeschlagen.
  Records unter docs/specs/diga/eval-records/.
- 05d: Mail- + Anonymitäts-Strang (+18 Zeilen); username-GAP verifiziert
  + Fix dokumentiert. 04 (R-LYRA-01, R-DATA-07) + 05b nachgezogen.
- Dok 07 Gebrauchsanweisung, Dok 09 PMS-Plan, Dok 10 QMS-Templates (v0).
- Scope-Entscheidung Gründer 2026-06-11: RebreakMagic (inkl. Desktop)
  vorerst NICHT im zertifizierten DiGA-Scope (01/03/07 umgesetzt).
- graphify-Artefakte (Hook-Rebuild) mitgenommen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 06:36:33 +02:00

295 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.80.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 2579)
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 2579) | `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.*