fix(daemon): buy 심볼 resolver 결함 수정 + REL-004 draft (운영자 run 증거)

REL-004(미릴리즈 BAT-014~021 통합) draft-release 작성. confirm-release 전
운영자 프로그램 run-the-app 검증(실 데몬 + trex-core CLI e2e)을 수행했고,
369 passed 가 놓친 실 프로덕션 버그를 검출·수정했다.

- fix(REQ-007 CHG-20260608-03): Daemon._resolve_symbol 이 SnapshotAsset.symbol
  (없는 속성)을 접근 → 데몬 buy admission 매 요청 AttributeError → intent RPC
  타임아웃(실 데몬 매수 전면 불능). asset.item.symbol 로 수정. 단위 테스트가
  stub resolver 를 주입해 실 배선을 한 번도 실행하지 않아 미검출이었음
- test: tests/runtime/test_daemon_resolve_symbol.py — 실 Daemon._resolve_symbol
  × 실 SnapshotStore 회귀 가드(수정 전 실패하는 테스트)
- docs(release): rel-004 draft(app-service, BAT-014~021) + Pre-Release Run
  Evidence(데몬 기동 + universe/slots/enter/exit e2e + ledger completed +
  버그 검출·수정 + LIVE 미검증 한계) + releases/index REL-004 행

검증: 실 데몬 재기동 후 buy/sell e2e admitted→체결→closed + ledger completed,
단위 337 passed, ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 17:38:34 +09:00
co-authored by Claude Opus 4.8
parent 6d7bca1460
commit a570ac659e
5 changed files with 199 additions and 2 deletions
@@ -0,0 +1,37 @@
"""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 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