feat(intents): dcy-011 buy intent portfolio_id 필수 계약 + ledger skip 가시화 (BAT-015)
dcy-011 전 주기 delivery. issue #6(buy 식별자 정정) + issue #11(ledger silent skip) 흡수. 거버넌스: 기존 Implemented REQ는 change-req, 신규 기능만 신규 REQ(OQ-3). - REQ-007 (change-req): buy admission portfolio_id 필수화 + SnapshotStore symbol resolve + unknown_portfolio 거부 (hard cutover, OQ-1/OQ-2) - REQ-021 (change-req): buy 메시지 payload symbol 제거 - REQ-018 (change-req): _record_ledger skip 가시화 (WARN + ledger_skipped 카운터) - REQ-055 (신규): closed↔ledger_outbox anti-join 운영 점검 find_ledger_gap_slots 코드: intents.py(BuyIntent portfolio_id 필수 + resolve_symbol 주입 + _admit_buy reject 분기), messaging_handlers.py, runtime/daemon.py(_resolve_symbol 배선), execution.py(skip WARN 로그), adapters/persistence/ops_checks.py(신규 anti-join). 검증: 단위 282 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 314 passed, ruff clean. BAT-015(standard) release-candidate. srs/index Next ID → REQ-056. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ single producer for ledger work items (NFR-3, single record subject).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
from typing import Callable, Optional
|
||||
@@ -27,6 +28,8 @@ from trex_core.application.ledger_outbox import LedgerOutbox
|
||||
from trex_core.application.ledger_port import LedgerTrade
|
||||
from trex_core.domain.slot import SlotService, SlotState, SlotStateMismatchError
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
# REQ-021/023: event emission hook. Runtime wires a callable that publishes
|
||||
# slot transition events through MessagingTransport. Application layer stays
|
||||
# transport-agnostic (NFR-1). Slot type is duck-typed to keep the application
|
||||
@@ -155,12 +158,23 @@ class ExecutionService:
|
||||
if self._ledger_outbox is None:
|
||||
return
|
||||
if not slot.portfolio_id:
|
||||
# REQ-018 AC-4: slot transition still proceeded; record skip for ops.
|
||||
# dcy-011 / REQ-018 (issue #11): ledger skip must NOT be silent.
|
||||
# Slot transition still proceeded; surface for ops (FR-4).
|
||||
r.ledger_skipped += 1
|
||||
_log.warning(
|
||||
"ledger skip: slot=%s symbol=%s side=%s reason=missing_portfolio_id "
|
||||
"(trade NOT recorded to portfolio-hub)",
|
||||
slot.slot_id, slot.symbol, side,
|
||||
)
|
||||
return
|
||||
if fs.execution_id is None:
|
||||
# Broker contract regression — log via counter; slot already transitioned.
|
||||
# Broker contract regression — slot already transitioned; surface for ops.
|
||||
r.ledger_skipped += 1
|
||||
_log.warning(
|
||||
"ledger skip: slot=%s portfolio_id=%s side=%s reason=missing_execution_id "
|
||||
"(trade NOT recorded to portfolio-hub)",
|
||||
slot.slot_id, slot.portfolio_id, side,
|
||||
)
|
||||
return
|
||||
price = float(fs.avg_price) if fs.avg_price is not None else 0.0
|
||||
trade = LedgerTrade(
|
||||
|
||||
Reference in New Issue
Block a user