# Holdout-Erstnutzung (KAR-963/P6, Master-Prompt §29/§43) — EINMALIGER Lauf

**Datum:** 16.07.2026. **Pipeline:** kadi-v2 `main`, Commit `b7753f5` (KAR-962/#329,
letzter gemergter PR des Programms). **Werkzeug:** `qaf-corpus/tools/batch-runner.ts`
(unverändert — identische Funktionen wie `app/qaf-differences/actions.ts`s echter
Ingest-Pfad: `loadExcelWorkbook → detectG60 → detectMultiQaf → buildTemplateFingerprint`),
plus ein lokales, NICHT committetes Scratch-Skript für `detectNotAQaf`/
`detectCostAllocationFamily` (gelöscht nach Erhebung, Ergebnis hier persistiert — gleiche
Disziplin wie `p5-metrics.md`). Keine Zellwerte/Preise erfasst, nur Strukturbefunde.

**Dies ist der einzige Lauf des `splits/holdout.json`-Sets (75 Dateien) über die
gesamte Programmlaufzeit.** Vor diesem Report wurde der Holdout-Split nachweislich
nicht angerührt (`splits/README.md`: „NUR einmalig am Programm-Ende … bis dahin TABU";
`p5-metrics.md` Zeile 28 bestätigt „Holdout … wurde nicht angerührt" für P5).

## 0. Korpus-Hygiene-Befund vor dem Lauf (wichtig für die Zahleninterpretation)

Beim Aufbau des Holdout-Arbeitsverzeichnisses (rekursiver Scan von `incoming/`,
Auflösung der 75 `splits/holdout.json`-Dateinamen gegen den echten Dateibaum) fiel auf:

- `incoming/` enthält **376** Excel-Dateien insgesamt, nicht 374 — `incoming/QAFs/`
  allein enthält exakt **374** (die kanonische Population, aus der Manifest/Splits/
  `batch-report.md` gebaut wurden), plus **2 zusätzliche Dateien direkt in
  `incoming/`** (`Lieferant_1_BT_1 3.xlsx`, `Lieferant_2_BT_1 3.xlsx`), die
  denselben Dateinamen wie bereits in `incoming/QAFs/` vorhandene Dateien tragen,
  aber **unterschiedlichen SHA-256-Hash** haben (verifiziert: `e81c1e9…` vs.
  `b19e003…` für die BT_1-Datei) — also keine exakten Duplikate, sondern
  vermutlich später separat abgelegte Revisionen/Re-Uploads außerhalb der
  manifestierten 374er-Population.
- **Konkrete Auswirkung auf den Holdout-Split:** `splits/holdout.json` referenziert
  Dateien nur über den bloßen Dateinamen (`"file": "Lieferant_2_BT_1 3.xlsx"`),
  nicht über den relativen Pfad. Für diesen einen Eintrag ist die Zuordnung
  dadurch **ambig** — zwei physisch unterschiedliche Dateien tragen denselben
  Namen. Kanonisch (aus derselben Population wie Manifest/Split gebaut) ist
  `incoming/QAFs/Lieferant_2_BT_1 3.xlsx`.
- **Behandlung:** um keine Daten stillschweigend zu verlieren (Master-Prompt §0.3),
  wurden **beide** Kandidaten verarbeitet (n=76 statt 75). Ergebnis: beide liefern
  identische `standardTemplateFingerprint`-Werte (`modified`/`QAF_V9_SUMMARY`,
  Facet-Coverage summary/manufacturing/material=1.0, sbm=0.865, rmr=0) — die
  Ambiguität ändert **keine** der unten berichteten Kennzahlen messbar. Alle
  Tabellen unten verwenden n=76 (75 offizielle Holdout-Einträge + 1 zusätzlicher
  Kandidat aus dieser Namenskollision); wo relevant ist n=75 (kanonisch, nur
  `QAFs/`-Version gezählt) in Klammern angegeben.
- **Einordnung:** dies ist ein neuer, bisher nicht dokumentierter Korpus-Integritäts-
  Befund (Master-Prompt §5 „duplicate filenames" — bisher nur für exakte Content-
  Duplikate geprüft, nicht für Namenskollisionen mit unterschiedlichem Inhalt).
  Empfehlung für ein Folge-KAR: Split-Dateien auf `relative_path` statt bloßen
  Dateinamen umstellen; die 2 zusätzlichen `incoming/`-Root-Dateien entweder ins
  Manifest aufnehmen (Korpus würde auf 376 wachsen) oder als bewusst
  außerhalb der Programm-Population liegend markieren.

## 1. Lade-/Crash-/Timeout-Rate (Master-Prompt §38, §43 Punkt 1)

| Metrik | Holdout (n=76) | Validation-Referenz (n=70, gleicher Lauf/Pipeline, siehe §3) |
|---|---|---|
| Erfolgreich geladen | 76/76 (100%) | 70/70 (100%) |
| Crash (`unexpected_crash`) | 0/76 (0%) | 0/70 (0%) |
| Timeout (60s-Limit) | 0/76 (0%) | 0/70 (0%) |
| Dateien mit ≥1 strukturiertem Fehler-Finding | 11/76 (14.5%) | 6/70 (8.6%) |

**0 Crashes, 0 Timeouts auf dem vollständig unberührten Holdout** — die
Promise.allSettled-Entkopplung (KAR-958/P1) und die Partial-Extraction-Fixes
(B5-B11-Muster) generalisieren nachweislich auf nie zuvor gesehene Dateien.

## 2. Klassifikations-Verteilung (primaryClassification)

| Klasse | Holdout (n=76) | Anteil | Validation (n=70) | Anteil |
|---|---|---|---|---|
| standard_summary | 74 | 97.4% | 67 | 95.7% |
| confirmed_multi_qaf | 1 | 1.3% | 3 | 4.3% |
| ambiguous | 1 | 1.3% | 0 | 0% |
| g60_detail | 0 | 0% | 0 | 0% |
| legacy_xls_unsupported | 0 | 0% | 0 | 0% |
| timeout / crash | 0 | 0% | 0 | 0% |

Verteilung liegt in derselben Größenordnung wie Validation und wie die
Vollkorpus-Baseline (`batch-report.md`: 95.7% standard_summary, 2.7%
confirmed_multi_qaf) — keine auffällige Verschiebung.

## 3. Template-Fingerprint-Klassifikation + Facet-Coverage je Modul (§38 Sheet/Field Coverage)

Gleicher Lauf, gleiche Pipeline, zusätzlich am selben Tag gegen `splits/validation.json`
(70 Dateien) ausgeführt — **nicht** zum erneuten Debuggen einzelner Fälle, sondern
ausschließlich um Holdout vs. Validation auf identischer Pipeline vergleichbar zu
machen (Validation war laut `p5-metrics.md` bereits mehrfach für Phasen-Metriken
genutzt worden, das ist kein neuer Regelbruch).

| | Holdout (n=76) | Validation (n=70) |
|---|---|---|
| `known` | 1 (1.3%) | 0 (0%) |
| `modified` | 70 (92.1%) | 68 (97.1%) |
| `unknown` | 5 (6.6%) | 2 (2.9%)|

| Facet (Ø Coverage, Anzahl auswertbar) | Holdout | Validation |
|---|---|---|
| summary | 0.999 (n=71) | 0.998 (n=68) |
| manufacturing | 0.979 (n=65) | 0.980 (n=62) |
| material | 0.918 (n=70) | 0.886 (n=66) |
| sbm | 0.620 (n=70) | 0.611 (n=68) |
| rmr | 0.000 (n=69) | 0.000 (n=65) |
| lccn | 0.667 (n=2) | 0.493 (n=5) |
| co2e | — (n=0) | 0.000 (n=1) |

**Holdout liegt auf jeder Facette innerhalb ±0.03 der Validation-Zahl, bei
material sogar leicht darüber (0.918 vs. 0.886).** Die SBM-Lücke (~0.62, nie
1.0) und die RMR-Lücke (0.0, strukturell nie erkannt) — beide bereits in
`p5-metrics.md` als bekannte, nicht in diesem Programm behobene
Kalibrierungslücken dokumentiert — reproduzieren sich identisch auf dem
Holdout. Das ist erwartetes, konsistentes Verhalten, kein neuer Befund.

## 4. Degradations-Quote (0-Fertigungskosten-Zeilen-Symptom)

11/76 (14.5%) Holdout-Dateien vs. 6/70 (8.6%) Validation-Dateien zeigen das
bereits aus `batch-report.md`/`gate-audit.md` bekannte
`manufacturing-parse: Keine passenden Spalten gefunden`-Finding (Header-Format
wird nicht erkannt — B14-Symptomklasse, Summary-Daten bleiben dank P1-Fix
erhalten, nur die Fertigungskosten-Zeilen fehlen).

**Wichtig — alle 11 Holdout-Treffer sind bereits bekannte Fehlerklassen, keine
neuen:**

| Datei-Cluster | Anzahl (Holdout) | Bereits dokumentiert in |
|---|---|---|
| `QAF 5A208xx`-Cluster (nicht standardisierter Fertigungskosten-Header) | 4 | `batch-report.md` §3a ("QAF 5A208xx/5A25B3x-Cluster, 13 Dateien") |
| BMW G70/I20-Neugeneration (2024/2025, `.xlsm`) | 1 | `batch-report.md` §3a + `gate-audit.md` Root-Cause-Tabelle ("Neue/unbekannte BMW-Template-Generation") — dieser konkrete Datei-Typ (Plant-Data-Workbook) liegt AUSSERHALB der 3 von KAR-961/P4 onboardeten Umlageschema-Kalkulation-Dateien |
| Nicht-QAF-Dateien (Preismatrix/Checkliste/Analyse-Workbook) | 3 | dieselben 3 Dateien, die auch `detectNotAQaf` unabhängig flaggt, siehe §5 |
| Multi-QAF (Single-Value-Parser kann Mehrspalten-Varianten strukturell nicht lesen) | 1 | dokumentierte Capability-Grenze (`qaf-type-detector.ts`, `gate-audit.md` §2.2 LEGITIM) |
| JIT-Liefermatrix (kein QAF, `ambiguous` klassifiziert) | 1 | `batch-report.md` §3c, Schwesterdatei `Jit Matrix Vergabe.xlsx` bereits in `quarantine/candidates.json` |
| Diese Namenskollision (`Lieferant_2_BT_1 3.xlsx`, s. §0) | 1 | — kein Fehler, aus Coverage-Sicht `modified`/hohe Coverage, nur der Vollständigkeit halber hier NICHT mitgezählt (es hat gar keinen Manufacturing-Parse-Fehler) |

Kein Holdout-Treffer fällt in eine Fehlerklasse, die nicht schon vor P6 bekannt
war. Das ist ein starkes Generalisierungssignal: das System versagt auf
nie gesehenen Dateien exakt dort, wo es laut Vorab-Analyse erwartbar war —
nicht an neuen, unvorhergesehenen Stellen.

## 5. Not-a-QAF-Erkennungsquote (`detectNotAQaf`, Master-Prompt §30)

3/76 (3.9%) Holdout-Dateien als `not_a_qaf` (SUSPECTED, kein Hard-Reject)
erkannt: eine Preismatrix, eine Analyse-Vergleichsdatei, eine
CN-Boost-Auflistung (Dateinamen intern dokumentiert, hier aus
Vertraulichkeitsdisziplin nicht wiederholt — sind exakt 3 der Dateien aus
§4-Tabelle). **Alle 3 waren bereits in `batch-report.md` §3b (Vollkorpus-Baseline
vor jeder Implementierung) als vermutliche Nicht-QAFs vermerkt** — der
`not-a-qaf-detector.ts` (KAR-962/P5, nie gegen Holdout kalibriert) bestätigt sie
jetzt strukturell und unabhängig auf einem Split, der beim Bau des Detektors nie
verwendet wurde. Das ist der stärkste einzelne Beleg gegen Overfitting in diesem
Report: der Detektor generalisiert korrekt auf 3 ihm nie gezeigte Dateien.

Bekannte, hier NICHT behobene Lücke (bereits im KAR-957-Auftrag als offenes
Risiko benannt): von den ~8 im Capability-Analyse-Finding vermuteten
Nicht-QAF-Kandidaten im Gesamtkorpus sind jetzt 3 (dev-Split, `quarantine/
candidates.json`) + 3 (dieser Holdout-Lauf) = **6 von ~8 strukturell bestätigt**
— eine Verbesserung gegenüber dem zuvor dokumentierten Stand „nur 3/8 erkannt"
(P5-Zeitpunkt), aber weiterhin nicht vollständig (die restlichen ~2 liegen
vermutlich im Validation-Split oder sind unter einer anderen Klassifikation
versteckt — nicht in diesem Programm abschließend identifiziert).

## 6. Performance

| Metrik | Holdout | Validation |
|---|---|---|
| p50 | 394 ms | 396 ms |
| p95 | 2839 ms | 3026 ms |
| max | 11024 ms | 3796 ms |
| Dateien >10s | 1 | 0 |

Der einzige Ausreißer (11.0s) ist `171103_Multi-QAF_CLARWE_EU_sz2_SZ_ABD__NEU.xlsx`
— bereits in `batch-report.md` §3d als bekannter Performance-Ausreißer
dokumentiert (1.21 MB Multi-QAF-Datei). Kein neuer Hänger, deutlich unter dem
60s-Timeout.

## 7. Gesamtbewertung — Overfitting-Signal: NEIN

Auf jeder gemessenen Achse (Lade-/Crash-Rate, Klassifikationsverteilung,
Facet-Coverage je Modul, Performance) liegt der niemals zuvor berührte
Holdout-Split innerhalb der Schwankungsbreite des Validation-Splits — auf
`material` sogar leicht darüber. Die einzige zahlenmäßig größere Abweichung
(Degradations-Quote 14.5% vs. 8.6%) verteilt sich vollständig auf bereits vor
diesem Programm dokumentierte, bekannte Fehlerklassen (BMW-G70/I20-Neugeneration,
5A208xx-Cluster, Nicht-QAF-Dateien, Multi-QAF-Grenze) — nicht auf neue,
unerwartete Fehlerarten. Bei n=76 vs. n=70 ist eine Differenz von 5 Dateien
(14.5% vs. 8.6%) statistisch nicht robust genug, um sie als eigenständigen
Trend zu werten; sie wird hier trotzdem ehrlich берichtet, nicht geglättet.

**Ehrliches Fazit:** Die Kalibrierung generalisiert. Kein Hinweis auf
Overfitting an dev/validation. Die bekannten strukturellen Lücken (SBM/RMR-
Coverage, BMW-G70/I20-Onboarding unvollständig, ~2 verbleibende Nicht-QAF-Fälle)
bestehen unverändert fort — sie sind Kalibrierungslücken, keine
Holdout-Überraschungen.

## Quellen

- `qaf-corpus/runs/holdout-final-results.json` (76 Einzelergebnisse, Rohdaten)
- `qaf-corpus/runs/validation-final-results.json` (70 Einzelergebnisse, Rohdaten)
- `qaf-corpus/runs/holdout-notaqaf.json` (Not-a-QAF-Detektions-Rohdaten)
- `qaf-corpus/splits/holdout.json`, `qaf-corpus/splits/validation.json`
- `qaf-corpus/batch-report.md` (Vollkorpus-Baseline vor Implementierung, Vergleichsbasis für §4/§5)
- `qaf-corpus/reports/p5-metrics.md` (known/modified-Kalibrierung dev/validation)
- `qaf-corpus/reports/gate-audit.md` (Root-Cause-Klassen für §4)
- Git-Commit der geprüften Pipeline: `b7753f5` (main, KAR-962/#329)
