From 6fb43fb4111f7e2360e1051098073bc56e1f94cd Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sun, 12 Jul 2026 11:51:31 +0900 Subject: [PATCH] test: validate normalized learning store contract --- .../validate_normalized_learning_store_v1.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tools/validate_normalized_learning_store_v1.py diff --git a/tools/validate_normalized_learning_store_v1.py b/tools/validate_normalized_learning_store_v1.py new file mode 100644 index 00000000..859f0105 --- /dev/null +++ b/tools/validate_normalized_learning_store_v1.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] + + +def main() -> int: + migration = ROOT / "src/dotnet/QuantEngine.Infrastructure/Migrations/V5__Add_Normalized_Learning_History.sql" + writer = ROOT / "src/dotnet/QuantEngine.Infrastructure/Repositories/NormalizedLearningStore.cs" + contract = ROOT / "src/dotnet/QuantEngine.Core/Interfaces/INormalizedLearningStore.cs" + dbml = ROOT / "docs/db/quantengine.dbml" + program = ROOT / "src/dotnet/QuantEngine.Web/Program.cs" + checks = { + "migration_exists": migration.exists(), + "writer_exists": writer.exists(), + "contract_exists": contract.exists(), + "dbml_exists": dbml.exists(), + "di_registration": "INormalizedLearningStore" in program.read_text(encoding="utf-8"), + "training_projection": "training_example_v1" in migration.read_text(encoding="utf-8"), + "outcome_upsert": "ON CONFLICT (decision_id, horizon_days)" in writer.read_text(encoding="utf-8"), + "dbml_v5_tables": all(name in dbml.read_text(encoding="utf-8") for name in ( + "source_observation", "factor_observation", "decision_event", "outcome_evaluation")), + } + gate = "PASS" if all(checks.values()) else "FAIL" + payload = {"formula_id": "NORMALIZED_LEARNING_STORE_V1", "gate": gate, "checks": checks} + output = ROOT / "Temp/normalized_learning_store_v1.json" + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(json.dumps(payload, indent=2), encoding="utf-8") + print(json.dumps(payload, indent=2)) + return 0 if gate == "PASS" else 1 + + +if __name__ == "__main__": + raise SystemExit(main())