# REL-003: core 자율 안전 매도 (watchdog + 가격 임계값 + forced_close / stop-loss·take-profit / 장 마감 청산 + update_thresholds RPC) - Status: confirmed - Profile: app-service - Included Batch: BAT-010, BAT-011 ## Scope - Included: - BAT-010 (REQ-034, REQ-035, REQ-036, REQ-041): safety-sell 기반 인프라 — per-slot 워치독 store(snapshot RPC 가 holding 슬롯 `last_seen_at` 갱신), 슬롯 `stop_loss_price`/`take_profit_price` 도메인 필드 + `004_add_price_thresholds.sql` additive 마이그레이션, `SlotService.sell()` 자율 매도 내부 경로(idempotent), safety-sell env 5종 파싱. - BAT-011 (REQ-037, REQ-038, REQ-039, REQ-040, REQ-042): safety-sell 트리거 레이어 — `trex-safety-sell` worker(7번째 스레드), forced_close_at 만기 자동 매도(REQ-037), stop-loss·take-profit KIS 현재가 polling(`TTTC8397R`/`VTTC8397R`, `stck_prpr`) + 트리거(REQ-038), 장 마감 강제 청산(`TREX_MARKET_CLOSE_LIQUIDATION_TIME`, REQ-039), `update_thresholds` intent RPC 액션(REQ-040), baseline 3문서 정합(REQ-042). - Excluded: - **REQ-030 AC-2/AC-3 (옵션 D)**: portfolio-hub#8 배포 대기로 status Approved 유지 — 본 release 범위 밖(REL-001 Excluded 와 동일 이월). - 가격 임계값 논리 유효성 검증(take_profit > stop_loss 등): dcy-007/REQ-035 범위 밖. - KIS 쿼터 초과 시 polling 간격 **동적 조정**: 본 release 는 상한 산정 + 경고 로그까지(REQ-038 AC-8). 동적 조정은 후속 후보. - 전략 모듈(orb-v1) 자체: 별도 Discovery/배포. ## Rollout Plan 1. 사전 점검: PostgreSQL / RabbitMQ 도달성 확인. `.env` 의 broker 설정(`TREX_BROKER`, kis 시 `TREX_KIS_*` + `TREX_KIS_ALLOW_LIVE`) 확인. safety-sell env(아래)는 모두 optional — 미설정 시 기본값. 2. DB 마이그레이션 적용: `004_add_price_thresholds.sql`(additive, `ADD COLUMN IF NOT EXISTS`). 데몬 boot `apply_migrations` 가 자동 적용하나 사전 적용 권장. 3. 배포 대상 commit SHA(a30efa8 이상) 설치 후 데몬 재기동 → **7 워커 스레드**(execution / ledger / intent-rpc / snapshot-rpc / pause-rpc / snapshot-scheduler / **trex-safety-sell**) 기동 확인. 4. safety-sell 튜닝 env(전부 optional): - `TREX_WATCHDOG_TIMEOUT`(기본 120s), `TREX_WATCHDOG_GRACE_PERIOD`(기본 60s) — 워치독 만료/부팅 grace. - `TREX_FORCED_CLOSE_CHECK_INTERVAL`(기본 60s), `TREX_STOP_LOSS_POLL_INTERVAL`(기본 30s) — worker 캐던스. - `TREX_MARKET_CLOSE_LIQUIDATION_TIME`(HH:MM KST, **기본 미설정 = 장 마감 청산 OFF**). 5. **운영 안전 주의(중요)**: `broker=kis` LIVE 에서 safety-sell worker 는 **실제 매도 주문**을 낸다. - forced_close / stop-loss·take-profit 는 **워치독 만료(전략 모듈이 snapshot RPC 폴링을 멈춘) 슬롯에만** 작동한다 → `TREX_WATCHDOG_TIMEOUT` 을 전략 모듈의 정상 snapshot 폴링 주기보다 충분히 크게 설정해 정상 운용 슬롯 오발동을 방지할 것. - 장 마감 청산은 설정 시 **워치독 무관 전체 holding** 을 매도하므로 의도적으로만 설정. - stop-loss·take-profit·forced_close 는 해당 슬롯에 임계값/만기가 설정된 경우에만 작동(매수 intent 또는 `update_thresholds` 로 주입). 미설정 슬롯에는 무영향. ## Rollback Plan - 코드 롤백: BAT-010+011 단일 커밋(a30efa8) revert → safety-sell worker 제거(데몬 6 스레드로 회귀). 타 batch 비의존. - 데이터: `004_add_price_thresholds.sql` 는 additive(컬럼 추가)라 데이터 파괴 없음. 롤백 시 컬럼 보존(드롭 불필요). - 즉시 무력화(코드 롤백 없이): safety-sell 은 임계값/만기/장 마감 env 가 **설정된 경우에만** 매도한다. 임계값을 주입하지 않고 `TREX_MARKET_CLOSE_LIQUIDATION_TIME` 을 비우면 worker 는 사실상 inert. 긴급 시 데몬 정지. - 트리거 조건 예: 정상 운용 슬롯 오발동(워치독 timeout 과소 설정), KIS 현재가 polling 쿼터 초과, 예기치 않은 청산. ## Verification Checklist - 배포 전: - 단위 `pytest -q --deselect ...::test_sandbox_token_and_submit` → 236 passed / 23 skipped. - 인프라 게이트(PG+RabbitMQ) `TREX_RABBITMQ_TEST_URL=... TREX_POSTGRESQL_TEST_DSN=... pytest -q` → 259 passed(마이그레이션 001~004 적용 + PG repo round-trip 포함; BAT-010 R-2 해소). - `ruff check trex_core tests` → All checks passed. - 실데몬 e2e(paper): RabbitMQ 매수(forced_close_at = 매수+60s) → 워치독 만료 → `holding→pending_sell(forced_close_at/trex-safety-sell)→closed` 관찰(PASS). - **실 KIS LIVE 시세 검증(읽기 전용)**: `get_current_price('005930')=Decimal('329000')`(rt_cd=0, tr `FHKST01010100`). 배포 전 진단에서 REQ-038 구 tr_id(`TTTC8397R`) 결함 발견 → change-req REQ-038 CHG-04/05 로 정정·재검증 완료(REL-003 re-confirm 근거). - 배포 후: - 데몬 기동 + **7 워커 스레드**(trex-safety-sell 포함) + 큐/exchange/DLQ 선언 확인. - 마이그레이션 004 적용 확인(`daily_slot` 에 `stop_loss_price`/`take_profit_price` 컬럼 존재). - `update_thresholds` intent RPC: holding 슬롯 임계값 갱신 + 워치독 리셋 + non-holding `ignored` 응답. - **차기 거래일 실 KIS 관찰**: stop-loss·take-profit·forced_close·장 마감 트리거 중 최소 1건 실 체결까지 확인(휴장/시장 상황 의존). ## Release Execution Evidence - Release Status Transition Target: released ### Deployment Facts - Executed At: - <배포 시작 시각> - Completed At: - <배포 완료 시각> - Environment: - <배포 대상 환경> - Operator: - <배포 수행자> - Revision or Artifact: - <커밋 SHA 또는 배포 artifact 식별자 (≥ a30efa8)> - Commands or Procedure: - <실행 명령 또는 배포 절차 요약> ### Profile-Specific Checks - app-service: - Health Endpoint: - - Startup Log Fields: - - Request Log Fields: - - Smoke or Manual Verification: - <마이그레이션 004 적용 + update_thresholds RPC + (차기 거래일) 실 KIS 트리거 관찰> ### Rollback Outcome - Rollback Required: - - Rollback Trigger: - <발생 시 원인, 없으면 none> - Rollback Action: - <수행한 조치, 없으면 none> ### Release Decision Evidence - Released Decision: - - Rationale: - - Recorded By: - <기록자> - Recorded At: - <기록 시각> ## Feedback Handoff - Observation Summary: - (배포 전, 2026-06-07) 실데몬 paper e2e — RabbitMQ 매수(forced_close_at +60s) → 워치독 자연 만료 → `trex-safety-sell` 가 `holding→pending_sell(forced_close_at)` 트리거 → 집행 루프 `pending_sell→closed`. 단위 236 + 인프라 게이트 259 passed, ruff clean. - (배포 전, 2026-06-07) 실 KIS LIVE 시세 검증에서 **REQ-038 tr_id 결함 포착** — 구 `TTTC8397R` 가 "없는 서비스 코드"(rt_cd=1)로 LIVE 손절/익절 silent 미발동. `FHKST01010100` 로 정정 후 `get_current_price=329000` 정상. mock/샌드박스로는 못 잡는 결함을 배포 전 LIVE 검증으로 포착(테스트 가치 입증). - Discovery Input: - <후속 discovery 후보> - REQ Input: - <후속 req 후보> - Change Request Input: - KIS 현재가 polling 쿼터 동적 조정(REQ-038 후속) — 워치독 만료 슬롯 급증 시 polling 간격 자동 확대. - 가격 임계값 논리 유효성 검증(take_profit > stop_loss 등) — 신규 후보.