feat(alarm): trex-core 알람 emitter + trex.alerts exchange (dcy-033 BAT-049, Implemented)
AlarmEmitter(application, best-effort 비차단)+trex.alerts topic exchange 가산·격리+8 CRITICAL code 배선. 608 passed, opus QC PASS, 팀장 e2e(텔레그램 HTTP200) 통과. REQ-098~101 Implemented. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
This commit is contained in:
@@ -9,7 +9,9 @@ manual holds).
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from trex_core.application.alarm_emitter import AlarmEmitter
|
||||
from trex_core.application.broker_port import BrokerPort
|
||||
from trex_core.application.portfolio import SnapshotStore
|
||||
from trex_core.domain.slot.state import SlotState
|
||||
@@ -17,8 +19,14 @@ from trex_core.domain.slot.state import SlotState
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def reconcile_core_holdings(*, slot_repo, slot_service, broker: BrokerPort,
|
||||
instance_key: str) -> dict[str, str]:
|
||||
def reconcile_core_holdings(
|
||||
*,
|
||||
slot_repo,
|
||||
slot_service,
|
||||
broker: BrokerPort,
|
||||
instance_key: str,
|
||||
alarm_emitter: Optional[AlarmEmitter] = None,
|
||||
) -> dict[str, str]:
|
||||
"""dcy-020 / REQ-062 (BAT-029): surface core-slot holding ↔ broker divergence.
|
||||
|
||||
Broker balance is the reconcile ground truth. Decisions (no silent auto-fix,
|
||||
@@ -48,6 +56,13 @@ def reconcile_core_holdings(*, slot_repo, slot_service, broker: BrokerPort,
|
||||
"core holding but broker flat: slot=%s symbol=%s -> error",
|
||||
slot.slot_id, sym,
|
||||
)
|
||||
# dcy-033 / REQ-100: CRITICAL alarm — position mismatch.
|
||||
if alarm_emitter is not None:
|
||||
alarm_emitter.publish_alarm(
|
||||
"core_holding_broker_flat",
|
||||
f"슬롯 보유인데 브로커 잔고 0 (slot={slot.slot_id} symbol={sym})",
|
||||
fields={"slot_id": str(slot.slot_id), "symbol": sym},
|
||||
)
|
||||
except Exception: # noqa: BLE001 - never let reconcile crash the loop
|
||||
_log.exception("failed to error-quarantine slot %s", slot.slot_id)
|
||||
elif slot.qty is not None and int(slot.qty) != bq: # C — qty mismatch
|
||||
|
||||
Reference in New Issue
Block a user