"""Daemon buy-symbol resolver regression (dcy-011/REQ-007, REL-004 smoke finding). Exercises the REAL Daemon._resolve_symbol against a REAL SnapshotStore — the gap that let `asset.symbol` (wrong; SnapshotStore.get returns a SnapshotAsset whose symbol is on `.item.symbol`) ship: unit tests injected a stub resolver, so the daemon wiring was never run until the REL-004 live smoke timed out every buy. """ from __future__ import annotations from pathlib import Path from trex_core.application.portfolio import PortfolioItem, SnapshotStore from trex_core.runtime.daemon import Daemon class _StoreHolder: """Minimal stand-in carrying just the attribute Daemon._resolve_symbol uses.""" def __init__(self, store): self.snapshot_store = store def _store(*items): s = SnapshotStore() s.swap(list(items)) return s def test_resolve_symbol_reads_item_symbol(): store = _store(PortfolioItem(portfolio_id="pf-005930", symbol="005930", cash_balance=0.0, asset_quantity=0.0)) holder = _StoreHolder(store) # call the real method with a stub self (no full daemon construction needed) assert Daemon._resolve_symbol(holder, "pf-005930") == "005930" def test_resolve_symbol_unknown_returns_none(): holder = _StoreHolder(_store()) assert Daemon._resolve_symbol(holder, "pf-missing") is None def test_daemon_wires_shared_alarm_emitter_into_intent_service(): src = ( Path(__file__).resolve().parents[2] / "trex_core" / "runtime" / "daemon.py" ).read_text(encoding="utf-8") assert "self.intent_service = IntentService(" in src assert "alarm_emitter=self.alarm_emitter" in src