DockerSpace / tests /test_close_loop_validation.py
DennisChan0909's picture
feat: integrate local architecture with HF Space
e610a2f
Raw
History Blame Contribute Delete
4.41 kB
import json
import pytest
from scripts.close_loop_validate import (
GateConfig,
ValidationMetrics,
ValidationRegistry,
evaluate_promotion_gate,
is_feature_version_promoted,
)
def _metrics(
*,
accuracy: float = 50.0,
direction_accuracy: float = 48.0,
signal_count: int = 100,
buy_signal_win_rate: float = 55.0,
severe_data_warnings: int = 0,
) -> ValidationMetrics:
return ValidationMetrics(
accuracy=accuracy,
direction_accuracy=direction_accuracy,
signal_count=signal_count,
buy_signal_win_rate=buy_signal_win_rate,
severe_data_warnings=severe_data_warnings,
)
def test_promotion_gate_passes_when_all_thresholds_clear():
baseline = _metrics()
candidate = _metrics(
accuracy=55.0,
direction_accuracy=46.0,
signal_count=70,
buy_signal_win_rate=55.0,
severe_data_warnings=0,
)
decision = evaluate_promotion_gate(
baseline,
candidate,
GateConfig(
min_accuracy_delta_pp=5.0,
min_direction_delta_pp=-2.0,
min_signal_count_ratio=0.70,
),
)
assert decision.passed is True
assert decision.failed_checks == []
assert decision.deltas["accuracy_delta_pp"] == pytest.approx(5.0)
assert decision.deltas["direction_accuracy_delta_pp"] == pytest.approx(-2.0)
assert decision.deltas["buy_signal_win_rate_delta_pp"] == pytest.approx(0.0)
@pytest.mark.parametrize(
("candidate_overrides", "failed_check"),
[
({"accuracy": 54.9}, "accuracy_delta_pp"),
({"direction_accuracy": 45.9}, "direction_accuracy_delta_pp"),
({"signal_count": 69}, "signal_count_ratio"),
({"buy_signal_win_rate": 54.9}, "buy_signal_win_rate_delta_pp"),
({"severe_data_warnings": 1}, "severe_data_warnings"),
],
)
def test_promotion_gate_fails_when_any_required_condition_fails(
candidate_overrides,
failed_check,
):
baseline = _metrics()
candidate_kwargs = {
"accuracy": 55.0,
"direction_accuracy": 46.0,
"signal_count": 70,
"buy_signal_win_rate": 55.0,
"severe_data_warnings": 0,
}
candidate_kwargs.update(candidate_overrides)
decision = evaluate_promotion_gate(
baseline,
_metrics(**candidate_kwargs),
GateConfig(
min_accuracy_delta_pp=5.0,
min_direction_delta_pp=-2.0,
min_signal_count_ratio=0.70,
),
)
assert decision.passed is False
assert failed_check in decision.failed_checks
def test_validation_registry_reports_promoted_feature_version(tmp_path):
registry_path = tmp_path / "validation_registry.json"
registry_path.write_text(
json.dumps({"promoted_feature_version": "features_c21_oldwang"}),
encoding="utf-8",
)
registry = ValidationRegistry(registry_path)
assert registry.get_promoted_feature_version() == "features_c21_oldwang"
def test_validation_registry_rejects_unpromoted_feature_versions(tmp_path):
registry_path = tmp_path / "validation_registry.json"
registry_path.write_text(
json.dumps({"promoted_feature_version": "features_c21_oldwang"}),
encoding="utf-8",
)
registry = ValidationRegistry(registry_path)
with pytest.raises(ValueError, match="not promoted"):
registry.assert_promoted_feature_version("features_c22_unvalidated")
def test_missing_registry_fails_closed_for_publishability(tmp_path):
missing = tmp_path / "missing_registry.json"
assert not is_feature_version_promoted("institutional-macd-oldwang-v2", missing)
def test_corrupt_registry_fails_closed_for_publishability(tmp_path):
registry_path = tmp_path / "validation_registry.json"
registry_path.write_text("{not-json", encoding="utf-8")
assert not is_feature_version_promoted("institutional-macd-oldwang-v2", registry_path)
def test_registry_requires_promoted_status_pass(tmp_path):
registry_path = tmp_path / "validation_registry.json"
registry_path.write_text(
json.dumps(
{
"promoted": {
"feature_version": "features_c22_unvalidated",
"status": "fail",
}
}
),
encoding="utf-8",
)
assert not is_feature_version_promoted("features_c22_unvalidated", registry_path)