The Phase-0b venue re-home reset the crypto sleeves' forward OOS clock to 2026-07-14 (definition-hash change → auto-re-inception). Since these were faithful re-homes (same edge + PIT data, record_mode=recompute), the pre-re-home days are still valid OOS; on 2026-07-15 they were recovered by backdating the active anchors' t0 in the DB (unlock 06-20 → recon-gate PASS +4.57%; xsfunding/positioning/bybit_4edge/levered → 8d). That backdate lived ONLY in the DB — a full operational-Postgres rebuild would let the anchors re-incept to `today` and silently lose the recovered window. This makes it reproducible from git (the SSOT): - forward_definition.inception_override(sid): returns a definition's declared `inception_t0.date`, VERSION-PINNED (honored only when its `version` == the definition's current version — a genuine re-tune bumps `version`, auto-ignoring a stale pin and correctly getting a fresh today-clock). Lives OUTSIDE `params` so it is NOT hashed — declaring it never itself re-inceptions (verified: the five sleeves' definition_hash is byte-identical to their live DB anchors). - run_track: at inception, t0 = inception_override(sid) if present AND <= today, else today (never incept in the future — clock-skew/not-yet-reached pins fall back to today). - registry: xsfunding/unlock/positioning/bybit_4edge/bybit_4edge_levered carry their pinned pre-re-home t0 (07-07/06-20/07-06/07-07/07-07, version 2). Tests: inception_override version match/stale/absent + not-hashed + a regression pin on the recovered dates; run_track honors the pin, ignores a version-stale pin, and falls back to today for a future pin. 262 forward/registry tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
3.8 KiB
Python
73 lines
3.8 KiB
Python
from fxhnt.application.forward_definition import definition_hash, inception_override, track_definition
|
|
from fxhnt.registry import STRATEGY_REGISTRY
|
|
|
|
|
|
def test_hash_is_stable_under_key_reordering():
|
|
assert definition_hash({"a": 1, "b": 2}, 1) == definition_hash({"b": 2, "a": 1}, 1)
|
|
|
|
|
|
def test_hash_changes_when_a_param_changes():
|
|
# the BTC-drop case: instruments 6 -> 5 must change the hash
|
|
six = definition_hash({"instruments": ["SPY", "IEF", "GLD", "PDBC", "DBMF", "BTC-USD"]}, 1)
|
|
five = definition_hash({"instruments": ["SPY", "IEF", "GLD", "PDBC", "DBMF"]}, 1)
|
|
assert six != five
|
|
|
|
|
|
def test_hash_changes_when_version_bumps():
|
|
assert definition_hash({"a": 1}, 1) != definition_hash({"a": 1}, 2)
|
|
|
|
|
|
def test_every_active_track_declares_a_definition():
|
|
for sid in STRATEGY_REGISTRY:
|
|
params, version, mode = track_definition(sid)
|
|
assert isinstance(params, dict) and isinstance(version, int)
|
|
assert mode in ("recompute", "observed")
|
|
|
|
|
|
def test_observed_mode_is_exactly_the_executed_twins():
|
|
# Pin is deliberately exhaustive: whenever a new track adopts record_mode="observed", update this set
|
|
# (C2 Task 3 added bybit_4edge_exec; Task 7 added vrp_exec) so the change is reviewed, not silently
|
|
# absorbed. `xsfunding` moved OFF observed (Phase 0b venue consolidation: standalone Binance
|
|
# `XsFundingForward` -> its own Bybit single-sleeve `recompute` track, mirroring `positioning`) — the
|
|
# remaining observed tracks are the OBSERVED-fills executed twins (fills are observed, not recomputable).
|
|
observed = {sid for sid in STRATEGY_REGISTRY if track_definition(sid)[2] == "observed"}
|
|
assert observed == {"multistrat_exec", "bybit_4edge_exec", "vrp_exec"}
|
|
|
|
|
|
def test_inception_override_returns_date_when_version_matches(monkeypatch):
|
|
monkeypatch.setitem(STRATEGY_REGISTRY, "t_ov",
|
|
{"definition": {"params": {"v": 1}, "version": 2, "record_mode": "recompute",
|
|
"inception_t0": {"date": "2026-06-20", "version": 2}}})
|
|
assert inception_override("t_ov") == "2026-06-20"
|
|
|
|
|
|
def test_inception_override_ignored_when_version_stale(monkeypatch):
|
|
# a genuine re-tune bumped the definition to v3 but left the v2 override → stale → ignored (fresh clock)
|
|
monkeypatch.setitem(STRATEGY_REGISTRY, "t_ov",
|
|
{"definition": {"params": {"v": 3}, "version": 3, "record_mode": "recompute",
|
|
"inception_t0": {"date": "2026-06-20", "version": 2}}})
|
|
assert inception_override("t_ov") is None
|
|
|
|
|
|
def test_inception_override_absent_returns_none(monkeypatch):
|
|
monkeypatch.setitem(STRATEGY_REGISTRY, "t_ov",
|
|
{"definition": {"params": {"v": 1}, "version": 1, "record_mode": "recompute"}})
|
|
assert inception_override("t_ov") is None
|
|
|
|
|
|
def test_inception_t0_is_not_hashed():
|
|
# the recovered-window pin MUST live outside `params` — else declaring it would change the definition hash
|
|
# and itself re-incept the live anchor, resetting the OOS clock (the exact opposite of its purpose).
|
|
for sid in ("xsfunding", "unlock", "positioning", "bybit_4edge", "bybit_4edge_levered"):
|
|
assert "inception_t0" not in track_definition(sid)[0]
|
|
|
|
|
|
def test_re_homed_sleeves_pin_their_recovered_inception():
|
|
# Regression: the Phase-0b faithful re-homes keep their pinned pre-re-home OOS start (recovered 2026-07-15)
|
|
# so a DB rebuild reproduces the window from git instead of restarting at today. If a sleeve is genuinely
|
|
# re-tuned later, its version bumps and the (now version-stale) pin is correctly ignored — update it here.
|
|
expected = {"xsfunding": "2026-07-07", "unlock": "2026-06-20", "positioning": "2026-07-06",
|
|
"bybit_4edge": "2026-07-07", "bybit_4edge_levered": "2026-07-07"}
|
|
for sid, date in expected.items():
|
|
assert inception_override(sid) == date
|