From 16a104822e1017a14e1c427e69e8fd4e56075fc8 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 24 Aug 2026 11:05:32 +0000 Subject: [PATCH] Phase 13.4: Historical Data Trust Gate (Provenance + Sanity Validation) - Doku - Rain Ocampo, 24.08.2026 --- .../system-docs/phase13_4_trust_gate.md | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 notes/trading/system-docs/phase13_4_trust_gate.md diff --git a/notes/trading/system-docs/phase13_4_trust_gate.md b/notes/trading/system-docs/phase13_4_trust_gate.md new file mode 100644 index 0000000..c51fd21 --- /dev/null +++ b/notes/trading/system-docs/phase13_4_trust_gate.md @@ -0,0 +1,206 @@ +# Phase 13.4 — Historical Data Trust Gate (Provenance + Sanity Validation) + +**Status:** FINAL CLOSED (technisch verifiziert, dokumentiert) +**Datum:** 24.08.2026 +**Autor:** Rain Ocampo (Hermes) +**Freigabe:** Christian List (Phase 13.4 Finalisierung / Second-Brain-Sync) + +--- + +## 1. Ausgangsproblem (aus Phase 13.3) + +Die Phase-13.3-Forensik zeigte: **HTTP 200 + erfolgreiches Parsing bedeutet NICHT automatisch vertrauenswürdige Daten.** + +Die bekannten problematischen November-Tage (11-09, 11-10, 11-12) wurden von Dukascopy mit HTTP 200 geliefert, technisch valide geparst, aber enthielten **fachlich unplausible Daten** (falsches Preisniveau, Wochenendaktivität). Der `source_timestamp` war in allen Fällen NULL. + +**Kernbefund:** Ein reiner "Download erfolgreich + Parse erfolgreich"-Check ist unzureichend. Es fehlt eine Schutzschicht, die Provenance und fachliche Plausibilität vor der Persistierung validiert. + +--- + +## 2. Neue Pipeline-Reihenfolge + +``` +RAW DOWNLOAD + → PROVENANCE CAPTURE + → TECHNICAL PARSE + → SANITY VALIDATION + → TRUST DECISION + → SESSION + → TECHNICAL/MARKET QUALITY + → EFFECTIVE ELIGIBILITY + → GAP + → PERSIST RAW + → DERIVED + → DATASET VERSION +``` + +Das Trust Gate sitzt **nach** dem technischen Parse und **vor** der Persistierung (Schritt 4c in `backfill.py`). Es klassifiziert, es löscht nicht. + +--- + +## 3. Provenance-Modell + +`HistoricalProvenanceContext` (Version `provenance_v1`) — 16 Felder: + +| Feld | Semantik | +|------|----------| +| `provider` | Datenquelle (Dukascopy, OANDA, FXCM, Polygon, …) | +| `instrument` | Instrument (EURUSD, …) | +| `timeframe` | Zeitrahmen (M1, M5, …) | +| `source_url` | Quelle (Credentials redacted) | +| `http_status` | HTTP-Statuscode | +| `content_length` | Rohdatenlänge | +| `raw_file_sha256` | SHA-256 der Rohdatei | +| `retrieved_at` | Abrufzeitpunkt (volatile, nicht im Hash) | +| `source_timestamp` | Quell-Zeitstempel (kritisch, fail-closed) | +| `adapter_version` | Adapter-Version | +| `parser_version` | Parser-Version | +| `normalization_version` | Normalisierungs-Version | +| `code_version` | Code-/Commit-Version | +| `raw_source` | Rohquelle | +| `dataset_identity` | Dataset-Identität | + +**Keine Secrets in `source_url`** — `redact_url()` entfernt Credentials; `to_dict()` wendet Redaction an. + +--- + +## 4. Trust States + +| State | Bedeutung | Persistierbar? | +|-------|-----------|----------------| +| `TRUSTED` | Provenance vollständig, Sanity plausibel | ✅ Ja | +| `CONDITIONAL` | Warnende Hinweise (z. B. Wochenendaktivität) | ⚠️ Nur mit expliziter Policy | +| `UNTRUSTED` | Fachlich unplausible Daten | ❌ Nein | +| `UNKNOWN` | Kritische Provenance fehlt | ❌ Nein (fail-closed) | + +Version: `trust_v1` + +--- + +## 5. Reason Codes (20, erweiterbar) + +`PRICE_LEVEL_MISMATCH`, `WEEKEND_DATA_ANOMALY`, `STALE_DAY`, `ZERO_VOLUME_DAY`, `SOURCE_TIMESTAMP_MISSING`, `RAW_ARTIFACT_MISSING`, `PROVENANCE_INCOMPLETE`, `CROSS_PROVIDER_MISMATCH`, `NAN_OR_INF`, `INSTRUMENT_MISMATCH`, `TIMEFRAME_MISMATCH`, `TIMESTAMP_DUPLICATE`, `TIMESTAMP_MISSING_MINUTE`, `TIMESTAMP_OUT_OF_RANGE`, `TIMESTAMP_NON_MONOTONIC`, `REFERENCE_UNAVAILABLE`, `PROVIDER_OUTAGE`, `PROVIDER_DATA_ERROR` + +--- + +## 6. Provider-Outage vs Provider-Data-Error + +**Strikt getrennte Codepfade:** + +- **`PROVIDER_OUTAGE`** — technischer Ausfall: HTTP 404/503, Timeout, Connection-Failure +- **`PROVIDER_DATA_ERROR`** — HTTP 200, technisch valide, aber fachlich unplausible Daten + +Diese Zustände bekommen **nie denselben Status/Codepfad**. + +--- + +## 7. Sanity-Prüfungen (6 Klassen, providerneutral) + +| Klasse | Prüfung | Konfigurierbar | +|--------|---------|----------------| +| A | Price-Level (gegen unabhängige Referenz) | ✅ asset-class-aware | +| B | Weekend/Session-Anomalie | ✅ | +| C | Stale-Day (flacher Tag) | ✅ | +| D | Volume (Zero-Volume-Day) | ✅ | +| E | Cross-Provider (optional, nur Validierung) | ✅ | +| F | Timestamp (UTC, Monotonie, Duplikate, Range) | ✅ | + +**Keine universelle 1,5%-Regel.** Die Forex-Default-Toleranz wurde aus dem Phase-13.3-Befund auf **0,5%** kalibriert (die bekannten falschen Tage wichen nur 0,55–1,07% ab und wurden bei 1,5% fälschlich TRUSTED). Schwellen sind versioniert und konfigurierbar. + +--- + +## 8. Fail-Closed-Verhalten + +- **TRUSTED:** Persistierung zulässig +- **CONDITIONAL:** nur mit expliziter Policy (Audit bleibt erhalten) +- **UNTRUSTED:** nicht als normaler vertrauenswürdiger Historical-Datensatz persistieren +- **UNKNOWN:** fail-closed, sofern kritische Provenance fehlt + +--- + +## 9. Raw-Artifact-Retention + +- Content-Hash (SHA-256) + kontrollierter Artifact Store +- Keine unkontrollierte Datenexplosion +- Retention-Policy: Hash + Metadaten (Größe, Retrieval-Zeit, Provider, Instrument, Zeitraum, HTTP-Status, URL ohne Credentials) + +--- + +## 10. source_timestamp-Regel + +- **Semantik:** Quell-Zeitstempel des Datenpunkts (UTC) +- **Pflichtgrad:** kritisch +- **Range vs Einzelwert:** beides unterstützt +- **UTC:** zwingend +- **Fail-Closed:** fehlt `source_timestamp` → `SOURCE_TIMESTAMP_MISSING` → `UNKNOWN` (nicht persistierbar) +- **Keine Altbestandsmigration** (November-Daten bleiben unverändert) + +--- + +## 11. Hash / Reproduzierbarkeit + +- `provenance_hash`: deterministischer SHA-256 über die Provenance +- **Volatile `retrieved_at` wird NICHT in den deterministischen Hash aufgenommen** +- Gleiche Raw-Datei + gleiche Modelle + gleiche Konfiguration → gleicher Hash +- Andere Raw-Datei / andere Trust-Policy → unterscheidbar + +--- + +## 12. Ergebnisse + +- **Trust-Gate-Tests: 27/27 grün** +- **Phase-13.3-Reproduction: 9/9 grün** + - 11-09 (Sa): UNTRUSTED (PRICE_LEVEL_MISMATCH + WEEKEND_DATA_ANOMALY) + - 11-10 (So): CONDITIONAL (WEEKEND_DATA_ANOMALY) + - 11-12 (Di): UNTRUSTED (PRICE_LEVEL_MISMATCH) + - **Keiner TRUSTED** — Reason Codes folgen aus den Daten, nicht gefittet +- **Relevante Phase-13-Regressionen grün** (Provider-Failures, Ingestion-State, Idempotenz, Hash-Konsistenz, Daily-Report) + +--- + +## 13. Deploy / Health-Status + +- Container `historical-service`: **Up** +- `/health`: `{"status":"ok","service":"historical-data-service","version":"0.1.0-poc"}` +- `/health/ready`: `{"status":"ready","db":"connected"}` +- Trust-Gate-Code im Container importierbar +- `BackfillOrchestrator.run` kennt `trust_gate` (additiv, Standard `None` = Gate inaktiv) + +--- + +## 14. Bekannte Technical Debt (vorbestehend, NICHT Phase-13.4-Regression) + +Die folgenden 4 Fehler sind **vorbestehend** — mit dem unveränderten Pre-13.4-`backfill.py` identisch reproduzierbar (definitiv bewiesen): + +1. **Aggregation E2E** — `TypeError: float - NoneType` (DB-Wahrheit, M5-Aggregation) +2. **Read API E2E** — `/bars M5` liefert 24 statt 12 Bars +3. **Parquet POC** — M5-Export/Reimport weicht ab +4. **Test-Fixture-Trennung** — operative Daten enthalten Feb-2024-Testbars + +Diese sind **nicht** durch das Trust Gate verursacht und werden **nicht** in Phase 13.4 behoben. + +--- + +## 15. November-Daten + +- **Unverändert** (5760 Bars für 11-09 bis 11-12, alle `source_timestamp` NULL) +- **Weiterhin UNTRUSTED** — als forensischer Beweis erhalten +- Nicht gelöscht, nicht überschrieben, nicht reklassifiziert, nicht migriert, nicht repariert + +--- + +## 16. Runner / Watchdog / OANDA / Production Gates + +- **Runner p13_eurusd:** PAUSED (unverändert) +- **Watchdog:** unverändert, Recovery-only (Cron `fa8ab4da220f`, DUKASCOPY_RECOVERY ONLY) +- **OANDA:** nicht integriert (keine Credentials, keine API-Calls) +- **Production Gates:** unverändert +- **DB-Schema:** unverändert (additiv, rückwärtskompatibel) + +--- + +## 17. Nächster empfohlener Schritt (NOCH NICHT FREIGEGEBEN) + +Ein minimaler kontrollierter **End-to-End-Ingest-Test** soll später beweisen, dass das Trust Gate nicht nur in Unit-/Reproduction-Tests funktioniert, sondern im echten `DOWNLOAD → PROVENANCE → SANITY → TRUST → PERSIST`-Pfad UNTRUSTED/UNKNOWN-Daten tatsächlich VOR der Persistierung blockiert. + +**Dieser Test ist jetzt noch NICHT freigegeben.**