Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions contracts/signals.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
},
"market_regime": {
"type": "string",
"enum": ["bull", "neutral", "caution", "bear"],
"description": "Current market regime assessment"
"enum": ["bull", "neutral", "bear"],
"description": "Current market regime assessment. 3-class Ang-Bekaert taxonomy (v0.42.0 / 2026-05-28). Legacy 4-class 'caution' retired per caution-regime-retirement-260528.md — its driving signals (VIX, HY OAS, SPY 30d return) are weighted continuously into regime_intensity_z (predictor META_FEATURE 13) rather than discretized into a 4th category. Portfolio-protective hysteresis is a separate axis on the predictor drawdown leg (risk_on/caution/risk_off). Historical signals.json artifacts with 'caution' in market_regime are grandfathered — consumers tolerant of legacy enum on read."
},
"sector_ratings": {
"type": "object",
Expand Down
35 changes: 35 additions & 0 deletions tests/integration/test_data_contract_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,41 @@ def test_missing_required_field_fails(self):
with pytest.raises(ValidationError):
validate(instance=bad_signals, schema=schema)

def test_market_regime_enum_is_3class(self):
# 3-class Ang-Bekaert taxonomy (v0.42.0 / 2026-05-28).
# Legacy 4-class "caution" retired per
# caution-regime-retirement-260528.md.
schema = _load_schema("signals.schema.json")
regime_field = schema["properties"]["market_regime"]
assert regime_field["enum"] == ["bull", "neutral", "bear"]

def test_market_regime_caution_rejected(self):
schema = _load_schema("signals.schema.json")
bad_signals = {
"date": "2026-04-03",
"run_time": "00:30:00",
"market_regime": "caution",
"sector_ratings": {},
"universe": [],
"buy_candidates": [],
}
with pytest.raises(ValidationError):
validate(instance=bad_signals, schema=schema)

def test_each_3class_regime_accepted(self):
schema = _load_schema("signals.schema.json")
for regime in ("bull", "neutral", "bear"):
signals = {
"date": "2026-04-03",
"run_time": "00:30:00",
"market_regime": regime,
"sector_ratings": {},
"universe": [],
"buy_candidates": [],
}
# Should not raise
validate(instance=signals, schema=schema)


class TestPredictionsContract:
def test_valid_predictions_pass(self):
Expand Down
Loading