# QAF → Wertstrom-Integration (QVS): Abschlussbericht

Stand: 2026-07-18 · Programm QVS (Epic KAR-968) · Phase P7 (KAR-976, Flag-ON) · Struktur nach Spec §39
(`reports/qaf-value-stream-spec-source.txt:206-212`). Dieser Bericht speist sich ausschließlich aus den
bestehenden kanonischen Quellen des Programms (siehe Quellenliste am Ende) — er erfindet keine neuen
Zahlen, sondern führt sie zusammen und ordnet sie ein. Die vollständige, einzeln belegte
40-Kriterien-Bilanz steht in `reports/qaf-value-stream-acceptance-criteria.md`.

Zielgruppe: Kais und — perspektivisch — BMW-Leser. Deutsch, präzise, ohne Marketing-Ton. Wo etwas
offen ist, steht **OFFEN**. Keine Korpus-Dateinamen oder Kundendaten — nur Split-Indizes
(`dev#N`/`validation#N`) und Template-Familien.

---

## A. Executive Summary

**Was gebaut wurde:** Ein Weg, aus einer bereits analysierten QAF-Datei mit einer klaren Aktion
(„Als Wertstrom übernehmen") eine vollständig editierbare Wertstromanalyse (VSM) zu erzeugen — ohne
Fertigungsdaten manuell abzutippen. Die Kette läuft über sieben Phasen (P0 Analyse, P1 Mapper-Kern,
P2 Persistenz, P3 UI, P4 Multi-QAF-Varianten + Kennzahlen, P5 Reimport/Sync, P6 Korpus-Validierung)
und wird mit P7 produktiv geschaltet: **`qafValueStream` steht ab diesem PR in den Profilen `bmw`
und `default` auf `true`** (zuvor in allen drei Profilen `false`); `_template` bleibt bewusst `false`
(Begründung: Abschnitt C).

**Wie der Nutzer-Workflow funktioniert:** Auf der QAF-Vergleichsseite (`summary`/`g60`-Vergleiche)
oder auf der projektbezogenen QAF-Übersicht erscheint der Button „Als Wertstrom übernehmen", sobald
verlässliche Fertigungsschritte erkannt wurden. Ein Preview-Dialog zeigt Quelle, Schritt-Liste,
Feld-Abdeckung und Warnungen; ein Klick auf „Erstellen" persistiert transaktional einen neuen
Wertstrom samt Audit-/Herkunfts-Datensatz und öffnet ihn direkt im Editor.

**Welche QAF-Strukturen unterstützt werden:** Jede Datei, die der bestehende Hauptparser bereits in
`qaf_manufacturing_step`-Zeilen überführt hat — unabhängig vom Sheet-Namen (Aliasse wie
„Fertigungskosten"/„Manufacturing Costs"/„LV Detail EU" werden bereits von der Capability-Schicht
erkannt) und ohne G60-, INPUT- oder Nummerierungs-Zwang. Korpus-Beleg (P6, `validation-results.md`):
parseOk 91,2 % (dev, 207/227) / 91,4 % (validation, 64/70); von den geparsten Dateien sind 96,1 %
(dev) / 96,9 % (validation) tatsächlich „eligible" (mindestens ein Schritt mit Prozessname).

**Welche Fertigungswerte übernommen werden:** Alle 22 kanonischen QAF-Felder — 14 fließen direkt in
den Wertstrom-Knoten (Name, Sequenz, Zykluszeit, Kosten, Mitarbeiterzahl, Standort, Währung, Scrap
u. a.), die übrigen 8 als strukturierte Herkunfts-Metadaten. **0 Felder werden verworfen**
(field-mapping.md). 11 von 12 Primärfeldern liegen bei 78-99 % Feld-Coverage (step-weighted); eine
Ausnahme (Rüstkosten, ~20 %, Abschnitt H) ist eine reale, geprüfte Quelldaten-Eigenschaft, kein
Programmfehler.

**Wie editierbar der erzeugte Wertstrom ist:** Alle bestehenden Editor-Funktionen (Umbenennen,
Verschieben/Reihenfolge, Hinzufügen, Löschen, Werte ändern) funktionieren unverändert; neu
hinzugekommen ist eine 4-Wege-Klassifikation (wertschöpfend/notwendig-nicht-wertschöpfend/nicht-
wertschöpfend/ungeklärt) statt der alten Ja/Nein-Checkbox, plus Reimport/Synchronisation gegen eine
neue QAF-Version.

**Wie Source-Traceability funktioniert:** Jeder importierte Knoten trägt `qafSource` mit Zelle,
Original-Wert, Einheit und Konfidenz je Feld — „Quelle anzeigen" macht das im Editor sichtbar. P6:
100,0 % der importierten Knoten tragen `qafSource` (beide Splits), mittlere Feld-Vollständigkeit
98,4 %/98,0 %, Minimum 90,9 %.

**Wie Wertschöpfungs-Analyse entsteht:** Eine konservative Mustererkennung schlägt eine Klassifikation
vor (nie automatisch „wertschöpfend") — P6 hat das über den vollen Korpus empirisch bestätigt: 0 von
1391 (dev) bzw. 0 von 415 (validation) Knoten wurden automatisch als `va` eingestuft.

**Welche Grenzen bleiben** (Kurzfassung, vollständig in Abschnitt H): Rüstkosten-Feld nur ~20 %
Abdeckung (Quelldaten-Eigenschaft); umbenannte Fertigungsschritte werden bei Reimport als
Entfernen+Neu statt als Änderung erkannt; Multi-QAF-Varianten-Stichprobe ist klein (9 Dateien); kein
Prozess-Count-Ground-Truth-Datensatz existiert (bewusst nicht gebaut, Kais-Entscheid); ein
vorbestehender, unabhängiger Testlücken-Fund (`rls-user-scoped.test.ts`, 9 andere Kerntabellen); und
— am wichtigsten für diesen PR — **der komplette Klick-Pfad im echten Browser gegen die jetzt
Flag-ON geschaltete Konfiguration wurde bis heute nie gefahren** (das Flag war während P1-P6
durchgehend `false`). Das ist der zentrale, nach diesem Merge noch ausstehende Verifikationsschritt.

## B. Ist-Analyse (Ausgangslage vor QVS)

Vor Programmstart existierten zwei vollständig getrennte Pipelines ohne jede Verbindung:

- **QAF-Hauptengine** (`lib/qaf-differences`, produktiv seit KAR-799): persistiert Fertigungszeilen
  relational in `qaf_manufacturing_step` inkl. Zell-Herkunft (`source_cells`), aber `qaf_file.file_hash`
  wurde geschrieben und indiziert, **nie gelesen** — Dedup-Fundament lag brach.
- **/Wertstrom-Modul** (VSM): `value_stream_maps` mit `VsmNode`-JSONB, bereits mit Timing-Feldern
  (`cycleTimeSec` u. a.), aber **kein einziges Kosten-Feld, kein Scrap, keine Varianten-Zugehörigkeit,
  keine Herkunft, kein Import-Status**. Drei bestehende Import-Wege (Excel, LSC, Stoppuhr-Picker)
  hatten **keine** Herkunfts-Markierung; der Excel-Import setzte `isValueAdded` sogar hartcodiert auf
  `true` für jede Zeile — der historische Fehler, den QVS explizit korrigiert (nie mehr automatisch
  „wertschöpfend").

13 Gaps wurden identifiziert und in drei Klassen sortiert (`gap-analysis.md`): **Klasse A** (Kern,
muss gebaut werden — z. B. G1 „keine QAF↔VSM-Verbindung", G2 „VsmNode-Modell unvollständig", G3
„kein Import-/Audit-Modell", G7 „Duplikat-Schutz-Fundament liegt brach", G11 „keine
UI-Entry-Points"), **Klasse B** (Korpus entscheidet — G4 „Extraktions-Lücken auf Schritt-Ebene", G9
„VSM-Versionierung"), **Klasse C** (ehrliche Limitation statt Bau — G5 „Multi-QAF-Varianten ohne
Schritt-Ebene", strukturell bedingt durch die Quelldaten selbst). Diese Klassifikations-Logik bestimmte
den gesamten Phasenplan (Abschnitt C).

## C. Implementierte Architektur

Sieben Leitentscheidungen (E1-E7, ADR-024, `docs/adr/024-qaf-value-stream-integration.md`) tragen das
gesamte Programm:

- **E1 — Aus der Hauptengine lesen, nicht neu parsen.** Quelle ist ausschließlich
  `qaf_manufacturing_step` + `qaf_file.g60_meta.capability_matrix`; kein neuer Parser, kein Zugriff
  auf den Legacy-Pfad `qaf_uploads.parsed_data`.
- **E2 — Additives VSM-Datenmodell.** Alle neuen `VsmNode`-Felder (`costPerUnit`, `scrapRate`,
  `vaClass`, `qafSource`, `fieldStatus` u. a.) sind optional im bestehenden `nodes`-JSONB — bestehende
  Wertströme bleiben byte-kompatibel gültig, keine Migration auf relationale Node-Tabellen.
- **E3 — `value_stream_imports` statt Dokument-Versionierung.** Ein neues Audit-/Lineage-Objekt trägt
  Quelle, Hash, Versionen, Zählwerte, Warnungen und einen Import-Snapshot; volle VSM-Versionierung
  bleibt bewusstes Follow-up (Gap G9).
- **E4 — Projekt-Scope erzwungen.** Ein aus QAF erzeugter Wertstrom übernimmt zwingend die
  `project_id` der Quelle — kein projektloser Import, kein RLS-Scope-Verlust für Kosten-Daten.
- **E5 — Feature-Flag, Rollout nach Korpus-Validierung.** Genau das Muster, das mit diesem PR (P7)
  abgeschlossen wird.
- **E6 — Fabrikationsverbot operationalisiert.** Nur real extrahierte Werte werden geschrieben; fehlt
  ein Wert, bleibt das Feld leer mit dokumentiertem Grund — nie 0/null gestopft, nie eine
  Varianten-Zykluszeit erfunden.
- **E7 — Diese ADR selbst** als bindende Grundlage für den gesamten Phasenplan P1-P7.

**Modul-Layout** (`lib/qaf-value-stream/`, ADR-019 Golden Path): reine Funktionen zuerst
(`mapper.ts`, `manufacturing-capability.ts`, `va-classification.ts`, `naming.ts` — P1), dann
DB-gebundene Services (`preview.ts`, `duplicates.ts`, `creation.ts` — P2), Multi-QAF-Kontext
(`multi-qaf-context.ts` — P4) und Sync (`sync.ts`/`reimport.ts` — P5). Server-Wiring ausschließlich
über `app/wertstrom/qaf-actions.ts` (nie direkt im bestehenden 4700-Zeilen `app/qaf-differences/actions.ts`).

**Datenmodell:** `value_stream_imports` (Migration `supabase-migration-value-stream-imports.sql`,
KAR-971/P2) — `_own`/`_admin`-RLS-Paar ab Tag 1, `project_id`/`qaf_file_id` beide `ON DELETE SET
NULL` (Audit-Trail überlebt eine Projekt-Löschung, analog `value_stream_maps`), `created_by NOT
NULL` als Sichtbarkeits-Fallback. Die Migration ist **seit 18.07.2026 ~10:31 CEST in Prod applied**
(operator-seitig, MIGRATIONS.md §7o) — Tabelle existiert, RLS aktiv, 0 Zeilen (Stand vor diesem PR;
das Flag war bis zu diesem Merge überall `false`, kein App-Code-Pfad hat je geschrieben).

**RLS-Design-Entscheidung (Kais-Entscheid, 18.07.2026 18:09, TG 8901):** Die
`vsm_own`-OR-RLS-Semantik — sichtbar für `created_by = auth.uid()` ODER Projekt-Owner —, repliziert 1:1
in `value_stream_imports_own`, **bleibt Bestandsmuster**. Das wurde bewusst geprüft und **nicht**
verschärft: Begründung ist Konsistenz mit dem bereits etablierten `value_stream_maps`-Bestandsverhalten
(dieselbe OR-Semantik gilt dort seit Programmstart), und die Anwendungs-/RPC-Schicht erzwingt den
Projekt-Scope bereits zusätzlich (E4 — `create_value_stream_from_qaf` leitet `project_id` immer aus der
QAF-Quelle ab, nie aus Client-Eingabe). Es gibt **keinen Verschärfungs-Follow-up-Auftrag** aus dieser
Entscheidung — sie ist hiermit als getroffene, dokumentierte Entscheidung geführt, nicht als offener
Punkt.

**Feld-Vertrag:** `mappings/qaf-to-value-stream-mapping.yaml` (`MAPPING_VERSION = qvs-1`), gegen
`mapping-drift.test.ts` gehärtet — Details in Abschnitt E.

**Multi-QAF-Varianten (P4):** „Geteilter Fertigungsfluss" (Default) oder „Je Variante ein
Wertstrom". Die Varianten-Bindung ist **evidenzbasiert**, nicht pauschal: nur Varianten mit
nachweislich demselben Fertigungsprofil (`variantProfileBindings`) werden gemeinsam dargestellt —
ein Container darf laut Domänenmodell auf unterschiedlichen Fertigungsprofilen/Standorten laufen, und
das wird seit einem Review-Fix (P4, Finding 1) korrekt nie mehr unterstellt.

**Reimport/Sync (P5):** `computeSyncDelta` klassifiziert jeden Schritt und jedes editierbare Feld in
sechs Zustände (`UNCHANGED|SOURCE_CHANGED|LOCAL_CHANGED|BOTH_CHANGED|NEW_IN_SOURCE|
REMOVED_FROM_SOURCE`). `LOCAL_CHANGED` wird von keinem Übernahme-Plan je angefasst; `BOTH_CHANGED`
nur durch explizite Einzelentscheidung — nie stilles Überschreiben.

## D. User Experience

Durchgängiger Flow (`ux-flow.md`, umgesetzt P3/P4):

1. **QAF hochladen + analysieren** — unverändert.
2. **Fähigkeit erkennen** — automatisch, capability-basiert; bei Teildaten erscheint die Aktion
   trotzdem mit Coverage-Hinweis, bei keinen Fertigungsdaten erscheint sie gar nicht (kein toter
   Button).
3. **Entry-Points** (beide öffnen denselben Dialog): (A) QAF-Vergleichsdetail (`summary`/`g60`,
   Button „Als Wertstrom übernehmen" neben den Export-Buttons, bei ALT+NEU ein Seiten-Umschalter,
   Default NEU); (B) projektbezogene QAF-Übersicht.
4. **Varianten & Modus** — nur bei Multi-QAF-Quelle: „Geteilter Fluss" (Default) oder „Je Variante
   ein Wertstrom", mit ehrlicher Formulierung der Datenlage (nie fabrizierte Varianz).
5. **Preview** — ein Dialog: Quelle, editierbarer Titel (`[Lieferant] · [Projekt] · [Variante] ·
   QAF-Wertstrom`), Schritt-Checkliste in Quell-Reihenfolge, Coverage-Zeile, nicht-blockierende
   Warnungen, aufklappbare fehlende-Felder-Liste mit Grund, Duplikat-Banner (`Öffnen`/`Trotzdem neu
   erstellen`, nie Hard-Block).
6. **Erstellen** — ein Klick, transaktional.
7. **Öffnen in /Wertstrom** — direkter Redirect, Erfolgs-Toast mit Kurzbilanz (z. B. „18 Schritte
   importiert, 3 ohne Zykluszeit").
8. **Anpassen & analysieren** — im Editor: dezente Herkunfts-Kennzeichnung, „Quelle anzeigen"-Modal
   (alle 22 Quellfelder mit Zelle/Original/Einheit/Konfidenz), vaClass-4-Wege-Auswahl, Stoppuhr-
   Soll/Ist-Vergleich (kein Auto-Overwrite — Nutzer wählt den Anzeigewert), „Synchronisieren"
   (Reimport gegen eine neue QAF-Version).

Design-Prinzip durchgehend: kein Parser-Vokabular im Hauptfluss, kein neuer Formular-Zoo (derselbe
Dialog-Baustein wie die bestehenden Import-Modals), Partial-Import sichtbar statt versteckt.

## E. Feld-Mapping

Vollständige Tabelle: `reports/qaf-value-stream-field-mapping.md` +
`mappings/qaf-to-value-stream-mapping.yaml` (`qvs-1`). Kurzfassung, alle 22 kanonischen QAF-Felder:

| Ziel-Kategorie | Anzahl Felder | Beispiele |
|---|---|---|
| Direkt auf Node-Primärfeld | 14 | Prozessname → `name`, Zykluszeit → `cycleTimeSec`, Mitarbeiterzahl → `numWorkers`, Rüstkosten → `setupCostPerUnit`, Prozesskosten → `costPerUnit`, Standort → `location`, Währung → `currency` |
| Nur als `qafSource`-Metadaten (Detail-Panel) | 8 | Teilebenennung, Lohnzuschlagssätze, FEK, RFGK, Angebotswährung, Wechselkurs, Menge je Angebotsteil, `fkAW` |
| **Verworfen** | **0** | — |

Zentrale Semantik-Schutzregeln (durch Tests erzwungen): Kosten werden nie in Zeit-Felder gemappt
(`ruestkosten` ≠ `setupTimeSec`); `laborHourRate`/`machineHourRate` sind Stundensätze, keine
Pro-Stück-Werte (P1-Review-Fix, vormals fälschlich `laborCostPerUnit` benannt);
`scrapCostPerUnit` ist AW-denominiert (Angebotswährung), **nicht** dieselbe Währung wie `node.currency`
(BW, P1-Review-Fix). Abgeleitete Werte: `vaClass` (konservative Mustererkennung, nie automatisch
`va`), `isValueAdded = (vaClass === 'va')` (Kompatibilität mit Bestands-Editor/-Metriken), lineare
`VsmConnection`-Kette aus der Sequenz.

Explizit nicht gemappt, mit Grund (keine Fabrikation): `machineTimeSec`/`manualTimeSec` (Quelle hat
keinen Zeit-Split), `setupTimeSec`/`waitTimeSec`/`transportTimeSec` (keine Quellfelder, nur
Rüst-KOSTEN vorhanden), `capacityPerHour`/`oee`/`demand`/`distance` (keine Schritt-Ebene-Quelle),
Varianten-Zykluszeiten je Schritt (existieren strukturell nicht, Gap G5).

## F. Testergebnisse

**Historische Baseline (P0-P6, zur Einordnung — Voll-Suite `npx vitest run --exclude "**/.claude/**"`):**

| Phase | PR | Voll-Suite | Bemerkung |
|---|---|---|---|
| P1 | #335 | 4001 → 4002 grün, 0 rot (nach Review-Fixes) | 113 Tests allein unter `lib/qaf-value-stream` |
| P2 | #336 | 4046 → 4052 grün, 0 rot (nach Review-Fixes) | Migration + RLS `_own`/`_admin` ab Tag 1 |
| P3 | #337 | 4120 → 4138 grün, 0 rot (nach Review-Fixes) | 6 neue Testdateien UI |
| P4 | #338 | 4224 → 4250 grün, 0 rot (nach Review-Fixes) | Multi-QAF-Varianten + Kennzahlen |
| P5 | #339 | 4326 → **4342** grün, 0 rot / **4409** grün, 0 rot **mit** `RLS_TEST_DATABASE_URL` (embedded Postgres 17.10, 67/67 RLS-Tests real grün, davon `rls-value-stream-imports-isolation.test.ts` 14/14) | Reimport/Sync |
| P6 | #340 | 4342 grün, 0 rot (reproduziert P5 exakt — 0 Produkt-Code-Diff) | Korpus-Validierung, 4 Reports |
| **P7** | **dieser PR** | **4342 grün, 0 rot, 67 skip, 36 todo** (identisch zu P5/P6) | **Flag-ON** — Gate-Details unten |

Der Flag-Flip selbst ändert keinen Testpfad strukturell: kein Test importiert
`config/profiles/{default,bmw}.ts` ungemockt mit einer hartcodierten `qafValueStream`-Erwartung
(verifiziert per Grep vor dem Gate-Lauf — `app/wertstrom/__tests__/qaf-actions.test.ts` mockt
`getProfile()` lokal und deckt beide Flag-Zustände bereits unabhängig vom realen Profil-Wert ab).

**Real-Korpus-Validierung (P6, `validation-results.md`, verbindliche Zahlen = validation-Split
n=70; dev-Split n=227 dient nur der Kalibrierung):**

| Metrik | dev (n=227) | validation (n=70) |
|---|---|---|
| parseOk | 91,2 % (207/227) | 91,4 % (64/70) |
| capabilityEligible (von parsed) | 96,1 % (199/207) | 96,9 % (62/64) |
| previewOk (von parsed) | **100,0 % (207/207)** | **100,0 % (64/64)** |
| Sequenz-Genauigkeit (row_order) | 98,5 % (196/199) | **100,0 % (62/62)** |
| Lineage (`fieldsPresentFraction`, Mittel) | 98,4 % | 98,0 % |
| `nodesWithQafSource` | 100,0 % (1391/1391) | 100,0 % (415/415) |
| VA-Klassifikation automatisch `va` | 0/1391 (0,0 %) | 0/415 (0,0 %) |

**Zykluszeit-Coverage — Nenner-Erklärung (kein Widerspruch, zwei dokumentierte Maßstäbe):** Die P1-
Baseline berichtete 91,4 % Zykluszeit-Abdeckung (Nenner: alle 1472 geparsten Zeilen inkl. 81 ohne
Prozessname). P6 berichtet 96,8 % (Nenner: nur die 1391 tatsächlich eligiblen Schritte). Zähler ist in
beiden Fällen identisch: **1346**. 1346/1472 = 91,4 % = 1346/1391 = 96,8 % — unterschiedliche, jeweils
dokumentierte Nenner-Wahl, keine Diskrepanz.

**Rüstkosten — Root-Cause (kein Parser-Bug):** `ruestkosten → setupCostPerUnit` liegt bei 19,7 % (dev)
/ 21,4 % (validation) step-weighted — deutlich unter den übrigen 11 Feldern (78-99 %). Aufschlüsselung
aller 1117 `missingFieldReasons`-Einträge (dev, voller Split): **100 % `cell_empty`, 0 %
`no_column_mapped`** — die Spalte wird immer korrekt lokalisiert, die Quellzelle ist überwiegend leer.
Aktiv ausgeschlossen, nicht nur vermutet.

**RLS-Suite (real gegen echtes Postgres, P5-Runde, 18.07.2026, embedded-postgres PG 17.10):** volle
Kette geladen (Bootstrap → 8 Migrationen inkl. `value_stream_imports` → RLS-Setup), **67/67 grün**
(`rls-value-stream-imports-isolation.test.ts` allein 14/14, inkl. aller 5 UPDATE-Fälle aus P5). Dabei
ein echter, von QVS unabhängiger Test-Isolationsbug in genau dieser Datei gefunden und behoben (kein
Sicherheitsproblem). In P6 und in dieser P7-Session nicht erneut gegen echtes Postgres gefahren (kein
RLS-relevanter Produkt-Code-Diff seit P5) — dieselbe, bereits dokumentierte Begründung wie P6.

**Bekannte, ehrlich dokumentierte Alt-Lücke (präzisiert, Review-Fix PR #341):**
`__tests__/security/rls-user-scoped.test.ts` ist ein unbedingter `it.todo()`-Stub (36 Platzhalter, 9
Kerntabellen × 4 Fälle — **keine** davon Teil des QVS-Datenmodells) ohne jedes Env-Var-Gate. Präzise:
2 der 9 (`projects`, `process_steps`) sind über eigene, echte Testdateien abgedeckt
(`rls-projects-isolation.test.ts`, R61, bzw. `rls-project-children-isolation.test.ts`,
R61/KAR-788-Teillieferung — beide Teil der 67/67-Runde oben); 2 weitere (`qaf_uploads`,
`workshop_actions`) sind laut `scripts/rls-test/setup.sql`-Kommentar durch dasselbe `*_own`-Muster
„representative" abgedeckt — ein Analogie-Anspruch, kein eigener Test. Nutzerskopierte
RLS-Isolation nie real getestet bleibt für die verbleibenden 5 Tabellen (`cycle_measurements`,
`user_profiles`, `assessments`, `oee_records`, `documents`). KAR-788 hat den `process_steps`-Teil
bereits geliefert und ist für den Rest reopened, **kein QVS-Blocker**, in
`unresolved-limitations.md` §1.3 an Kais eskaliert.

**Adversarialer Review über das Programm (P1-P6, 6 Runden, 0 refuted):**

| Phase | PR | CONFIRMED Findings |
|---|---|---|
| P1 | #335 | 4 |
| P2 | #336 | 10 |
| P3 | #337 | 9 |
| P4 | #338 | 11 (2 davon derselbe Bug, unabhängig von 2 Reviewern gefunden → 10 Fixes) |
| P5 | #339 | 13 (2 critical, 5 major, 6 minor) |
| P6 | #340 | 7 |
| **Summe** | | **54** |

Alle 54 gefixt, 0 refuted, 0 unverified — nachgezählt direkt aus den jeweiligen CHANGELOG-Einträgen
(P0 hatte ebenfalls eine adversarielle Review-Runde mit „10 Fakten-Korrekturen", aber ohne
überlebendes CONFIRMED/refuted-Zählschema im heutigen CHANGELOG-Text — hier bewusst nicht in die
Summe der 6 formal gezählten Runden P1-P6 gemischt, um keine unterschiedlichen Zählverfahren zu
vermengen).

**Gate-Ergebnisse dieses PRs, final (2026-07-18, nach dem Flag-Flip, kompletter Diff):**

| Gate | Kommando | Ergebnis |
|---|---|---|
| Typecheck | `npm run typecheck` | clean, 0 Fehler |
| ESLint (Diff-Scope) | `npx eslint` auf den 13 geänderten/neuen Dateien (2 `.ts` + 11 `.md` — Review-Fix PR #341 hat 6 weitere `.md`-Dateien zum Diff hinzugefügt: `MIGRATIONS.md`, `docs/adr/024-...`, `docs/adr/README.md`, `lib/qaf-value-stream/README.md`, `reports/qaf-value-stream-regression-results.md`, `reports/unresolved-limitations.md`) | **0 Fehler**, 11 Warnungen (je 1× „file ignored" pro `.md`-Datei — kein Lint-Ziel; die 2 `.ts`-Dateien laufen durch die echte Regelprüfung und liefern 0 Probleme) |
| Voll-Suite | `npx vitest run --exclude "**/.claude/**"` | **4342 grün, 0 rot, 67 skip, 36 todo** (303/312 Testdateien) — identisch zur P5/P6-Baseline (Review-Fix PR #341 ändert 0 Test-/Produkt-Code, nur Dokumentation) |
| `check:profiles` | `npm run check:profiles` | 3/3 Profile validiert |
| `check:portability` (strict) | `CHECK_FORBIDDEN_LEVEL=error npm run check:portability` | alle 8 Teilchecks clean (profiles/forbidden/boundaries/openapi/csp/secrets/hardcoded-colors/bmw-fonts) |

Der Flag-Flip selbst reproduziert die Voll-Suite exakt (4342/0/67/36) — strukturell erwartbar, da kein
Test die realen Profil-Dateien ungemockt mit einer hartcodierten `qafValueStream`-Erwartung liest
(verifiziert per Grep vor dem Gate-Lauf: `app/wertstrom/__tests__/qaf-actions.test.ts` und
`app/api/v1/assignments/[id]/__tests__/route.test.ts` mocken `getProfile()` jeweils lokal).

**Was in diesen Zahlen NICHT enthalten ist — Browser-E2E (ergänzt, Review-Fix PR #341):** Jede Zahl
oben (4342 grün, 67/67 RLS, alle 5 Gates grün) stammt aus Unit-/Komponententests, einem
DB-Testharness oder einem Korpus-Tool — keine einzige aus einer Browser-Session. Der komplette
Klick-Pfad (Button → Preview → Erstellen → Editor, Duplikat-Fall, Reimport über mehrere echte
Syncs, `/wertstrom`-Liste gegen `value_stream_imports`) wurde **nie in einem echten Browser gegen
die jetzt Flag-ON geschaltete Konfiguration gefahren** — s. Abschnitt H, Limitation 7, für die
vollständige Einordnung. Dieser Abschnitt allein belegt keine vollständige Verifikation des
Nutzer-Flows.

## G. Vorher/Nachher

| | Vorher (manuell) | Nachher (QVS, Flag-ON) |
|---|---|---|
| Dateneingabe | Fertigungswerte manuell aus dem QAF abgetippt | Ein Klick „Als Wertstrom übernehmen" + Preview-Bestätigung |
| Herkunft | Keine Markierung, welcher Wert woher kam | Jeder importierte Wert trägt Zelle/Original/Einheit/Konfidenz („Quelle anzeigen") |
| Fehlerquelle | Abtipp-Fehler, keine Gegenprüfung | Werte direkt aus bereits geparsten, geprüften `qaf_manufacturing_step`-Zeilen |
| Wertschöpfungs-Klassifikation | Binäre Checkbox, historisch teils hartcodiert `true` (Excel-Import) | 4-Wege-Klassifikation, nie automatisch „wertschöpfend" (0/1806 Nodes im P6-Korpus-Test) |
| Änderungsnachvollziehbarkeit | Keine Unterscheidung importiert/manuell geändert | `fieldStatus` je Feld (`imported`/`modified`), Original bleibt immer erhalten |
| Aktualisierung bei neuer QAF-Version | Kompletter manueller Neuabgleich | Reimport/Sync mit 6-Zustands-Delta, nie stilles Überschreiben lokaler Änderungen |
| Duplikat-Schutz | Keiner | Hash-/Projekt-/Varianten-basierter Hinweis („Öffnen"/„Neu erstellen") |
| Multi-Varianten-QAFs | Kein Weg, Fertigungsdaten je Variante zu übernehmen | Geteilter Fluss oder Je-Variante-Wertstrom, evidenzbasiert, nie fabrizierte Varianz |
| Kennzahlen | Bottleneck + binäre VA-Quote | Zusätzlich vaClass-Aufschlüsselung, Setup-/Warte-/Transport-Summen, Kosten-/Scrap-Rollup je Währung (Formel/Datenbasis hinterlegt, aber noch ohne Editor-Panel — Abschnitt H) |

**Hinweis zur „Nachher"-Spalte (ergänzt, Review-Fix PR #341):** Alle neun Zeilen beschreiben den
per Unit-/Komponententest und Code-Review verifizierten Soll-Zustand des Codes — keine Zeile wurde
bislang in einem echten Browser gegen die jetzt Flag-ON geschaltete Konfiguration bestätigt (s.
Abschnitt H, Limitation 7). Die Tabelle zeigt „was der Code laut Tests tut", nicht „was ein Nutzer
im Browser bereits bestätigt gesehen hat".

## H. Verbleibende Limitationen (ehrlich, nichts versteckt)

1. **Rüstkosten-Coverage ~20 %.** `ruestkosten → setupCostPerUnit` liegt in beiden Splits bei nur
   19,7 %/21,4 % (step-weighted), gegenüber 78-99 % bei allen anderen 11 Primärfeldern. Ursache
   aktiv geprüft und ausgeschlossen als Parser-Fehler: 100 % der 1117 Fehlgründe (dev) sind
   `cell_empty` — die Quellzelle ist in den meisten Fertigungsschritten schlicht leer, eine reale
   Eigenschaft der QAF-Dokumente (Rüstkosten werden dort erkennbar nur für ausgewählte Schritte
   geführt). Keine Aktion vorgesehen.
2. **Rename = REMOVED_FROM_SOURCE + NEW_IN_SOURCE.** Eine im Quelldokument umbenannte Fertigungsstation
   hat keine stabile Identität (kein Prozess-UUID im QAF) und erscheint bei Reimport als zwei
   getrennte Ereignisse statt eines einzelnen `SOURCE_CHANGED`. Eine Positions-Fallback-Heuristik
   wurde bewusst **nicht** gebaut — das wäre exakt die Art Raten, die das Programm verbietet (E6).
3. **Multi-QAF-Kleinstichproben.** Nur 9 Multi-QAF-Dateien insgesamt über beide Splits (Sub-Familien
   `81_custom`/`mqaf_v1`/`mqaf_v2`, je n=1-3) — zu klein für belastbare Familien-Prozentaussagen.
   Beobachtete Schwankungen (z. B. `81_custom` 100 % dev vs. 33 % validation, n=3) sind
   Stichproben-Artefakte, kein Bug-Verdacht.
4. **Holdout-Split verbraucht.** Die 75 Holdout-Dateien wurden am 16.07.2026 durch einen anderen
   Workstream (KAR-963) bereits einmalig verwendet — für QVS TABU seit P6, kein Ersatz-Holdout
   fabriziert. Die berichteten Zahlen stützen sich ausschließlich auf dev (Kalibrierung) + validation
   (verbindlich).
5. **Kein Prozess-Count-Ground-Truth-Datensatz — Kais-Entscheid: wird nicht gebaut.** Es existiert
   kein Datensatz mit von Hand geprüften „erwarteten" Prozessschritt-Zahlen je QAF-Datei (P6 hat das
   systematisch geprüft: `manifests/`, `profiles/*.json`, kein `golden/`-Verzeichnis mit solchen
   Werten, keine Treffer für „groundTruth"/„expectedProcessCount" in kadi-v2 oder im Korpus-Repo).
   Der in der Spec vorgesehene Vergleich „erkannt vs. erwartet" bleibt daher strukturell auf
   „erkannt" (deskriptiv) beschränkt. **Entscheidung (P7, Kais):** Ein manuelles Ground-Truth-Set
   wird **nicht** aufgebaut — Begründung: der Preview-Dialog macht Erkennungslücken bereits vor jedem
   einzelnen Import sichtbar (Coverage-Zeile, fehlende Felder mit Grund), eine nachträgliche
   Ground-Truth-Vermessung des gesamten Korpus wäre ein eigenständiger, nicht-trivialer Aufwand ohne
   unmittelbaren Nutzen; eine Nachmessung erfolgt erst bei einem konkreten, fallbezogenen BMW-Zweifel
   an einer bestimmten Datei, nicht pauschal im Voraus.
6. **`rls-user-scoped.test.ts` — vorbestehende, unabhängige Testlücke, präziser gefasst (Review-Fix
   PR #341).** 9 Kerntabellen (`projects`, `process_steps`, `cycle_measurements`,
   `workshop_actions`, `qaf_uploads`, `user_profiles`, `assessments`, `oee_records`, `documents` —
   **keine davon Teil des QVS-Datenmodells**) stehen als 36 unbedingte `it.todo()`-Platzhalter in
   dieser einen Datei (kein Env-Var-Gate). Real getestet sind davon 2: `projects`
   (`rls-projects-isolation.test.ts`, R61) und `process_steps`
   (`rls-project-children-isolation.test.ts`, R61/KAR-788-Teillieferung) — beide Teil der
   67/67-Runde. 2 weitere (`qaf_uploads`, `workshop_actions`) sind laut
   `scripts/rls-test/setup.sql` durch dasselbe `*_own`-Muster wie `process_steps` „representative"
   abgedeckt — ein dokumentierter Analogie-Anspruch, kein eigener Test. Echte Rest-Lücke ohne jede
   Testdatei: `cycle_measurements`, `user_profiles`, `assessments`, `oee_records`, `documents` (5
   von 9). Kein QVS-Regressionsbefund (die Datei existierte unverändert vor QVS), aber
   sicherheitsrelevant genug für die verbleibenden 5, um hier erneut benannt zu werden (KAR-788 hat
   den `process_steps`-Teil geliefert und ist für den Rest reopened —
   `unresolved-limitations.md` §1.3, Entscheidung über Folge-Ticket liegt bei Kais).
7. **Browser-End-to-End ausstehend — der zentrale Punkt für diesen PR.** Der komplette Klick-Pfad
   (Button → Preview → Erstellen → Editor, Duplikat-Fall, Reimport über mehrere echte Syncs,
   `/wertstrom`-Liste gegen `value_stream_imports`) wurde **nie in einem echten Browser gegen die
   jetzt Flag-ON geschaltete Konfiguration gefahren** — das Flag war während der gesamten
   Entwicklung (P1-P6) `false`. Bisherige Abdeckung ist Unit-/Komponententest + Code-Review, keine
   Browser-Session. Das ist **nach diesem Merge der ausstehende, operator-seitige
   Live-Verifikationsschritt** — hier ausdrücklich **nicht** als erledigt dargestellt.
8. **Kennzahlen-Explain ohne Editor-Panel.** Die P4-Kennzahlen (`computeVaClassBreakdown`,
   Setup-/Warte-/Transport-Summen, Kosten-/Scrap-Rollup) liefern korrekt berechnete, unit-getestete
   `MetricExplain`-Objekte (Formel + Datenbasis) — es gibt aber noch **kein Editor-Panel**, das sie
   einem Nutzer anzeigt. Ein Folge-Task, kein Regressionsbefund.
9. **Fehlende Editier-Operationen (vorbestehend, außerhalb QVS-Scope; Beleg korrigiert, Review-Fix
   PR #341).** Duplizieren/Gruppieren/Splitten/Zusammenführen von Prozessschritten sowie Undo und
   volle Wertstrom-Versionierung existieren im Editor nicht — eine vorbestehende, von QAF/QVS
   unabhängige Editor-Grenze (keine QVS-Regression). Korrektur: `gap-analysis.md` „Nicht-Gaps"
   nennt nur „kein Undo, Desktop-only, tote layout-Spalte, Titel-Edit, Offline-Fähigkeit" —
   Duplizieren/Gruppieren/Splitten/Zusammenführen stehen dort NICHT (0 Treffer, Volltextsuche);
   diese vier werden hier zum ersten Mal explizit als Limitation benannt, nicht bereits vorab
   gescoped.
10. **KAR-977 / KAR-941 — im Repo nicht auffindbar.** Beide als „bekannte Altlasten" im
    Programmkontext genannten Ticket-IDs finden sich in keiner Repo-Quelle (`reports/`,
    `CHANGELOG.md`, `TODO.md`, `docs/`, komplette Git-Historie). Da Linear laut Auftrag nicht
    angefasst werden soll, konnte ihr Inhalt nicht verifiziert werden — inhaltlich weiterhin
    **OFFEN**, nur als Platzhalter zitiert.
11. **Rollback-Rest-Verhalten.** Nach einem Flag-Rollback bleibt der „Synchronisieren"-Button für
    bereits importierte Wertströme sichtbar, aber funktionslos (die Server-Aktion lehnt ab) — siehe
    `docs/runbooks/qaf-value-stream-rollout.md` Abschnitt 2 für das vollständige, code-verifizierte
    Verhalten. Kein Datenverlust, aber ein sichtbar toter Button bis zu einem möglichen Folge-Fix.

---

## Quellen

- `docs/adr/024-qaf-value-stream-integration.md` (Leitentscheidungen E1-E7; P7-Status-Nachtrag in
  diesem PR ergänzt, Review-Fix — kein veralteter Flag-Stand mehr)
- `reports/qaf-value-stream-architecture.md`, `-current-state.md`, `-gap-analysis.md`,
  `-field-mapping.md`, `-ux-flow.md`, `-corpus-evidence.md`
- `reports/qaf-value-stream-test-results.md`, `-validation-results.md`, `-regression-results.md`
  (§3 in diesem PR präzisiert, Review-Fix)
- `reports/unresolved-limitations.md` (§1.3 in diesem PR präzisiert, Review-Fix)
- `reports/qaf-value-stream-acceptance-criteria.md` (40-Kriterien-Einzelbilanz, dieser PR)
- `docs/runbooks/qaf-value-stream-rollout.md` (Rollback-Runbook, dieser PR)
- CHANGELOG.md, Einträge QVS-P0 bis QVS-P6 (2026-07-17/18) und QVS-P7 (dieser PR)
- `lib/qaf-value-stream/README.md` (öffentliche API je Phase; in diesem PR auf den P7-Flag-Stand
  aktualisiert, Review-Fix — zuvor veraltet)
- `docs/adr/README.md` (ADR-Registry-Zeile 024; in diesem PR auf den P7-Flag-Stand aktualisiert,
  Review-Fix)
- MIGRATIONS.md §7o/R36 (Migrations-Apply-Nachweis; Flag-Aussage in diesem PR auf den P7-Stand
  aktualisiert, Review-Fix — zuvor veraltet, s. CHANGELOG-Review-Fixes-Absatz für den vollständigen
  Stand: keine der hier zitierten Quellen enthält nach diesem PR noch eine durch den Flip falsch
  gewordene Aussage)
