docs(discovery): dcy-027 모든 OQ Answered — 중장기 슬롯 운영 결정 완료
OQ-1: (a′) 기존 슬롯 도메인 유지 + 운영 프로파일/규칙 추가 (PositionBook 불필요) OQ-2: safety_sell_enabled=false → 코어 손절매 루틴 없음, 전략 모듈 전적 책임 OQ-3: per-instance watchdog_timeout_sec 연장 (1800s 이상 권장), 알림은 후속 Discovery OQ-4: 중장기 전략 폴링 주기 최소 1분·최대 10분 feat(bat-041): REQ-076/077/078 — watchdog timeout TOML + 중장기 운영 프로파일 + baseline Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# BAT-041 Design
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-041
|
||||
|
||||
## Architecture Summary
|
||||
- watchdog timeout 설정을 단일 지점에서 per-instance 화한다: `DaemonInstanceConfig.watchdog_timeout_sec`(TOML, optional) → `DaemonConfig.from_config` 에서 값이 있으면 `SafetySellConfig.watchdog_timeout_sec` 를 `dataclasses.replace` 로 override. 소비자 2곳(slots RPC 핸들러의 expired 표시, SafetySellService 의 trigger gating)은 모두 `config.safety_sell.watchdog_timeout_sec` 를 읽으므로 자동으로 일치한다.
|
||||
- 중장기 프로파일은 신규 코드 없이 기존 설정 메커니즘 조합(`safety_sell_enabled=false` + `watchdog_timeout_sec=1800` + `max_active_slots` + market-close env 미설정)으로 표현되고, `config/longterm.example.toml` 로 표준화한다.
|
||||
- runtime-flows 에 중장기 병행 운영 흐름(보호 경계 포함)을 추가한다.
|
||||
|
||||
## Changed Areas
|
||||
- Modules:
|
||||
- `trex_core/runtime/config.py`:
|
||||
- `DaemonInstanceConfig.watchdog_timeout_sec: Optional[int] = None`
|
||||
- `from_toml`: `watchdog_timeout_sec` 파싱 + `<= 0` 거부(기존 `max_active_slots` 검증 패턴)
|
||||
- `from_config`: `inst.watchdog_timeout_sec is not None` → `safety_sell = dataclasses.replace(safety_sell, watchdog_timeout_sec=...)`
|
||||
- `config/longterm.example.toml` (신규)
|
||||
- Tests: `tests/runtime/test_config*.py` 패턴 — TOML 적용/env 폴백/독립/검증 거부
|
||||
- Docs: `docs/runtime-flows.md`(중장기 운영 흐름 + Change Log), `docs/project-structure.md`(불필요 예상 — 구조 불변, config 필드 1개)
|
||||
|
||||
## Key Decisions
|
||||
1. **override 지점 = `from_config` 단일 지점**: TOML 값이 frozen `SafetySellConfig` 를 `dataclasses.replace` 로 교체. daemon.py·safety_sell.py·messaging_handlers.py 는 무변경 — 소비자가 이미 `config.safety_sell.watchdog_timeout_sec` 를 읽음(R-1 제거).
|
||||
2. **TOML 우선, env 폴백**: `watchdog_timeout_sec` TOML 미설정 시 기존 env(`TREX_WATCHDOG_TIMEOUT`, 기본 120) 그대로 — 기존 인스턴스 byte-for-byte 무회귀(REQ-076 AC-2). REQ-060(env 폐기)과 달리 env 는 보존: 기존 운영 사용 중.
|
||||
3. **`<= 0` 명시 거부**: `max_active_slots`/`default_order_timeout_sec` 와 동일한 from_toml 검증 패턴.
|
||||
4. **프로파일 = 설정 조합(신규 코드 0)**: REQ-077 은 example TOML + 검증으로 충족. market-close 는 env 영역이므로 TOML 주석으로 "미설정 전제" 명시(코드 강제 없음 — 운영 절차).
|
||||
5. **S-1 검증 범위**: 멀티데이 보유 유지는 영구 슬롯 DB 영속(dcy-020)의 기존 보장 + 자율 청산 미발화는 `safety_sell_enabled=false` 워커 미기동(BAT-036 evidence). 본 batch 는 프로파일 조합이 의도대로 로딩·적용되는지(워커 미기동 + timeout 1800 + 독립 instance_key)를 설정·기동 구성 단위로 검증하고, 실 데몬 장기 run 은 release 운영 검증으로 위임.
|
||||
|
||||
## Edge Cases
|
||||
- TOML `watchdog_timeout_sec = 0` 또는 음수: from_toml 명시 거부(RuntimeError).
|
||||
- TOML 미설정 + env 미설정: 기본 120s(기존과 동일).
|
||||
- TOML 설정 + env 도 설정: TOML 승리(per-instance 가 전역보다 구체적).
|
||||
- 당일 인스턴스(TOML 미설정)와 중장기(1800) 병행: 인스턴스별 DaemonConfig 가 독립 생성되므로 분리 적용.
|
||||
|
||||
## Architecture Impact
|
||||
- runtime-flows (중장기 병행 운영 흐름 신설 — REQ-078 소관)
|
||||
|
||||
## Reference Doc Update Plan
|
||||
- project-structure.md: none 예상(구조 불변 — config 필드 1개 + 예시 파일. 예시 파일 위치 언급이 필요하면 한 줄)
|
||||
- runtime-flows.md: 중장기 인스턴스 운영 섹션 신설 — 병행 토폴로지(instance_key 분리), 프로파일 구성(REQ-077 레시피), 보호 규칙 경계(전략 전적 책임 + CLI exit 백스톱, 코어 손절매 루틴 미사용), forced_close_at 미사용(발화 불가 근거), watchdog 중장기 의미(1800s, last_seen 가시성 유지). Change Log 항목 추가.
|
||||
@@ -0,0 +1,31 @@
|
||||
# BAT-041 Implementation
|
||||
|
||||
- Status: completed
|
||||
- Batch: BAT-041
|
||||
|
||||
## Plan Summary
|
||||
- `DaemonInstanceConfig.watchdog_timeout_sec`(TOML, env 폴백) + `from_config` 단일 지점 override, `config/longterm.example.toml` 표준 프로파일, runtime-flows 중장기 운영 flow, 테스트 7종.
|
||||
|
||||
## Changed Files
|
||||
- `trex_core/runtime/config.py` — `DaemonInstanceConfig.watchdog_timeout_sec: Optional[int] = None` + `from_toml` 파싱(<=0 거부) + `from_config` 에서 `SafetySellConfig` `dataclasses.replace` override(TOML 우선, env 폴백)
|
||||
- `config/longterm.example.toml` (신규) — 중장기 표준 프로파일(instance_key=longterm, safety_sell_enabled=false, watchdog_timeout_sec=1800, max_active_slots=10) + 키별 중장기 의미 주석(forced_close_at 미사용, market-close env 미설정 포함)
|
||||
- `docs/runtime-flows.md` — `중장기(멀티데이) 인스턴스 병행 운영` flow 신설(6단계: 분리 기동/프로파일/보유 유지/보호 경계/forced_close_at 미사용/watchdog 의미) + Change Log
|
||||
- `tests/runtime/test_watchdog_timeout_toml.py` (신규, 7 테스트)
|
||||
|
||||
## Execution Log
|
||||
1. `config.py`: `DaemonInstanceConfig` 에 optional 필드 추가, `from_toml` 에 기존 `max_active_slots` 검증 패턴으로 파싱+거부, `from_config` 에서 `inst.watchdog_timeout_sec is not None` 시 `safety_sell` replace — 소비자 2곳(slots RPC 핸들러 daemon.py:284, SafetySellService `_cfg`)이 모두 `config.safety_sell` 을 읽으므로 단일 지점으로 일치(design Key Decision 1).
|
||||
2. `longterm.example.toml`: REQ-077 레시피 — 운영자 복제 사용 가능한 주석 포함.
|
||||
3. `runtime-flows.md`: multi-instance 라우팅 섹션 뒤에 중장기 운영 flow 신설.
|
||||
4. 테스트: TOML 적용(1800)/TOML>env 우선/env 폴백(300)/기본 120/인스턴스별 독립/<=0 거부/예시 프로파일 조합 로딩(longterm·false·1800·10).
|
||||
|
||||
## Validation
|
||||
- `pytest tests/runtime/test_watchdog_timeout_toml.py` — 7 passed (신규)
|
||||
- `pytest tests/` — **446 passed, 46 skipped** (BAT-040 439 → +7, 회귀 0 — NFR-1 당일 무회귀 게이트 green)
|
||||
- `ruff check trex_core tests` — All checks passed
|
||||
- instance 격리(NFR-2): 인스턴스별 독립 timeout 테스트 + 기존 instance topology 테스트 회귀 green.
|
||||
|
||||
## Remaining Risks
|
||||
- 없음. R-1(소비자 불일치)=단일 지점 override 로 제거, R-2(frozen)=`replace` 사용, R-3(장기 run 재현)=설정·기동 구성 단위 검증 + BAT-036 evidence 재참조, 실 데몬 장기 운영 검증은 release 단계 위임(verification 명시).
|
||||
|
||||
## Out-of-scope Finding (별도 후속)
|
||||
- **pre-existing bug 발견**: `DaemonInstanceConfig.from_toml` 은 `default_order_timeout_sec` 를 파싱하지만 `DaemonConfig.from_config` 의 `replace(...)` 에 전파 누락 — TOML 의 `default_order_timeout_sec` 가 런타임에서 조용히 무시됨(daemon.py:156 은 `config.default_order_timeout_sec` 를 읽으나 항상 env-base 값). REQ-068/REQ-048 영역 — 본 batch 범위 밖, change-req 후속 필요.
|
||||
@@ -0,0 +1,33 @@
|
||||
# BAT-041: 중장기 인스턴스 운영 — watchdog per-instance TOML + 프로파일 + baseline (dcy-027)
|
||||
|
||||
- Status: release-candidate
|
||||
- Profile: standard
|
||||
- Source Discovery: dcy-027 (issue #20 이월)
|
||||
- Included REQ: REQ-076, REQ-077, REQ-078
|
||||
- Excluded REQ: 없음
|
||||
|
||||
## Summary
|
||||
- 중장기 매매 전략용 인스턴스 운영 토대를 완성한다(dcy-027, 구현 위치 (a′) — 기존 슬롯 도메인 유지). watchdog timeout 을 per-instance TOML 로 노출하고(REQ-076, env 폴백), 중장기 표준 운영 프로파일 TOML 레시피를 제공·검증하며(REQ-077), 보호 규칙 경계(전략 모듈 전적 책임 + CLI exit 백스톱)와 forced_close_at 미사용을 baseline 문서에 명시한다(REQ-078).
|
||||
|
||||
## Scope
|
||||
- In Scope:
|
||||
- `trex_core/runtime/config.py` — `DaemonInstanceConfig.watchdog_timeout_sec`(optional) + `from_toml` 파싱 + `from_config` 에서 `SafetySellConfig.watchdog_timeout_sec` override(TOML 우선, env 폴백)
|
||||
- `config/longterm.example.toml` — 중장기 표준 프로파일 예시(키별 중장기 의미 주석)
|
||||
- `docs/runtime-flows.md`(·필요 시 `docs/project-structure.md`) — 중장기 병행 운영 흐름 + 보호 규칙 경계 + forced_close_at 미사용
|
||||
- 테스트: TOML 로딩/env 폴백/인스턴스 독립, 프로파일 조합 기동 구성, instance 격리 회귀
|
||||
- Out of Scope:
|
||||
- 멀티데이 보호 규칙 코어 구현 (dcy-027 OQ-2 — 전략 모듈 전적 책임, 코어 구현 없음)
|
||||
- watchdog 소유권 진입 외부 알림(슬랙·이메일) — 후속 Discovery
|
||||
- 중장기 전략 모듈 구현(별도 저장소)
|
||||
- PositionBook 도메인 (OQ-1 미채택)
|
||||
|
||||
## Documents
|
||||
- Planning: [planning.md](./planning.md)
|
||||
- Design: [design.md](./design.md)
|
||||
- Implementation: [implementation.md](./implementation.md)
|
||||
- Verification: [verification.md](./verification.md)
|
||||
|
||||
## Notes
|
||||
- 코드 변경은 경량(config 1개 필드 + override 전파)이나, 런타임 설정 채널 + 운영 프로파일 + baseline 문서 정렬을 함께 포함하므로 standard profile.
|
||||
- NFR-1(당일 무회귀)은 본 batch verification 의 전체 회귀 게이트, NFR-2(무간섭)는 REQ-077 AC-3, NFR-3(TOML 재사용)은 REQ-076 요구사항 제약으로 흡수(dcy-027).
|
||||
- S-1 의 "일자 경계·재시작 보유 유지"는 영구 슬롯 모델(dcy-020, DB 영속)의 기존 보장 — 본 batch 는 프로파일 조합으로 자율 청산 미발화를 검증한다(설정 단위 + 기존 BAT-036 evidence 재참조).
|
||||
@@ -0,0 +1,37 @@
|
||||
# BAT-041 Planning
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-041
|
||||
- Profile: standard
|
||||
|
||||
## Included REQ
|
||||
- REQ-076: watchdog timeout per-instance TOML(`watchdog_timeout_sec`, TOML 우선·env 폴백). AC 4.
|
||||
- REQ-077: 중장기 운영 프로파일 — `config/longterm.example.toml` 레시피 + 기동 구성·병행 무간섭 검증. AC 4.
|
||||
- REQ-078: baseline 정합 — 중장기 흐름 + 보호 규칙 경계 + forced_close_at 미사용. AC 3.
|
||||
|
||||
## Delivery Plan
|
||||
1. `config.py` — `DaemonInstanceConfig.watchdog_timeout_sec: Optional[int] = None` + `from_toml` 파싱(>0 검증) + `from_config` 에서 값 존재 시 `SafetySellConfig` override(`dataclasses.replace`).
|
||||
2. `config/longterm.example.toml` — instance_key/safety_sell_enabled=false/watchdog_timeout_sec=1800/max_active_slots + 키별 중장기 의미 주석(forced_close_at 미사용 포함).
|
||||
3. 테스트 — TOML 로딩(1800 적용)/미설정 env 폴백(120)/인스턴스별 독립/프로파일 조합 기동 구성(워커 미기동 + timeout 적용), instance 격리 회귀.
|
||||
4. `docs/runtime-flows.md` — 중장기 병행 운영 흐름 섹션(토폴로지/프로파일/보호 경계/forced_close_at 미사용) + Change Log.
|
||||
|
||||
## Dependencies
|
||||
- Internal:
|
||||
- `SafetySellConfig.watchdog_timeout_sec` 소비자 2곳 확인 완료 — slots RPC 핸들러(daemon.py:284), SafetySellService(`_cfg.watchdog_timeout_sec`). override 가 `config.safety_sell` 에 반영되면 두 경로 모두 자동 적용.
|
||||
- 기존 TOML 패턴(`max_active_slots`/`default_order_timeout_sec`/`safety_sell_enabled`) 준용.
|
||||
- BAT-036(safety_sell_enabled=false 워커 미기동) 기존 evidence — 프로파일 검증에서 재사용.
|
||||
- External: 없음 (paper broker 로 검증, 라이브 불요).
|
||||
|
||||
## Design Gate
|
||||
- Design Required Before Implementation: yes
|
||||
- Reason: TOML→SafetySellConfig override 주입 지점(frozen dataclass replace), env 폴백 우선순위 의미, 프로파일 검증 범위(설정 단위 vs 실 데몬)를 design 에서 확정.
|
||||
|
||||
## Milestones
|
||||
1. Design confirmed — override 경로·검증 범위 확정
|
||||
2. Implementation — config + example TOML + 테스트 + baseline 문서
|
||||
3. Verification — REQ-076/077/078 AC 매핑 + 전체 회귀(NFR-1) + ruff
|
||||
|
||||
## Risks
|
||||
- R-1 (Low): override 가 SafetySellService 에는 적용되고 slots RPC 핸들러에 미적용(또는 역) — 완화: 단일 지점(`config.safety_sell`) override 로 두 소비자 자동 일치, 테스트로 확인.
|
||||
- R-2 (Low): frozen dataclass 수정 시도 오류 — 완화: `dataclasses.replace` 사용.
|
||||
- R-3 (Low): 일자 경계·재시작 시나리오를 실시간 재현 불가 — 완화: 영구 슬롯 DB 영속(dcy-020 기존 보장) + 자율 청산 미발화는 설정 단위 검증 + BAT-036 evidence 재참조로 충족(S-1 의 run-the-app 전수 재현은 release 운영 검증으로 위임, verification 에 명시).
|
||||
@@ -0,0 +1,48 @@
|
||||
# BAT-041 Verification
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-041
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- REQ-076 AC-1 (TOML `watchdog_timeout_sec = 1800` → 1800s 동작):
|
||||
- Evidence: `test_toml_watchdog_timeout_applied`(1800 적용) + `test_toml_wins_over_env`(env 300 무시, TOML 1800 승리) PASSED.
|
||||
- REQ-076 AC-2 (미설정 → env 폴백, byte-for-byte 무회귀):
|
||||
- Evidence: `test_absent_falls_back_to_env`(env 300 적용) + `test_absent_and_no_env_keeps_default_120` PASSED. 전체 회귀 446 passed(기존 인스턴스 경로 무회귀).
|
||||
- REQ-076 AC-3 (인스턴스별 독립 timeout):
|
||||
- Evidence: `test_instances_get_independent_timeouts` — day 120 / lt 1800 동시 분리 PASSED.
|
||||
- REQ-076 AC-4 (저빈도 폴링 비오인 + last_seen 가시성):
|
||||
- Evidence: timeout 1800s 적용 경로가 slots RPC 핸들러·SafetySellService 양쪽의 단일 소스(`config.safety_sell.watchdog_timeout_sec`, daemon.py:284 wiring 코드 리뷰)로 일치 — 600s 폴링 < 1800s timeout 으로 `is_expired` 산식상 비오인(WatchdogStore.is_expired 는 경과>timeout 비교). `last_seen` 노출 경로(slot_to_dict) 불변(기존 slots 핸들러 16 테스트 회귀 green).
|
||||
|
||||
- REQ-077 AC-1 (프로파일 기동 구성 — 워커 미기동 + 1800 + 독립 큐):
|
||||
- Evidence: `test_longterm_example_profile_loads_with_expected_combination` — instance_key=longterm, `safety_sell_enabled=False`, watchdog 1800, max_active_slots=10 PASSED. 워커 미기동(`safety_sell_enabled=false` → `trex-safety-sell` 스레드 제외 + WARNING)은 BAT-036 verification evidence 유효(본 batch 코드 경로 불변). per-instance 큐명은 dcy-009/BAT-013 evidence 유효.
|
||||
- REQ-077 AC-2 (멀티데이 보유 유지 — 일자 경계·재시작):
|
||||
- Evidence: 영구 자산 슬롯의 DB 영속·날짜 키 부재(dcy-020/BAT-027~030 verification — holding 이 재시작·일자 경계 통과)는 기존 evidence 유효. 본 프로파일은 자율 청산 트리거 전부 OFF(safety_sell_enabled=false + market-close env 미설정) 조합 — 설정 단위 검증 PASSED. **실 데몬 장기 run(수일) 검증은 release 운영 단계로 위임**(planning R-3 명시) — 코드 경로는 기존 검증 조합의 재구성이므로 release-ready 차단 아님.
|
||||
- REQ-077 AC-3 (당일·중장기 병행 무간섭):
|
||||
- Evidence: `test_instances_get_independent_timeouts`(설정 독립) + 기존 instance topology/스코프 격리 테스트 회귀 green(446 passed — DB instance_key 스코프·per-instance 큐 기존 evidence 유효).
|
||||
- REQ-077 AC-4 (예시 파일 — 표준 레시피 + 의미 주석):
|
||||
- Evidence: `config/longterm.example.toml` — 키별 중장기 의미 주석(safety_sell off 이유, 1800s 근거, forced_close_at 미사용, market-close env 미설정) 포함, 예시 로딩 테스트로 유효성 보증.
|
||||
|
||||
- REQ-078 AC-1 (runtime-flows 중장기 흐름 — 토폴로지/프로파일/보호 경계 정합):
|
||||
- Evidence: `docs/runtime-flows.md` `중장기(멀티데이) 인스턴스 병행 운영` flow 신설(6단계) + Change Log — 현행 코드(BAT-036 워커 미기동, REQ-076 override 경로)와 정합 확인.
|
||||
- REQ-078 AC-2 (forced_close_at 미사용 명시):
|
||||
- Evidence: runtime-flows flow 5단계("의미 없다 — 집행 주체 OFF, 발화 불가") + longterm.example.toml 주석 명시.
|
||||
- REQ-078 AC-3 (운영자 판단 가능성 — 보호장치 부재·책임 주체 명확):
|
||||
- Evidence: flow 4단계 — "코어 손절매 루틴 일절 미사용 / 모든 보호 규칙 전략 모듈 전적 책임 / 유일한 백스톱 = 운영자 CLI exit" 모호함 없이 명시.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Test:
|
||||
- `pytest tests/runtime/test_watchdog_timeout_toml.py` — 7 passed (신규)
|
||||
- `pytest tests/` — **446 passed, 46 skipped** (BAT-040 439 → +7, 회귀 0 — dcy-027 NFR-1 당일 무회귀 게이트 green)
|
||||
- `ruff check trex_core tests` — All checks passed
|
||||
- Manual / Baseline 동기화 (Architecture Impact: runtime-flows):
|
||||
- `docs/runtime-flows.md` 중장기 운영 flow 신설 + Change Log ✓ 코드 정합.
|
||||
- `docs/project-structure.md`: 변경 불필요(design Reference Doc Update Plan — 구조 불변, config 필드 1개 + 예시 파일).
|
||||
- override 단일 지점(daemon.py:284 + SafetySellService) 코드 리뷰 확인.
|
||||
|
||||
## Result
|
||||
- Ready for Release: true
|
||||
- Blocking Issues: 없음
|
||||
- REQ-077 AC-2 의 실 데몬 장기 run(수일) 검증은 release 운영 단계 사항 — 구성 요소별 기존 evidence(영구 슬롯 영속 BAT-027~030, 워커 미기동 BAT-036) + 프로파일 조합 설정 검증으로 release-ready 충족. verification 한계로 명시.
|
||||
- out-of-scope finding(`default_order_timeout_sec` TOML 전파 누락, implementation.md 기록)은 본 batch REQ 와 무관한 pre-existing — 별도 change-req 후속.
|
||||
@@ -48,3 +48,4 @@
|
||||
| BAT-038 | standard | release-candidate | REQ-018 (CHG-20260612-01) | dcy-026 (issue #24) | [bat-038](./bat-038_20260612_sell-transaction-tax-fee/) |
|
||||
| BAT-039 | standard | release-candidate | REQ-011 (CHG-20260612-01) | 없음 (issue #4) | [bat-039](./bat-039_20260612_paper-seq-redis-persistence/) |
|
||||
| BAT-040 | standard | release-candidate | REQ-002 (CHG-20260612-01), REQ-006 (CHG-20260612-01), REQ-073 (CHG-20260612-02) | 없음 (issue #25) | [bat-040](./bat-040_20260612_slots-rpc-db-filter/) |
|
||||
| BAT-041 | standard | release-candidate | REQ-076, REQ-077, REQ-078 | dcy-027 (issue #20 이월) | [bat-041](./bat-041_20260612_long-term-instance-profile/) |
|
||||
|
||||
Reference in New Issue
Block a user