Files
fxhnt/tests/unit/test_backtest_invariant.py

33 lines
1.9 KiB
Python

from fxhnt.application.backtest_refs import registry_backtest_kind
from fxhnt.application.forward_ingest import CockpitBacktestRefProvider
from fxhnt.registry import STRATEGY_REGISTRY
def _is_reconciliation_gated(entry) -> bool:
return entry.get("gate_spec", {}).get("gate_type") == "reconciliation"
def test_every_reconciliation_gated_strategy_has_a_backtest_provider():
"""THE invariant: a reconciliation-gated strategy without a non-`none` backtest kind can never gate-PASS
(its gate WAITs forever on a missing ref). Making that a CI failure is what turns a silent live gap into
a caught error. If you add a reconciliation-gated strategy, declare its `definition.backtest.kind`."""
offenders = [sid for sid, entry in STRATEGY_REGISTRY.items()
if _is_reconciliation_gated(entry) and registry_backtest_kind(sid) == "none"]
assert not offenders, f"reconciliation-gated strategies with no backtest ref provider: {offenders}"
def test_every_reconciliation_gated_model_ref_twin_has_a_resolving_alias():
"""A `model-ref` twin declares kind != none (so the test above passes) but gets its reconciliation ref
SOLELY from CockpitBacktestRefProvider._REF_ALIAS. Without an alias entry whose target resolves to a
real (non-none) provider, its gate silently WAITs forever — the vrp_exec bug. Make it structural."""
alias = CockpitBacktestRefProvider._REF_ALIAS
offenders = []
for sid, entry in STRATEGY_REGISTRY.items():
if _is_reconciliation_gated(entry) and registry_backtest_kind(sid) == "model-ref":
target = alias.get(sid)
if target is None:
offenders.append(f"{sid}: model-ref with no _REF_ALIAS entry")
elif registry_backtest_kind(target) == "none":
offenders.append(f"{sid}: alias target {target!r} has a 'none' provider")
assert not offenders, f"model-ref twins whose reconciliation ref never resolves: {offenders}"