"""Kill-switch day-exclusion store + resume tests (REQ-046 / BAT-012). Tests the InMemoryKillSwitchStore and KillSwitchService.resume(). View-masking through build_snapshot_envelope was removed in BAT-035 (dcy-025). Exclusion semantics are now tested at the store level. """ from __future__ import annotations from datetime import date import pytest from trex_core.application.killswitch import KillSwitchService from trex_core.application.portfolio import ( GLOBAL_KILLSWITCH, InMemoryKillSwitchStore, ) from trex_core.domain.slot import SlotService from trex_core.domain.slot.in_memory_repository import InMemorySlotRepository _DAY = date(2026, 6, 7) _DAY_NEXT = date(2026, 6, 8) @pytest.fixture def ks_store(): return InMemoryKillSwitchStore() def test_portfolio_exclusion_recorded(ks_store): """AC-1: excluding a portfolio records it in the store for the day.""" ks_store.exclude("pf-A", _DAY) assert "pf-A" in ks_store.list_excluded(_DAY) assert "pf-B" not in ks_store.list_excluded(_DAY) def test_global_exclusion_uses_sentinel(ks_store): """AC-2: global exclusion uses GLOBAL_KILLSWITCH sentinel.""" ks_store.exclude(GLOBAL_KILLSWITCH, _DAY) assert GLOBAL_KILLSWITCH in ks_store.list_excluded(_DAY) def test_day_scoped_auto_recovery(ks_store): """AC-4: next trading day, the exclusion is absent (day-scoped).""" ks_store.exclude("pf-A", _DAY) assert "pf-A" not in ks_store.list_excluded(_DAY_NEXT) def test_persistence_same_day(ks_store): """AC-5: same day, exclusion persists across repeated calls.""" ks_store.exclude("pf-A", _DAY) assert "pf-A" in ks_store.list_excluded(_DAY) assert "pf-A" in ks_store.list_excluded(_DAY) def test_resume_clears_exclusion(ks_store): """AC-6: resume (clear) removes the exclusion for that day.""" repo = InMemorySlotRepository() svc = KillSwitchService(slot_repo=repo, slot_service=SlotService(repo), killswitch_store=ks_store) ks_store.exclude("pf-A", _DAY) assert "pf-A" in ks_store.list_excluded(_DAY) svc.resume(scope="portfolio", portfolio_id="pf-A", now=__import__("datetime").datetime(2026, 6, 7, 6, tzinfo=__import__("datetime").timezone.utc)) assert "pf-A" not in ks_store.list_excluded(_DAY) def test_no_exclusion_empty_list(ks_store): """Baseline: with no exclusions, list_excluded returns empty set.""" assert ks_store.list_excluded(_DAY) == set() def test_clear_without_prior_exclude_is_noop(ks_store): """Clearing a non-excluded portfolio is safe (no exception).""" ks_store.clear("pf-X", _DAY) assert ks_store.list_excluded(_DAY) == set()