33 lines
1.9 KiB
Python
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}"
|