Files
trex-core/docs/discovery/dcy-024_20260611_safety-sell-disable-mode.md
T
genichinandClaude Opus 4.8 f0ad37747b feat(rel-007): dcy-025/024 + BAT-035/036 — slots.req 즉시 교체 + safety_sell_enabled
BAT-035 (dcy-025): trex.snapshot.req → trex.slots.req 즉시 교체
- topology: SNAPSHOT_REQ_QUEUE 제거, SLOTS_REQ_QUEUE = "trex.slots.req" 추가
- portfolio.py: View/build_snapshot_envelope/SnapshotEnvelope/_asset_to_dict 제거;
  slot_to_dict 시그니처 확장(snapshot_store/watchdog_store/pause_store/watchdog_timeout_sec)
  — asset_quantity(hub)/cash_balance/cash_estimated/warned/watchdog{}/paused 병합 (REQ-074)
- messaging_handlers.py: make_snapshot_rpc_handler 제거, make_slots_rpc_handler 추가
  — filter(all/inactive/pending/holding/error) + spy(bool) 처리; strategy 필드 제외 (REQ-073/074)
- daemon.py: _snapshot_rpc_loop → _slots_rpc_loop, make_slots_rpc_handler 연결
- cli.py: universe/slots → slots_queue + spy=True + server-side filter; buyable→inactive 매핑 (REQ-063)
- rabbitmq.py: snapshot_queue → slots_queue
- docs: interface-contract.md + runtime-flows.md slots.req 계약으로 업데이트 (REQ-075)
- REQ-028: Implemented → Deprecated (코드 삭제 완료)
- 테스트: test_snapshot_handler/selection/rpc_watchdog/messaging_snapshot_consumer 삭제;
  test_slots_handler.py(신규, 13 cases), test_killswitch_masking_resume 재작성,
  test_ledger_option_d._apply_cash_estimate → slots handler 경유, test_topology/cli_operator 갱신

BAT-036 (dcy-024): per-instance safety_sell_enabled 플래그
- config.py: DaemonInstanceConfig + DaemonConfig 에 safety_sell_enabled: bool = True 추가;
  from_toml 파싱, from_config 전파
- daemon.py: start() workers 조건부 — safety_sell_enabled=false 시 trex-safety-sell 미기동 + WARNING
- tests: test_instance_config.py 에 safety_sell_enabled 파싱 3개 케이스 추가

REQ: 073/074/075/021/034/063/048/005 Approved → Implemented

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 14:45:45 +09:00

15 KiB

