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.
7.9 KiB
| id | type | role | representation | state | knowledge_schema |
|---|---|---|---|---|---|
| object/ac1df780-019b-bb11-cb91-4edaa49e1843 | arch | history | canonical | historical | 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_versionin 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 A–J ✅ (test_shared_repository)
- Phase 5 20/20 ✅
- Phase 6 14/14 ✅
- Phase 7 A–J ✅
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.pynutzt FakeStorage für den Gate-Pfad; echtes DB-Persistieren der BLOCKED-Runs wird im Container (Deploy) verifiziert.