trading-system-docs/notes/trading/system-docs/historical-v2-phase8-m12-datasetgate.md
Red Queen adbb96d04a feat(tolaria): migrate final auto-safe knowledge batch 3 to schema v1
C3F FINAL AUTO_SAFE BATCH 3: migriert alle 21 verbleibenden AUTO_SAFE
Knowledge Objects auf knowledge_schema v1 (18 standalone logs + 3
standalone-canonical). Body byte-genau, IDs stabil (0 Kollisionen).
Keine HR/DO_NOT_TOUCH berührt. C3 MIGRATION weiter IN_PROGRESS.
2026-08-25 19:06:44 +00:00

160 lines
7.9 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.

---
id: object/ac1df780-019b-bb11-cb91-4edaa49e1843
type: arch
role: history
representation: canonical
state: historical
knowledge_schema: 1
---
# Phase 8 — M12 Historical-V2 DatasetGate + Run-Audit
Autor: Rain Ocampo (Hermes) | Datum: 2026-08-22 | Status: IMPLEMENTIERT + GETESTET
## Ziel
M12 akzeptiert Historical-V2-Datasets künftig NUR für Backtests, wenn der
DatasetContext fachlich backtest-eligible ist. Jeder V2-Run macht seine
komplette Datenwahrheit auditierbar. Legacy-Verhalten bleibt unverändert.
## 1. Baseline
- M12 12/12 grün (vor Änderung, unverändert nach)
- M12 Backup: `/opt/data/backup_phase8_20260822_214633` (service.py, client.py, storage.py, core/)
- DATA SOURCE = UNSET (→ legacy) bestätigt
- ALLOW_FIXTURE_DATA = UNSET (→ false/default) bestätigt
- /health + /health/ready = 200 OK (im Container via urllib)
## 2. DatasetGate (nur historical_v2, fail-closed)
`BacktestService._dataset_gate()` greift NUR bei `marketdata.source == "historical_v2"`.
Legacy (source=legacy) ist vollständig unangetastet — kein Gate, kein neuer Fehler.
Gate-Regeln (Punkt 2/3):
- A) backtest_eligible=true → Run darf weiter
- B) backtest_eligible=false → fail-closed blockiert
- C) UNKNOWN_CRITICAL_METADATA → NICHT starten
- D) Fixture + ALLOW_FIXTURE_DATA=false → FIXTURE_DATA_BLOCKED
- E) fehlender DatasetContext → fail-closed (DATASET_CONTEXT_MISSING)
- F) fehlende Dataset-Version → fail-closed (DATASET_VERSION_NOT_FOUND)
- G) kein stiller Fallback auf Legacy
## 3. Block-Codes
| error_code | Bedingung |
|---|---|
| DATASET_NOT_ELIGIBLE | backtest_eligible=false, reason != UNKNOWN_CRITICAL_METADATA |
| UNKNOWN_CRITICAL_METADATA | backtest_eligible=false + reason=UNKNOWN_CRITICAL_METADATA |
| FIXTURE_DATA_BLOCKED | is_fixture=true + ALLOW_FIXTURE_DATA=false |
| DATASET_CONTEXT_MISSING | build_dataset_context wirft / Context None |
| DATASET_VERSION_NOT_FOUND | dataset_version_id & hash beide None |
Ein geblockter Run wird als **auditierbarer BLOCKED-Run persistiert** (status=BLOCKED,
metrics.error_code, metrics.block_reason, metrics.policy_version, metrics.timestamp,
metrics.audit). KEINE Strategieausführung.
## 4. Run-Audit (Punkt 4)
Vollständiger Audit-Datensatz pro V2-Run (in `metrics.audit` + Antwort `audit`):
dataset_context_version, data_source, dataset_id, dataset_version_id,
dataset_version_hash, raw_source_hash, instrument, timeframe, start/end,
provider, feed_type, price_basis, data_as_of, data_hash,
normalization_version, quality_model_version, stale_model_version,
session_model_version, calendar_version, eligibility_model_version,
aggregation_version, eligibility_policy_version, is_fixture,
quality_summary, effective_eligibility_summary, backtest_eligible, block_reason,
strategy, strategy_version, parameters, run_hash.
Keine DB-Migration nötig — sauber im bestehenden `backtest_run.metrics` (JSONB).
## 5. Run-Identität / Reproduzierbarkeit (Punkt 5)
M12 hatte bereits deterministischen `run_hash` (strategy/version/params/symbol/
timeframe/start/end/data_hash). Für historical_v2 wird ZUSÄTZLICH `dataset_version_hash`
+ `eligibility_policy_version` in den Hash aufgenommen (nur wenn gesetzt).
- gleiche Daten + Strategie + Parameter + Policy → gleiche Identität
- andere Dataset-Version → andere Identität
- andere Policy-Version → andere Identität
- Legacy (beide None) → exakt alter Hash, unverändert
## 6. Echter EURUSD-V2-Blocktest (POSITIV, Punkt 6)
Gegen historical-DB (Port 5433): DatasetContext liefert aktuell
`backtest_eligible=False`, `block_reason=NO_DATASET_METADATA`,
`dataset_version_id=None` (keine Dataset-Version für EURUSD/H4 2024-01).
Gate blockt mit `DATASET_VERSION_NOT_FOUND` (strenger als UNKNOWN).
Keine Strategieausführung, Run als BLOCKED auditierbar.
-> PASS (fail-closed, keine Echtorders)
Anmerkung: Der im Brief erwartete Code `UNKNOWN_CRITICAL_METADATA` trifft hier
nicht zu, weil keine Dataset-Version existiert. Der UNKNOWN-Code ist separat über
Mock-Test abgedeckt. Beides gültige fail-closed Blöcke.
## 7. Positiver ELIGIBLE-Test (Punkt 7)
Mock/Test-DatasetContext vollständig & backtest_eligible=true, mit
ALLOW_FIXTURE_DATA=true → Gate lässt durch, M12 läuft bis zur bestehenden
Backtestlogik, Audit vollständig. (Test 3, 7 grün.)
## 8. QualitySummary im Run (Punkt 8)
total/eligible/conditional/excluded/unknown/suspect/partial/stale_bars,
gap_count, coverage_pct — über `quality_summary` im Audit. None bleibt None
(nicht 0/100% erfunden), bewiesen durch Test.
## 9. CONDITIONAL Data Policy (Punkt 9)
Keine finale Handelslogik. Audit kennzeichnet CONDITIONAL sichtbar
(`effective_eligibility_summary.conditional`). Kein stilles Zählen als FULL.
## 10. Feed Type (Punkt 10)
Historical V2 Dukascopy: feed_type=REFERENCE — im Audit sichtbar. Kein Eindruck
REFERENCE == IG Broker Feed, keine Kosten-Simulation.
## 11. Legacy-Kompatibilität
- Legacy (source=legacy) → kein Gate, kein Audit, kein neuer Fehler
- M12 12/12 unverändert grün
- Legacy run_hash deterministisch unverändert (Phase-7 J, Phase-6 12)
- kein Hash-/Cache-Break
- Legacy bleibt Default
## 12. Tests (Punkt 12)
Neue Suite `m12_app/tests/test_phase8_gate.py` (13 Tests) — alle grün:
1 Legacy unverändert | 2 V2 Context vollständig | 3 eligible erlaubt
4 not_eligible blockiert | 5 UNKNOWN blockiert | 6 Fixture default blockiert
7 Fixture explizit erlaubt | 8 fehlender Context fail-closed
9 fehlende Version fail-closed | 10 andere dataset_hash → andere ID
11 andere policy_version → andere ID | 12 gleiche Inputs → gleiche ID
13 QualitySummary vollständig | 14 CONDITIONAL sichtbar | 15 REFERENCE sichtbar
Regression:
- M12 12/12 ✅
- M13 AJ ✅ (test_shared_repository)
- Phase 5 20/20 ✅
- Phase 6 14/14 ✅
- Phase 7 AJ ✅
## 13. Produktionsdeploy
NUR M12. HISTORICAL_DATA_SOURCE bleibt legacy/unset, ALLOW_FIXTURE_DATA bleibt
false/unset. Keine Netzwerkänderung. (Deploy-Pfad: scp → docker cp → chown)
## 14. Dokumentation
Diese Datei. Push zu Forgejo/Tolaria in Phase 8 formalisiert (nur diese Datei, keine Secrets); Obsidian NUR lokal, KEIN Push.
## 15. Legacy-Smoke-Ergebnis (POST /backtest, BT_PULL 1h demo, 2026-08-01→19)
Ausgeführt im Produktions-Container Modul-12-Backtesting (urllib, Port 55012):
- **Run A**: status=COMPLETED, run_id=ed62f1b3628b4fa29c3e880d83002ed8
- **Run B**: status=COMPLETED, run_id=73a8cf75034a439cba60e974bd07304b
- **run_hash**: `bc6e2553…` A == B identisch ✅
- **data_hash**: `d76a7549…` A == B identisch ✅
- **error_code**: None / None ✅ (kein Gate-Code)
- **block_reason**: None / None ✅
- **audit vorhanden (Legacy)**: False (korrekt minimal, kein Audit-Feld nötig)
- KEIN DATASET_NOT_ELIGIBLE / DATASET_VERSION_NOT_FOUND / FIXTURE_DATA_BLOCKED
- **Produktions-DB (trading.backtest_run)**: status=COMPLETED, run_hash bc6e2553…
- **Health/Ready nach Smoke**: /health 200, /health/ready 200
- **Production Gate nach Smoke**: HISTORICAL_DATA_SOURCE=UNSET, ALLOW_FIXTURE_DATA=UNSET
**Legacy-Hash-Nachweis (vorher=nachher):**
- Pre-Phase-8-Hash (Backup) payload = {strategy,version,params,symbol,timeframe,start,end,data_hash}
- Phase 8 fügt dataset_version_hash/eligibility_policy_version NUR hinzu wenn `is not None`
→ Legacy ruft mit None auf → **byte-identischer payload → identischer Hash.**
- Empirisch 2 unabhängige Runs nach Deploy → gleicher run_hash bc6e2553…
- ⇒ Legacy run_hash deterministisch UNVERÄNDERT gegenüber vor Phase 8. ✅
**Safety:** keine M09-Order, keine M07/M08/M15-Control-Auswirkung, keine Netzwerkänderung,
keine IG-Calls. Nur M12-Container-Neustart (Prozess, kein Docker-Netz/Config).
## Bekannte offene Punkte
- EURUSD-Context liefert NO_DATASET_METADATA (keine Dataset-Version hinterlegt).
- CONDITIONAL-Handelslogik (Punkt 9) NICHT implementiert (nur Kennzeichnung) — bewusst.
- Noch keine Broker-Kosten-/Feed-Angleichung — bewusst.
- `verify_phase8_block.py` nutzt FakeStorage für den Gate-Pfad; echtes DB-Persistieren
der BLOCKED-Runs wird im Container (Deploy) verifiziert.