0. 문서 상태

  • 상태: confirmed
  • 문서 ID: dcy-024_20260611_safety-sell-disable-mode
  • 이슈명: safety-sell 자율 청산 비활성화 모드 (issue #15)
  • 작성 시각(KST): 2026-06-11
  • 마지막 갱신 시각(KST): 2026-06-11 13:50 KST (change-req 진행: REQ-048 CHG-20260611-01(safety_sell_enabled TOML) + REQ-005 CHG-20260611-01(조건부 워커·기동 로그·runtime-flows), 둘 다 Implemented→Approved. 신규 REQ 없음(OQ-1).)
  • 대체됨: 없음
  • 후속 Discovery 참조: 없음
  • 생성된 REQ 참조: 없음 (change-req only, dcy-024 OQ-1). Delivery: REQ-048(CHG-20260611-01)·REQ-005(CHG-20260611-01) change-req → 차기 batch.

1. 계획 상태 요약

  • 연계 문서 현황:
    • 관련 점수 파일: 없음
    • 관련 TODO/메모: GitHub issue #15 (자율 청산 비활성화 모드 설계 전문 포함)
  • 해석:
    • REL-006 피드백 환류 Discovery 후보로 식별됨. 자율 청산(forced_close / SL·TP / market_close) 워커를 완전히 끄고 전략·운영자 지시 매도만 허용하는 운영 모드 요구.
    • REQ-048(per-instance TOML) + REQ-005(daemon bootstrap) change-req 2건으로 닫는다 — OQ-1·OQ-2 확정. SafetySellConfig(env) 변경 없음.

2. 요구사항 판정 결과

  • 판정: 신규
  • 근거
    • dcy-007(core-autonomous-safety-sell)은 자율 매도 기능을 구현한 Discovery로 REL-003에서 released됨. 비활성화 모드는 그 기능의 확장이 아닌 운영 정책 플래그 추가 — 독립 후속 주기.
    • 현재 SafetySellConfig에 enabled 플래그가 없고, daemon.start()의 workers 리스트에 trex-safety-sell 스레드가 조건 없이 포함됨. 코드 갭이 실존하는 신규 요구.

3. 문제점의 요약

  • 현재 상태
    • trex_core/runtime/daemon.py:335: ("trex-safety-sell", self._safety_sell_loop) 이 workers 리스트에 항상 포함되어 데몬 기동 시 매번 자율 청산 워커가 시작됨.
    • SafetySellConfig(config.py:113)에는 enabled 플래그가 없고, per-trigger 비활성화 수단도 없음. 관찰 전용 인스턴스·신규 전략 검증 환경에서 자율 청산을 막을 방법이 없음.
  • 기대 상태
    • DaemonInstanceConfig(per-instance TOML)에 safety_sell_enabled: bool = True 추가(OQ-2 — env 제외, max_active_slots/default_order_timeout_sec 선례)로, false 시 trex-safety-sell 스레드를 데몬 기동부에서 아예 시작하지 않음.
    • 기동 로그에 safety_sell=disabled 표시로 운영자가 안전망 없는 인스턴스임을 즉시 인지 가능(스냅샷 응답 미포함 — OQ-3).
  • 이해관계자
    • 운영자/시스템 관리자 (Justin Ko): 관찰 전용 인스턴스·신규 전략 검증 시 자율 청산 OFF 필요
    • 전략 모듈(trex-orb-v1): 전략 지시 매도는 항상 유지되어야 함
    • 리뷰어/승인자: 안전망 없음을 명시한 운영 가이드 확인
  • 제약사항
    • ExecutionService(집행 루프), 운영자 CLI, kill-switch는 이 플래그에 영향받지 않아야 함 — 자율 청산(safety-sell 워커)만 OFF.
    • Redis·RabbitMQ·PostgreSQL 의존성 변경 없음. config.py + daemon.py 한정 수정.

주요 사용자 시나리오

  • 관찰 전용 인스턴스: per-instance TOML safety_sell_enabled = false 설정 후 데몬 기동 → 기동 로그에 safety_sell=disabled 확인 → 포지션 유지 중 자동 청산 미발생, 전략 sell intent는 정상 집행.
  • 신규 전략 검증(paper 브로커): safety-sell 없이 전략 모듈 매도 타이밍만 테스트 — 의도치 않은 장마감 강제청산 없이 전략 e2e 검증.
  • 기본 운영(enabled=true): 기존 동작과 완전 동일. 하위 호환 변경 없음.

4. 이번에 정의할 변경

  • DaemonInstanceConfig(per-instance TOML)에 safety_sell_enabled: bool = True 필드 추가(OQ-2 — env 제외, SafetySellConfig 변경 없음).
  • daemon.start() workers 리스트 구성부에서 safety_sell_enabled=false 시 trex-safety-sell 스레드 제외 — run_once 내부 if-가드보다 스레드 미기동이 물리적으로 자율 청산을 차단.
  • 기동 로그(RUNNING)에 safety_sell_enabled 상태 노출(스냅샷 응답 미포함 — OQ-3) — 운영자가 인지 없이 안전망 없는 인스턴스를 운영하는 사고 방지.

영향 범위

  • 코드 영향:
    • trex_core/runtime/config.py: DaemonInstanceConfig에 safety_sell_enabled: bool = True 필드 추가 + from_toml() 파싱 (SafetySellConfig 변경 없음)
    • trex_core/runtime/daemon.py: start() workers 조건부 구성 — config.instance.safety_sell_enabled 참조 + 기동 로그 safety_sell=disabled/enabled
  • 문서 영향:
    • REQ-048(per-instance TOML 설정) change-req: safety_sell_enabled 필드 추가
    • REQ-005(daemon bootstrap) change-req: 워커 조건부 기동 명시
    • docs/runtime-flows.md: safety-sell 비활성 모드 플로우 추가
  • 운영 영향:
    • 기본값 true — 기존 운영 인스턴스 동작 무변. 기동 전 .env 또는 TOML에 TREX_SAFETY_SELL_ENABLED=false 추가 시에만 비활성 모드로 전환.
    • 비활성 모드 인스턴스는 손절/강제만기/장마감 안전망 없음 — 운영 가이드·기동 로그 명시 필수.

5. 요구사항 목록

기능 요구사항

  • FR-1: DaemonInstanceConfig(per-instance TOML)에 safety_sell_enabled: bool = True 필드를 추가하고, TOML safety_sell_enabled = false로 인스턴스별 비활성화를 제어한다. 기본값 true(미지정 시 기존 동작 유지). env var 경로 미노출 — 인스턴스별 운영 모드 차이(max_active_slots 선례).
  • FR-2: daemon.start() 시 DaemonInstanceConfig.safety_sell_enabled == False 이면 trex-safety-sell 워커 스레드를 workers 리스트(daemon.py:335)에 포함하지 않는다. True(기본)이면 기존과 동일하게 기동한다.
  • FR-3: 기동 시 RUNNING 로그에 safety_sell_enabled=<true|false> 필드를 포함한다. 비활성 모드(false)이면 추가로 no autonomous liquidation 경고를 로그에 남긴다.
  • FR-4: safety_sell_enabled 모드는 기동 로그(FR-3)로만 노출하고 스냅샷/slots 응답에는 포함하지 않는다(OQ-3). 근거: 인스턴스 config 이지 per-slot 데이터가 아니며, dcy-025 가 read 표면을 "응답=상태(slots[])+health"로 최소화하므로 config 를 응답에 싣지 않는 패턴과 정합한다. 런타임 노출이 필요해지면 per-slot 이 아니라 dcy-025 envelope-level(또는 별도 instance-status 표면)에서 조율한다.

비기능 요구사항

  • NFR-1: enabled=false 시 ExecutionService(집행 루프)·운영자 CLI(enter/exit/cancel)·kill-switch·messaging handler에는 영향 없음. 자율 청산(safety-sell 워커)만 미기동.
  • NFR-2: 기본값 true — 기존 운영 인스턴스 재배포 시 config 변경 없이 기존 동작 보존(완전 하위 호환).
  • NFR-3: 비활성 모드는 테스트에서 config.safety_sell.enabled=False를 주입하는 것만으로 재현 가능. 추가 mocking 불필요.

범위 경계

  • In Scope
    • SafetySellConfig enabled 필드 + env + TOML 파싱
    • daemon.start() workers 조건부 구성
    • 기동 로그에 모드 노출(스냅샷 응답 미포함 — OQ-3)
    • REQ-048(per-instance TOML) change-req + REQ-005(daemon bootstrap) change-req + runtime-flows 갱신
  • Out of Scope
    • per-trigger 개별 플래그(forced_close / SL·TP / market_close 각각 ON/OFF) — 마스터 플래그 이후 별도 후속 이슈로 분리
    • kill-switch 포함 여부 변경 — 운영자 지시 경로이므로 유지(혼용 금지)
    • 비활성 모드용 별도 watchdog 가시화 — 워커 미기동 시 로깅 없어도 무방(과설계 회피)
    • trex-orb-v1 전략 모듈 변경 — 전략 sell intent는 messaging handler 경로이며 영향 없음

6. 리스크/가정 목록

리스크

  • R-1 (Medium): 비활성 모드 인스턴스에서 전략 모듈이 죽어 폴링이 끊겨도 안전망 없이 포지션이 계속 유지됨 — 의도적 모드이지만 운영자 인지 없이 설정하면 무제한 손실 리스크.
    • 완화 방안: 기동 로그 no autonomous liquidation 경고로 운영자가 즉시 인지(스냅샷 응답 미포함 — OQ-3). 운영 가이드에 위험 명시.
  • R-2 (Low): TOML safety_sell_enabled 오타/잘못된 타입이 의도와 다르게 해석될 경우 기대와 반대로 자율 청산이 활성화됨.
    • 완화 방안: TOML bool 파싱 규약을 따르되(미지정/비-false → true), 기동 로그에 파싱된 값을 항상 출력해 운영자가 확인 가능하게 함.
  • R-3 (Low): 기존 SafetySellConfig 단위 테스트가 enabled 필드 추가 후 drift할 수 있음.
    • 완화 방안: EXPECTED_SLOT_FIELDS drift test 선례처럼 config 계약 가드 테스트 추가 또는 기존 테스트 보완.

가정

  • A-1: 단일 마스터 플래그(enabled) 구현으로 시작하고, per-trigger 세분화는 후속 이슈로 분리한다.
  • A-2: enabled=false 시 kill-switch, 운영자 CLI exit, 전략 sell intent는 그대로 동작한다.
  • A-3: 신규 REQ 없이 REQ-048(per-instance TOML) + REQ-005(daemon bootstrap) change-req 2건으로 닫는다 — OQ-1·OQ-2 Justin Ko 확정. SafetySellConfig(env) 변경 없음.

오픈 질문

  • OQ-1: 신규 REQ 없이 change-req 경로(REQ-041·005)만으로 진행할지, 별도 Configuration REQ를 신규 발행할지?
    • 상태: Answered
    • 처리 방안: Justin Ko 확정 — change-req 우선(신규 REQ 미발행). REQ-048(DaemonInstanceConfig TOML) + REQ-005(daemon bootstrap) change-req 2건으로 닫는다.
    • 종료 조건: 완료
  • OQ-2: per-instance TOML [safety_sell] enabled = false 지원 포함 여부(env만 지원할지 TOML도 포함할지)?
    • 상태: Answered
    • 처리 방안: Justin Ko 확정 — TOML 포함(env 제외). 당일 매매 인스턴스는 enabled=true, 중장기 보유 인스턴스는 enabled=false — 인스턴스마다 다른 운영 모드이므로 DaemonInstanceConfig(TOML)에 배치. max_active_slots·default_order_timeout_sec 선례 동일. REQ-048 change-req 추가.
    • 종료 조건: 완료
  • OQ-3: 스냅샷 응답(slots[] envelope)에 safety_sell_enabled 필드 추가 포함 여부(FR-4)?
    • 상태: Answered (2026-06-11, 사용자 결정)
    • 결정: 기동 로그만, 스냅샷/slots 응답 미포함. 근거: safety_sell_enabled는 인스턴스 config(per-slot 데이터 아님)이고, dcy-025 가 read 표면을 "응답=상태(slots[])+health"로 최소화하므로 config 를 응답에 싣지 않는 패턴과 정합. per-slot 행에 넣지 않는다. 런타임 노출이 필요해지면 per-slot 이 아니라 dcy-025 envelope-level(또는 별도 instance-status 표면)에서 조율(후속). 반영: FR-4.

7. 초기 성공 기준

  • S-1: per-instance TOML safety_sell_enabled = false로 데몬 기동 시 trex-safety-sell 스레드가 시작되지 않는다. 기동 로그에 safety_sell_enabled=false와 no autonomous liquidation 경고가 포함된다.
  • S-2: 비활성 모드에서 forced_close_at 만기·SL·TP·장마감 시각이 지나도 슬롯이 자동 청산되지 않는다. 전략 모듈 sell intent + 운영자 CLI exit는 정상 집행된다.
  • S-3: enabled=true(기본값) 시 기존 동작과 동일하며 기존 단위·통합 테스트 회귀가 없다.

측정 방식 및 데이터 출처

  • S-1 측정 방식: 단위 테스트 — enabled=False config 주입 + daemon.start() 후 thread 이름 목록에 trex-safety-sell 부재 확인 / 데이터 출처: tests/runtime/test_daemon.py 또는 신규 테스트
  • S-2 측정 방식: run-the-app 스모크 — 비활성 모드 데몬 기동 후 holding 슬롯 유지 중 장마감 시각 경과 → 슬롯 상태 holding 유지 + 전략 sell intent 처리 확인 / 데이터 출처: 데몬 기동 로그(safety_sell_enabled=false) + 슬롯 상태(trex-core slots로 holding 유지 확인 — slots 출력 자체엔 safety_sell_enabled 미포함, OQ-3)
  • S-3 측정 방식: pytest 전체 실행 회귀 없음, ruff check clean / 데이터 출처: CI 또는 로컬 테스트 결과

8. REQ로 넘기기 전 확인 체크

  • 범위(In Scope/Out of Scope) 확정
    • 기준: per-trigger 플래그 Out of Scope + TOML 지원(OQ-2 TOML·env 제외) 확정
  • 성공 지표의 측정 방식/데이터 출처 확정
    • 기준: S-1 단위(스레드 부재)·S-2 run-the-app 스모크·S-3 회귀로 정의됨
  • High 영향 리스크 우선순위 및 해소 책임자 지정
    • 기준: R-1(비활성 모드 손실)은 기동 로그 경고 + 운영 가이드로 해소, 가이드 작성 담당 = 구현 batch/Justin Ko(아래)
  • 모든 오픈 질문(OQ) Open 상태 없음 확인
    • 기준: OQ-1/2/3 전부 Answered
  • Freeze 확정 담당자(CONFIRMED_BY) 지정
    • 기준: Justin Ko 승인 후 confirm-discovery 수행
  • (delivery 인계) 비활성 모드 운영 가이드(손실 리스크 경고) 작성 — 구현 batch 단계 산출물, 담당 project maintainers/Justin Ko (Discovery confirm 비차단)

9. 파일 처리 결과

  • 처리 결과: 생성
  • 생성 경로: docs/discovery/dcy-024_20260611_safety-sell-disable-mode.md
  • 참조 문서:
    • GitHub issue #15 — 자율 청산 비활성화 모드 설계 전문 (영향 범위·구현 방안·OQ 상세)
    • docs/discovery/dcy-007_20260606_core-autonomous-safety-sell.md — 자율 매도 구현 Discovery (선행 참조)
    • trex_core/runtime/config.py:113 — SafetySellConfig (변경 대상)
    • trex_core/runtime/daemon.py:335 — workers 리스트 (trex-safety-sell 항목, 변경 대상)

10. 사용자 결정 필요 항목 요약

DECIDE

  • 없음 (OQ-1·OQ-2 확정 완료)

CONFIRM

  • 없음. (1) 스냅샷 응답 노출 = OQ-3 Answered(기동 로그만). (2) kill-switch·운영자 CLI exit가 safety_sell_enabled=false와 무관하게 유지됨은 설계로 확정(A-2/NFR-1) — 저장소상 KillSwitchService(daemon.py:166)·운영자 CLI exit 는 trex-safety-sell 워커와 독립 경로라 워커 미기동이 그 둘에 영향 없음(확인 완료).

DATA

  • 없음. (운영 가이드(손실 리스크 경고) 작성은 Discovery 정책 결정이 아니라 delivery 단계 산출물이므로 §8 인계 체크로 이동 — 담당은 구현 batch/project maintainers.)

11. Discovery Freeze

섹션 참조

Freeze 플래그

  • Handoff Decision: 승인
  • Handoff Rationale: OQ-1/2/3 전부 Answered(change-req 경로·TOML·기동 로그만). C형 플레이스홀더 0(CONFIRM/DATA 해소). 저장소 사실 재확인 일치. 운영 가이드 작성만 delivery 단계 비차단 인계. REQ Drafting 인계 가능.
  • Ready for REQ Drafting: true
  • Confirmed By: Justin Ko
  • Confirmed At (KST): 2026-06-11 13:29 KST