dcy-007(core 자율 안전 매도) 전체 delivery. BAT-010 기반 인프라가 미커밋 상태였고 BAT-011 트리거 레이어와 공유 파일에서 섞여 있어 한 커밋으로 묶음. BAT-010 (REQ-034/035/036/041, release-candidate): - WatchdogStore(application/watchdog.py) + snapshot RPC 워치독 갱신 - Slot stop_loss_price/take_profit_price 필드 + 004_add_price_thresholds.sql - SlotService.sell() 자율 매도 내부 경로 + idempotency - SafetySellConfig env 5종 파싱 BAT-011 (REQ-037/038/039/040/042, release-candidate): - SafetySellService(application/safety_sell.py): forced_close 만기 / stop-loss· take-profit KIS polling / 장 마감 강제 청산 + trex-safety-sell 7번째 스레드 - BrokerPort.get_current_price + KIS inquire-price(TTTC8397R/VTTC8397R, stck_prpr) + paper stub - SlotService.update_thresholds() + intent RPC update_thresholds 액션 (부분 갱신/null 해제, 워치독 last_seen_at 리셋) - baseline 3문서 정합(interface-contract/runtime-flows/project-structure) 거버넌스: REQ-034~042 Implemented 동기화, BAT-010/011 release-candidate, dcy-007 discovery 포함. 검증: 신규 38 테스트 green, 단위 236 passed/23 skipped, 인프라 게이트(PG+RabbitMQ) 259 passed(마이그레이션 001~004 round-trip 포함), ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.4 KiB
4.4 KiB
BAT-010 Design
- Status: confirmed
- Batch: BAT-010
Architecture Summary
BAT-010은 safety-sell 기능의 기반 레이어 세 가지를 추가한다.
- WatchdogStore (
application/watchdog.py신규):dict[str, datetime]in-memory store. snapshot RPC handler가 응답 슬롯의last_seen_at을 갱신하고 BAT-011 트리거 루프가 만료 판정에 사용한다. - 도메인 필드 확장 (
models.py,postgresql.py, SQL 마이그레이션):stop_loss_price,take_profit_priceOptional[Decimal]additive 추가. BAT-011 KIS polling이 트리거 기준으로 사용한다. - SlotService.sell() (
domain/slot/service.py): RabbitMQ 우회 내부 매도 경로. BAT-011의 모든 트리거 루프(forced_close, KIS polling, 장 마감)가 이 메서드를 호출한다.
Changed Areas
- Docs:
- 없음 (baseline 문서 갱신은 REQ-042 / BAT-011에서 처리)
- Modules:
trex_core/runtime/config.py—DaemonConfig에 safety-sell env vars 5종 파싱 추가trex_core/domain/slot/models.py—stop_loss_price: Optional[Decimal],take_profit_price: Optional[Decimal]추가trex_core/adapters/persistence/postgresql.py— 두 필드 read/write 포함trex_core/adapters/persistence/sql/— 마이그레이션 스크립트 신규 추가trex_core/application/intents.py—IntentIn에stop_loss_price,take_profit_priceOptional 필드 추가trex_core/application/messaging_handlers.py—make_snapshot_rpc_handler확장(last_seen_at갱신) + intent RPC payload 파싱 확장(price fields)trex_core/application/watchdog.py(신규) —WatchdogStoreclasstrex_core/domain/slot/service.py—SlotService.sell(slot_id, actor, reason)추가
- Interfaces:
SlotService.sell(slot_id: str, actor: str, reason: str) -> None(신규 내부 인터페이스)WatchdogStore.update(slot_id: str) -> None(신규)WatchdogStore.is_expired(slot_id: str, timeout_s: int) -> bool(신규 — BAT-011 트리거 루프 계약)WatchdogStore.in_grace_period(grace_s: int) -> bool(신규)
Key Decisions
- WatchdogStore를
watchdog.py신규 모듈로 분리:portfolio.py는 snapshot 조회·직렬화 책임이 있어 watchdog 관심사(타임스탬프 추적·만료 판정)를 추가하면 단일 책임 위반. 신규 모듈이 독립 테스트와 BAT-011 참조에 유리하다. - REQ-041 env vars 5종 전체를 BAT-010에서 파싱 완성:
TREX_FORCED_CLOSE_CHECK_INTERVAL·TREX_STOP_LOSS_POLL_INTERVAL·TREX_MARKET_CLOSE_LIQUIDATION_TIME은 BAT-010에서 사용하지 않지만, REQ-041을 두 batch에 분리하면 REQ 단위 거버넌스 trace가 깨진다. 파싱만 완성하고 BAT-011이 config 값을 참조한다. - WatchdogStore 동시성은 Python GIL에 의존:
dict[str, datetime]단일 dict의 Python 레벨 read/write는 GIL 보장 하에 원자적. 별도threading.Lock불필요. grace period 판정:datetime.utcnow() - self.started_at < timedelta(seconds=grace_s)단순 비교. - SlotService.sell()은 transit_slot() 재사용: 기존
transit_slot(slot_id, from_state=HOLDING, to_state=PENDING_SELL, ...)advisory lock + outbox 경로를 그대로 재사용. 신규 로직을 최소화해 BAT-004 검증 coverage를 그대로 이어받는다.
Edge Cases
- grace period 중
is_expired()호출:in_grace_period()True이면 store에 없는 슬롯 포함 전체 만료 판정 유예. - 데몬 재시작 시 watchdog store: in-memory 초기화 +
started_at재설정으로 grace period 자동 재시작. sell()호출 시 이미pending_sell상태:transit_slot호출 전 상태 조회 → silent return (중복 매도 intent 제출 없음).sell()호출 시idle·cancelled등 비정상 상태:SlotStateError(또는 동등 예외) raise, 슬롯 상태 불변.- 마이그레이션 기존 row:
ALTER TABLE slots ADD COLUMN IF NOT EXISTS stop_loss_price NUMERIC패턴으로 멱등성 보장. 기존 rowNULL유지.
Architecture Impact
- runtime-flows: snapshot RPC handler → watchdog
last_seen_at갱신 흐름 추가 (BAT-011 REQ-042에서 문서화) - project-structure:
watchdog.py신규 모듈 추가 (BAT-011 REQ-042에서 문서화)
Reference Doc Update Plan
- project-structure.md: BAT-011 REQ-042에서 처리 (
watchdog.py신규 모듈 반영) - runtime-flows.md: BAT-011 REQ-042에서 처리 (snapshot RPC → watchdog update + sell() 내부 경로 반영)