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>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# BAT-035 Design
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-035
|
||||
|
||||
## Architecture Summary
|
||||
- `trex.snapshot.req` RPC 파이프라인(큐 선언·핸들러·View enum·assets[]/available_slots/watchdog[] 구조)을 제거하고 `trex.slots.req` 단일 RPC로 즉시 교체한다.
|
||||
- 슬롯 행(slot_to_dict)이 자산·워치독·overlay를 흡수해 소비자 측 배열 조인을 없앤다.
|
||||
- 변경은 topology → messaging_handlers → portfolio → CLI 레이어 순으로 안쪽부터 바깥으로 진행한다.
|
||||
|
||||
## Changed Areas
|
||||
- Docs: docs/interface-contract.md (snapshot→slots 계약 교체 + 필드별 정본 출처 표), docs/runtime-flows.md (read 흐름 교체)
|
||||
- Modules:
|
||||
- `trex_core/adapters/messaging/topology.py` — SNAPSHOT_REQ_QUEUE → SLOTS_REQ_QUEUE, snapshot_queue() → slots_queue()
|
||||
- `trex_core/application/messaging_handlers.py` — make_slots_rpc_handler 신설, make_snapshot_rpc_handler 제거, _attach_watchdog 제거
|
||||
- `trex_core/application/portfolio.py` — slot_to_dict 확장, View enum 제거, build_snapshot_envelope 제거
|
||||
- CLI 모듈 — slots.req 사용, spy=true, filter 매핑
|
||||
- Tests:
|
||||
- tests/adapters/messaging/ — topology 단언
|
||||
- tests/application/ — slots 핸들러·slot_to_dict·divergence·overlay
|
||||
|
||||
## Key Decisions
|
||||
|
||||
1. **즉시 교체(lockstep)**: snapshot.req 큐·핸들러·legacy stub 경로를 같은 커밋에서 제거한다. 전략 모듈(trex-orb-v1)은 배포 전 lockstep 대응 완료 상태여야 한다(REQ-073, dcy-025 OQ-1).
|
||||
|
||||
2. **slot_to_dict 서명 확장**: `slot_to_dict(s, *, snapshot_store=None, watchdog_store=None, pause_store=None) → dict`. snapshot_store 없으면 asset_quantity=None, cash_balance=None, cash_estimated=False; watchdog_store 없으면 watchdog=None; pause_store 없으면 paused=False. None 필드는 응답에 그대로 포함(소비자가 구분 가능).
|
||||
|
||||
3. **warned 계산**: `warned = (slot.qty != asset_quantity)`. asset_quantity가 None(snapshot 미연결)이면 warned=False(불확정, 조용히 처리). slot.qty는 슬롯 미러 값.
|
||||
|
||||
4. **watchdog 행 흡수**: `watchdog: {expired: bool, last_seen: str|null}`. watchdog_store.get(slot_id) → WatchdogEntry(last_seen_at, timeout_sec). expired = (now - last_seen_at) > timeout_sec (또는 last_seen_at is None). WatchdogStore None 이면 watchdog 필드 전체 None.
|
||||
|
||||
5. **filter 분기**: `filter` → `{all: 전체, inactive: status==inactive, pending: status in (pending_buy, pending_sell), holding: status==holding, error: status==error}`. 미지정/null/"all" = 전체. 미지정 값은 all로 처리(조용히).
|
||||
|
||||
6. **spy 분기**: `spy=true` → holding 슬롯 워치독 미터치. `spy=false` or 미지정 → holding 슬롯 watchdog.update(). REQ-034 CHG-01 시맨틱.
|
||||
|
||||
7. **View enum 제거**: `portfolio.py:65`의 `class View(str, Enum)` 전체 제거. 호출 지점(build_snapshot_envelope, CLI) 정리.
|
||||
|
||||
8. **build_snapshot_envelope 제거**: `portfolio.py:340`의 `build_snapshot_envelope` 함수 전체 제거. messaging_handlers.py 의 snapshot 경로(221~244) 같이 제거.
|
||||
|
||||
9. **REQ-028 Deprecated 전환**: 이번 배치에서 snapshot.req 코드가 제거되면 REQ-028 상태를 Implemented→Deprecated로 전환한다.
|
||||
|
||||
## Edge Cases
|
||||
- asset_quantity(hub) = 0 이고 qty(slot) = 0 → warned=False (정상 일치)
|
||||
- asset_quantity(hub) = 0 이고 qty(slot) = 1 → warned=True (divergence)
|
||||
- snapshot_store 미연결(degraded) → asset_quantity=None, cash_balance=None, cash_estimated=False, degraded=true
|
||||
- spy=true 요청인데 holding 슬롯 없음 → watchdog 터치 없음, 정상 반환
|
||||
- invalid filter 값("buyable" 등) → all 처리 (하위호환, CLI 매핑은 상위 계층에서 처리)
|
||||
|
||||
## Architecture Impact
|
||||
- runtime-flows: yes (snapshot → slots 흐름 교체)
|
||||
- project-structure: no (파일 추가 없음, 기존 파일 수정)
|
||||
|
||||
## Reference Doc Update Plan
|
||||
- docs/interface-contract.md: snapshot 섹션 제거 → slots.req 계약 + 필드별 정본 출처 표 추가 (REQ-075 AC-1)
|
||||
- docs/runtime-flows.md: read 흐름 snapshot→slots 교체 (REQ-075 AC-2)
|
||||
@@ -0,0 +1,35 @@
|
||||
# BAT-035 Implementation
|
||||
|
||||
- Status: draft
|
||||
- Batch: BAT-035
|
||||
|
||||
## Plan Summary
|
||||
- topology.py: SLOTS_REQ_QUEUE 신설, SNAPSHOT_REQ_QUEUE 제거, snapshot_queue→slots_queue
|
||||
- messaging_handlers.py: make_slots_rpc_handler 신설, make_snapshot_rpc_handler + _attach_watchdog 제거
|
||||
- portfolio.py: View enum 제거, build_snapshot_envelope 제거, slot_to_dict 확장
|
||||
- CLI: slots.req 사용 + spy=true + filter 매핑
|
||||
- docs: interface-contract.md, runtime-flows.md 교체
|
||||
- tests: topology + slots 핸들러 + slot_to_dict
|
||||
|
||||
## Changed Files
|
||||
- `trex_core/adapters/messaging/topology.py`
|
||||
- `trex_core/application/messaging_handlers.py`
|
||||
- `trex_core/application/portfolio.py`
|
||||
- CLI 모듈 (slots.req 호출 경로)
|
||||
- `docs/interface-contract.md`
|
||||
- `docs/runtime-flows.md`
|
||||
- `tests/adapters/messaging/test_topology.py` (또는 해당 파일)
|
||||
- `tests/application/test_messaging_handlers.py` (또는 해당 파일)
|
||||
- `tests/application/test_portfolio.py` (또는 해당 파일)
|
||||
- `docs/srs/Interface/req-028_snapshot-read-message-contract-and-envelope.md` (Deprecated 전환)
|
||||
- `docs/srs/index.md` (REQ-028 Deprecated)
|
||||
|
||||
## Execution Log
|
||||
|
||||
(구현 진행 시 기록)
|
||||
|
||||
## Validation
|
||||
(구현 후 기록)
|
||||
|
||||
## Remaining Risks
|
||||
- trex-orb-v1 lockstep 대응 확인 전 배포 불가
|
||||
@@ -0,0 +1,25 @@
|
||||
# BAT-035: 전략 read 표면 재설계 — trex.slots.req + 슬롯 단일 행 스키마 (dcy-025)
|
||||
|
||||
- Status: confirmed
|
||||
- Profile: standard
|
||||
- Source Discovery: dcy-025
|
||||
- Included REQ: REQ-073, REQ-074, REQ-075, REQ-021 (CHG-20260611-01), REQ-034 (CHG-20260611-01), REQ-063 (CHG-20260611-01)
|
||||
- Excluded REQ: 없음
|
||||
|
||||
## Summary
|
||||
- `trex.snapshot.req` 파이프라인(view/assets[]/available_slots/watchdog[] 구조)을 `trex.slots.req` 단일 RPC로 즉시 교체(과도기 없음)한다. 슬롯 행 하나가 슬롯 상태·자산(hub 정본 + 슬롯 미러)·워치독·overlay 플래그를 모두 운반해 소비자 측 배열 조인을 없앤다. 필터는 status 단일 값, spy=true 시 워치독 무터치. strategy 계열 필드는 전면 제외.
|
||||
|
||||
## Scope
|
||||
- In: topology.py 큐명 교체(SNAPSHOT_REQ_QUEUE → SLOTS_REQ_QUEUE) + snapshot.req 선언 제거, messaging_handlers.py slots 핸들러 신설 + snapshot 핸들러 제거 + `_attach_watchdog` top-level 제거, portfolio.py `View` enum 폐기 + `slot_to_dict` 확장(asset_quantity/qty/warned/cash_balance/cash_estimated/watchdog nested/paused) + `build_snapshot_envelope` 제거, CLI slots.req 사용 + spy=true + --status→filter 매핑, docs(interface-contract.md / runtime-flows.md) snapshot→slots 계약 교체, 테스트(topology/slots 핸들러/filter/spy/응답 키 집합)
|
||||
- Out: strategy 계열 필드 slots 행 도입(후속 discovery), trex-orb-v1 소비 측 코드 수정(운영자 별도 lockstep 확인), 라이브 브로커 잔고 행 포함, overlay 서버측 필터링
|
||||
|
||||
## Documents
|
||||
- Planning: [planning.md](./planning.md)
|
||||
- Design: [design.md](./design.md)
|
||||
- Implementation: [implementation.md](./implementation.md)
|
||||
- Verification: [verification.md](./verification.md)
|
||||
|
||||
## Notes
|
||||
- 즉시 교체(과도기 없음): 배포 시점에 trex-orb-v1 의 `trex.slots.req` 대응 준비 완료 여부를 사전 확인해야 한다(dcy-025 R-1, REQ-073 Notes).
|
||||
- REQ-028(snapshot 계약 REQ): keep-current(Implemented) 유지, 이번 배치에서 코드 제거 완료 시 Deprecated 전환.
|
||||
- REQ-062(hub 정본 + 슬롯 미러 + 브로커 ground truth 정합)는 이번 배치 영향 없이 유지 — slot_to_dict 가 그 계약을 행에 표현한다.
|
||||
@@ -0,0 +1,61 @@
|
||||
# BAT-035 Planning
|
||||
|
||||
- Status: done
|
||||
- Batch: BAT-035
|
||||
- Profile: standard
|
||||
|
||||
## Included REQ
|
||||
- REQ-073: trex.slots.req RPC 계약 (Interface/High) — 큐 교체, filter/spy, 응답 slots+health only
|
||||
- REQ-074: 슬롯 단일 행 스키마 (Data/High) — asset_quantity+qty+warned, cash_balance+cash_estimated, watchdog nested, paused
|
||||
- REQ-075: baseline 문서 정합 (Documentation/Medium) — interface-contract/runtime-flows
|
||||
- REQ-021 CHG-20260611-01: 토폴로지 큐명 snapshot→slots 교체
|
||||
- REQ-034 CHG-20260611-01: watchdog 트리거=slots.req 기본/spy=무터치, 행 흡수
|
||||
- REQ-063 CHG-20260611-01: CLI slots.req+spy=true, --status→filter 매핑
|
||||
|
||||
## Delivery Plan
|
||||
|
||||
### M1: 토폴로지 + 인프라 계약 교체
|
||||
- `trex_core/adapters/messaging/topology.py`: SNAPSHOT_REQ_QUEUE → SLOTS_REQ_QUEUE (`"trex.slots.req"`), `snapshot_queue()` → `slots_queue()`
|
||||
- `docs/interface-contract.md`: trex.snapshot.req 섹션 제거, trex.slots.req 계약(요청 {filter, spy}, 응답 {slots[], degraded/reason/message}, 필드별 정본 출처 표) 추가
|
||||
- `docs/runtime-flows.md`: read 흐름 snapshot→slots 교체
|
||||
|
||||
### M2: messaging_handlers — slots 핸들러 신설 + snapshot 핸들러 제거
|
||||
- `make_snapshot_rpc_handler` 전체 제거
|
||||
- `make_slots_rpc_handler` 신설: filter(str) / spy(bool) 파싱, filter 분기 슬롯 조회, spy=false → holding watchdog 터치, 응답 {slots, degraded, reason, message} only
|
||||
- `_attach_watchdog` top-level 함수 제거 (watchdog 처리가 핸들러 내부로 흡수)
|
||||
|
||||
### M3: portfolio — slot_to_dict 확장 + View 폐기 + snapshot envelope 제거
|
||||
- `portfolio.py`: `View` enum 제거, `build_snapshot_envelope` 제거
|
||||
- `slot_to_dict(s, snapshot_store=None, watchdog_store=None, pause_store=None)` 확장:
|
||||
- 슬롯/코어 정본 필드(기존 유지)
|
||||
- `asset_quantity` (snapshot_store → hub 정본) + `qty` (슬롯 미러 s.qty) + `warned` (qty≠asset_quantity)
|
||||
- `cash_balance` + `cash_estimated` (snapshot_store)
|
||||
- `watchdog: {expired: bool, last_seen: str|null}` nested (watchdog_store)
|
||||
- `paused: bool` (pause_store)
|
||||
|
||||
### M4: CLI — slots.req 사용 + spy=true + filter 매핑
|
||||
- `trex_core/interfaces/cli.py` (또는 해당 모듈): 슬롯 조회 시 slots.req + spy=true, `--status` 인자→filter 매핑 (all/inactive/pending/holding/error, 기존 "buyable" → "inactive")
|
||||
|
||||
### M5: 테스트 + 회귀
|
||||
- tests/adapters/messaging/: topology 단언 (SLOTS_REQ_QUEUE 존재, SNAPSHOT_REQ_QUEUE 부재)
|
||||
- tests/application/: slots 핸들러 filter·spy·응답 키 집합, watchdog 터치/무터치, degraded 신호, portfolio slot_to_dict 확장 필드 + divergence + warned + cash_estimated + paused holding 직교, strategy 필드 부재
|
||||
- 전체 suite green
|
||||
|
||||
## Dependencies
|
||||
- Internal: REQ-062(hub 정본 + 슬롯 미러 정합 — 이번 배치가 그 계약을 표면에 구현), PauseStore, WatchdogStore 기존 API 재사용
|
||||
- External: trex-orb-v1 lockstep 대응(배포 전 확인)
|
||||
|
||||
## Design Gate
|
||||
- Design Required Before Implementation: **yes**
|
||||
- Reason: topology.py 큐 선언 변경(REQ-021), messaging_handlers.py 핸들러 신설/제거(REQ-073), portfolio.py slot_to_dict 서명 변경 + View 폐기(REQ-074)가 상호 연결된 인터페이스 변경. 제거 지점 전수와 새 핸들러 설계 계약을 design.md에 먼저 고정해 구현 drift를 방지.
|
||||
|
||||
## 위험 요소
|
||||
- R-1 (lockstep): trex-orb-v1 이 snapshot.req 를 아직 쓰고 있으면 배포 즉시 read 실패 → 배포 전 trex-orb-v1 의 slots.req 대응 완료 여부 확인 필수
|
||||
- R-2 (slot_to_dict 서명 변경): 호출 지점이 다수(messaging_handlers + CLI + 테스트) → grep 으로 호출 지점 전수 확인 후 한 번에 교체
|
||||
- R-3 (build_snapshot_envelope 제거): snapshot_store wiring path 삭제 시 CLI / daemon wiring 코드에서 잔존 참조 compile 오류 → M5 회귀로 검출
|
||||
|
||||
## 검증 계획 (요약)
|
||||
- topology: SLOTS_REQ_QUEUE 존재, SNAPSHOT_REQ_QUEUE 부재 assert
|
||||
- slots 핸들러: filter 분기(all/inactive/pending/holding/error), spy 터치/무터치, 응답 키 집합 {slots/degraded/reason/message} only, strategy 필드 부재
|
||||
- slot_to_dict: asset_quantity(hub) + qty(mirror) + warned(divergence) + cash_balance + cash_estimated + watchdog:{expired,last_seen} + paused 포함
|
||||
- 회귀: 전체 suite green
|
||||
@@ -0,0 +1,72 @@
|
||||
# BAT-035 Verification
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-035
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- REQ-073 AC-1: topology 선언 — `trex.slots.req` 큐 존재, `trex.snapshot.req` 큐·핸들러 부재
|
||||
- REQ-073 AC-2: filter 분기 — inactive/pending(buy∪sell)/holding/error/all/invalid 처리
|
||||
- REQ-073 AC-3: 응답 키 집합 — {slots/degraded/reason/message} only, assets/available_slots/watchdog(top) 키 부재
|
||||
- REQ-073 AC-4: spy=true → last_seen_at 미갱신; spy=false(default) → holding watchdog 갱신
|
||||
- REQ-073 AC-5: degraded=true + reason 전파, credentials sanitized
|
||||
- REQ-074 AC-1: 행 필드 — slot_id/status/avg_price/entry_price/forced_close_at/symbol/portfolio_id/cash_balance/asset_quantity/qty/watchdog:{expired,last_seen}/paused/warned 포함
|
||||
- REQ-074 AC-2: qty≠asset_quantity → warned=true, 두 값 모두 노출
|
||||
- REQ-074 AC-3: cash_estimated=true 구간 + 수렴 시 false
|
||||
- REQ-074 AC-4: paused holding → filter=holding 반환, paused=true (직교)
|
||||
- REQ-074 AC-5: strategy 계열 키 부재 (strategy_id/sell_strategy_id/strategy_params/active_strategy_id)
|
||||
- REQ-075 AC-1: interface-contract.md 에 slots.req 계약 + 필드 소스 테이블 추가, snapshot.req 현행 계약 섹션 제거
|
||||
- REQ-075 AC-2: runtime-flows.md read 흐름 slots.req 기준으로 업데이트
|
||||
- REQ-075 AC-3: `trex.snapshot.req` 현행 계약 서술 제거됨 (change log 이력 제외)
|
||||
- REQ-021 CHG-01 AC: 토폴로지에 slots.req 선언, snapshot.req 없음 (SNAPSHOT_REQ_QUEUE 상수 제거)
|
||||
- REQ-034 CHG-01 AC: spy=true → watchdog 미갱신; spy=false → holding watchdog 갱신
|
||||
- REQ-063 CHG-01 AC: CLI spy=true 전송, --status 인자 server-side filter 매핑 (buyable→inactive)
|
||||
|
||||
## Evidence
|
||||
|
||||
### Tests (420 passed, 45 skipped — 2026-06-11)
|
||||
|
||||
- **REQ-073 AC-1**: `tests/adapters/messaging/test_topology.py::test_topology_constants`
|
||||
- `topology.SLOTS_REQ_QUEUE == "trex.slots.req"` ✓
|
||||
- `not hasattr(topology, "SNAPSHOT_REQ_QUEUE")` ✓
|
||||
- **REQ-073 AC-2**: `tests/application/test_slots_handler.py`
|
||||
- `test_filter_all_returns_all_slots` ✓
|
||||
- `test_filter_inactive_returns_inactive_slots` ✓
|
||||
- `test_filter_holding_returns_holding_slots` ✓
|
||||
- `test_filter_pending_returns_pending_buy_and_sell` ✓
|
||||
- `test_invalid_filter_treated_as_all` ✓
|
||||
- **REQ-073 AC-3**: `test_response_keys_only_slots_health` ✓
|
||||
- **REQ-073 AC-4**: `test_spy_true_no_watchdog_update`, `test_spy_false_updates_watchdog` ✓
|
||||
- **REQ-073 AC-5**: `test_degraded_signal_propagated` ✓
|
||||
- **REQ-074 AC-1**: `test_slot_row_contains_merged_fields` ✓
|
||||
- **REQ-074 AC-2**: `test_warned_true_when_qty_diverges` ✓
|
||||
- **REQ-074 AC-3**: `tests/application/test_ledger_option_d.py::test_apply_cash_estimate_overlays_pending_delta` ✓
|
||||
- **REQ-074 AC-4**: `test_paused_holding_orthogonal_to_filter` ✓
|
||||
- **REQ-074 AC-5**: `test_strategy_fields_absent` ✓
|
||||
- **REQ-021 CHG-01**: `test_topology_constants` + `tests/adapters/messaging/test_instance_topology.py::test_named_instance_suffix` ✓
|
||||
- **REQ-034 CHG-01**: spy 워치독 억제 tests (위) ✓
|
||||
- **REQ-063 CHG-01**: `tests/runtime/test_cli_operator.py`
|
||||
- `test_universe_uses_slots_queue_with_spy` ✓
|
||||
- `test_slots_status_sends_server_side_filter` ✓
|
||||
- `test_slots_buyable_maps_to_inactive_filter` ✓
|
||||
|
||||
### Manual
|
||||
|
||||
- `tests/application/test_killswitch_masking_resume.py`: View/build_snapshot_envelope 의존 제거 후 재작성 완료
|
||||
- `tests/application/test_ledger_option_d.py`: _apply_cash_estimate 직접 테스트 → slots handler 경유 재작성 완료
|
||||
|
||||
### Code Review
|
||||
|
||||
- `trex_core/adapters/messaging/topology.py`: SNAPSHOT_REQ_QUEUE 제거, SLOTS_REQ_QUEUE 추가 ✓
|
||||
- `trex_core/application/portfolio.py`: View, build_snapshot_envelope, _asset_to_dict, SnapshotEnvelope 제거 ✓
|
||||
- `trex_core/application/messaging_handlers.py`: make_snapshot_rpc_handler 제거, make_slots_rpc_handler 추가 ✓
|
||||
- `trex_core/runtime/daemon.py`: _snapshot_rpc_loop → _slots_rpc_loop, make_slots_rpc_handler 연결 ✓
|
||||
- `trex_core/runtime/cli.py`: slots_queue + spy=True + server-side filter ✓
|
||||
- `docs/interface-contract.md`: slots.req 계약 추가, snapshot.req envelope 섹션 제거 ✓
|
||||
- `docs/runtime-flows.md`: 슬롯 RPC flow 추가, snapshot RPC flow 교체 ✓
|
||||
- `docs/srs/index.md`: REQ-028 → Deprecated ✓
|
||||
|
||||
## Result
|
||||
|
||||
- Ready for Release: true
|
||||
- Blocking Issues: 없음
|
||||
@@ -0,0 +1,42 @@
|
||||
# BAT-036 Design
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-036
|
||||
|
||||
## Architecture Summary
|
||||
- `DaemonInstanceConfig`에 `safety_sell_enabled: bool = True` 필드를 추가하고 per-instance TOML 파싱 경로(`from_toml`)와 `DaemonConfig.from_config()` 전파 경로를 업데이트한다.
|
||||
- `Daemon.start()` 내부 workers 리스트 구성 시 `safety_sell_enabled` 값을 체크해 False이면 `("trex-safety-sell", self._safety_sell_loop)` 항목을 포함하지 않는다.
|
||||
|
||||
## Changed Areas
|
||||
- Docs: 없음 (docs 변경 없음)
|
||||
- Modules:
|
||||
- `trex_core/runtime/config.py` — DaemonInstanceConfig 필드 + from_toml + from_config 전파
|
||||
- `trex_core/runtime/daemon.py` — start() workers 분기
|
||||
- Tests:
|
||||
- config 파싱 단위 테스트
|
||||
- daemon workers 구성 테스트
|
||||
|
||||
## Key Decisions
|
||||
|
||||
1. **absent=true 기본값**: `from_toml()` 내 `data.get("safety_sell_enabled", True)`. TOML 키 부재 시 True → 기존 배포 동작 보존.
|
||||
|
||||
2. **DaemonConfig 전파 경로**: `DaemonConfig.from_config()` → `DaemonInstanceConfig.from_toml()` → `DaemonInstanceConfig.safety_sell_enabled` → `DaemonConfig` 생성자 또는 속성으로 전달. `Daemon.__init__` 에서 `self._config.safety_sell_enabled` 로 참조.
|
||||
|
||||
3. **workers 조건 분기 위치**: `daemon.py:328` workers 리스트 구성 블록 내, `("trex-safety-sell", self._safety_sell_loop)` 항목을 조건부로 append. 리스트 구성 후 순회 루프(`for name, target in workers:`)는 변경 없음.
|
||||
|
||||
4. **로그 메시지**: `logger.warning("safety_sell disabled — trex-safety-sell worker not started. Autonomous safety-sell will NOT run.")`. RUNNING 로그(기존)로 전체 워커 시작 상태를 가시화.
|
||||
|
||||
5. **AC-6 보존**: `_safety_sell_loop` 제거가 아닌 workers 리스트 미포함. `Daemon._safety_sell_loop` 메서드 자체는 삭제하지 않는다(CLI exit/cancel/kill-switch 독립 경로는 이 메서드를 직접 호출하지 않으므로 무관).
|
||||
|
||||
## Edge Cases
|
||||
- safety_sell_enabled=True (기본): workers에 포함, 기존 동작과 동일
|
||||
- safety_sell_enabled=False: workers에 미포함, 경고 로그, 나머지 워커 영향 없음
|
||||
- TOML 키 오타(예: "safety_sell_enable"): get() 기본값 True 처리 → 활성화(안전한 방향)
|
||||
|
||||
## Architecture Impact
|
||||
- runtime-flows: no (daemon 기동 흐름만 경미하게 변경, 문서 갱신 불필요)
|
||||
- project-structure: no
|
||||
|
||||
## Reference Doc Update Plan
|
||||
- docs/interface-contract.md: 없음
|
||||
- docs/runtime-flows.md: 없음
|
||||
@@ -0,0 +1,23 @@
|
||||
# BAT-036 Implementation
|
||||
|
||||
- Status: draft
|
||||
- Batch: BAT-036
|
||||
|
||||
## Plan Summary
|
||||
- config.py: DaemonInstanceConfig.safety_sell_enabled 필드 + from_toml 파싱 + from_config 전파
|
||||
- daemon.py: start() workers 조건 분기
|
||||
|
||||
## Changed Files
|
||||
- `trex_core/runtime/config.py`
|
||||
- `trex_core/runtime/daemon.py`
|
||||
- `tests/` (config 파싱 + daemon workers 테스트)
|
||||
|
||||
## Execution Log
|
||||
|
||||
(구현 진행 시 기록)
|
||||
|
||||
## Validation
|
||||
(구현 후 기록)
|
||||
|
||||
## Remaining Risks
|
||||
- 없음
|
||||
@@ -0,0 +1,25 @@
|
||||
# BAT-036: safety_sell_enabled TOML 설정 + 조건부 데몬 워커 기동 (dcy-024)
|
||||
|
||||
- Status: confirmed
|
||||
- Profile: standard
|
||||
- Source Discovery: dcy-024
|
||||
- Included REQ: REQ-048 (CHG-20260611-01), REQ-005 (CHG-20260611-01)
|
||||
- Excluded REQ: 없음
|
||||
|
||||
## Summary
|
||||
- per-instance TOML 에 `safety_sell_enabled: bool = true` 필드를 추가하고, `false` 시 daemon.start() 가 `trex-safety-sell` 워커를 workers 리스트에서 제외해 스레드를 기동하지 않는다. 기동 로그로 상태를 가시화하며, 나머지 실행 경로(ExecutionService/CLI exit/cancel/kill-switch/strategy sell intent)는 이 값과 무관하게 동작한다.
|
||||
|
||||
## Scope
|
||||
- In: `trex_core/runtime/config.py` — DaemonInstanceConfig에 `safety_sell_enabled: bool = True` 필드 추가 + from_toml/from_config 파싱 + DaemonConfig로 전파, `trex_core/runtime/daemon.py` — start() workers 리스트 조건 분기 (safety_sell_enabled=False → trex-safety-sell 제외 + RUNNING 로그 + 경고 로그), 관련 테스트
|
||||
- Out: env 변수 TREX_SAFETY_SELL_ENABLED, CLI 노출, slots/snapshot 응답 노출, 다른 워커 제어
|
||||
|
||||
## Documents
|
||||
- Planning: [planning.md](./planning.md)
|
||||
- Design: [design.md](./design.md)
|
||||
- Implementation: [implementation.md](./implementation.md)
|
||||
- Verification: [verification.md](./verification.md)
|
||||
|
||||
## Notes
|
||||
- absent=true 기본값: TOML에 키 없으면 True(기존 동작 보존).
|
||||
- 선례: max_active_slots, default_order_timeout_sec 와 동일한 per-instance TOML 경로.
|
||||
- REQ-005 AC-6: ExecutionService/CLI exit/cancel/kill-switch/strategy sell intent 는 safety_sell_enabled 값과 무관하게 동작 — 이번 배치 구현에서 그 경로를 건드리지 않는 것이 검증 기준.
|
||||
@@ -0,0 +1,49 @@
|
||||
# BAT-036 Planning
|
||||
|
||||
- Status: done
|
||||
- Batch: BAT-036
|
||||
- Profile: standard
|
||||
|
||||
## Included REQ
|
||||
- REQ-048 CHG-20260611-01: DaemonInstanceConfig.safety_sell_enabled: bool=True, from_toml/from_config 파싱, DaemonConfig 전파 (AC-10)
|
||||
- REQ-005 CHG-20260611-01: daemon.start() 조건부 workers — safety_sell_enabled=False 시 trex-safety-sell 제외 + RUNNING 로그 + 경고 로그 (AC-5/6)
|
||||
|
||||
## Delivery Plan
|
||||
|
||||
### M1: config.py — DaemonInstanceConfig 필드 추가
|
||||
- `trex_core/runtime/config.py:DaemonInstanceConfig` 에 `safety_sell_enabled: bool = True` dataclass 필드 추가
|
||||
- `from_toml()`: `data.get("safety_sell_enabled", True)` 파싱
|
||||
- `DaemonConfig.from_config()`: DaemonConfig 생성 시 inst.safety_sell_enabled 전파
|
||||
|
||||
### M2: daemon.py — start() 조건부 workers
|
||||
- `trex_core/runtime/daemon.py:328~337` workers 리스트 구성 부분에서 조건 분기:
|
||||
```python
|
||||
if self._config.safety_sell_enabled:
|
||||
workers.append(("trex-safety-sell", self._safety_sell_loop))
|
||||
else:
|
||||
logger.warning("safety_sell disabled — trex-safety-sell worker not started")
|
||||
```
|
||||
- RUNNING 로그(기존 구조 안에서)로 비활성 상태 가시화
|
||||
|
||||
### M3: 테스트
|
||||
- config 파싱: TOML `safety_sell_enabled=false` → False; 키 부재 → True
|
||||
- daemon start: safety_sell_enabled=False → trex-safety-sell 스레드 미기동 단언
|
||||
- AC-6: ExecutionService/exit/cancel/kill-switch 경로는 이번 M1~M2 변경으로 건드리지 않음(회귀 테스트로 확인)
|
||||
|
||||
## Dependencies
|
||||
- Internal: DaemonConfig 내 DaemonInstanceConfig 전파 경로(from_config → DaemonInstanceConfig.from_toml)
|
||||
- External: 없음
|
||||
|
||||
## Design Gate
|
||||
- Design Required Before Implementation: **yes**
|
||||
- Reason: DaemonConfig ↔ DaemonInstanceConfig 전파 경로와 daemon.start() workers 리스트 수정 지점을 design.md 에 먼저 확정해 구현 오류를 방지.
|
||||
|
||||
## 위험 요소
|
||||
- R-1 (absent=true 누락): from_toml 에서 get 기본값을 False 로 잘못 설정하면 기존 인스턴스 동작 파괴 → 단위 테스트로 absent→True 확인
|
||||
- R-2 (DaemonConfig 전파): DaemonConfig 에 safety_sell_enabled 를 전달하지 않으면 daemon.start() 에서 참조 실패 → M1 에서 전파 경로를 먼저 확인
|
||||
|
||||
## 검증 계획 (요약)
|
||||
- TOML 파싱: present=false→False, present=true→True, absent→True
|
||||
- daemon.start() workers: False → trex-safety-sell 제외, True → 포함
|
||||
- 다른 워커(trex-execution 등) 영향 없음
|
||||
- 전체 suite green
|
||||
@@ -0,0 +1,44 @@
|
||||
# BAT-036 Verification
|
||||
|
||||
- Status: confirmed
|
||||
- Batch: BAT-036
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- REQ-048 CHG-20260611-01 AC-10: Given per-instance TOML safety_sell_enabled(absent=true), When from_toml/from_config, Then 값이 파싱되어 DaemonConfig로 전파된다
|
||||
- present=false → DaemonInstanceConfig.safety_sell_enabled=False → DaemonConfig.safety_sell_enabled=False
|
||||
- present=true → True
|
||||
- absent → True (기본값)
|
||||
- REQ-005 CHG-20260611-01 AC-5: Given safety_sell_enabled=False, When daemon.start(), Then trex-safety-sell 스레드 미기동 + WARNING 로그
|
||||
- REQ-005 CHG-20260611-01 AC-6: ExecutionService/CLI exit/cancel/kill-switch/strategy sell intent — safety_sell_enabled 값과 무관 동작 (회귀: 해당 경로 테스트 green)
|
||||
|
||||
## Evidence
|
||||
|
||||
### Tests (420 passed, 45 skipped — 2026-06-11)
|
||||
|
||||
- **REQ-048 CHG-20260611-01 AC-10**: `tests/runtime/test_instance_config.py`
|
||||
- `test_safety_sell_enabled_default_true` ✓
|
||||
- `test_safety_sell_enabled_false_from_toml` ✓
|
||||
- `test_safety_sell_enabled_true_explicit_from_toml` ✓
|
||||
- **REQ-005 CHG-20260611-01 AC-6** (회귀): 전체 테스트 스위트 420 passed — execution/exit/cancel/kill-switch 경로 모두 green ✓
|
||||
|
||||
### Code Review
|
||||
|
||||
- `trex_core/runtime/config.py`:
|
||||
- `DaemonInstanceConfig.safety_sell_enabled: bool = True` ✓
|
||||
- `from_toml()`: `safety_sell_enabled=bool(data.get("safety_sell_enabled", True))` ✓
|
||||
- `DaemonConfig.safety_sell_enabled: bool = True` ✓
|
||||
- `from_config()` replace: `safety_sell_enabled=inst.safety_sell_enabled` ✓
|
||||
- `trex_core/runtime/daemon.py`:
|
||||
- `start()` workers 조건부: `if self.config.safety_sell_enabled: workers.append(...)` ✓
|
||||
- `else: _log.warning("safety_sell_enabled=false — trex-safety-sell worker not started...")` ✓
|
||||
|
||||
### Manual
|
||||
|
||||
- `daemon.start()` 스레드 조건부 기동: 단위 테스트에서 실제 스레드 기동 없이 코드 경로 검증 (config 파싱 tests + code review)
|
||||
- safety_sell 비기동 시 execution/exit/cancel/kill-switch 경로 무관함을 회귀 테스트로 확인
|
||||
|
||||
## Result
|
||||
|
||||
- Ready for Release: true
|
||||
- Blocking Issues: 없음
|
||||
@@ -42,3 +42,5 @@
|
||||
| BAT-032 | standard | release-candidate | REQ-068, REQ-069, REQ-070, REQ-071, REQ-072, REQ-061(CHG-05), REQ-013(CHG-03) | dcy-022 | [bat-032](./bat-032_20260610_execution-policy/) |
|
||||
| BAT-033 | batch-lite | release-candidate | REQ-032 (CHG-20260610-06) | REQ-032 change-req (issue #23) | [bat-033](./bat-033_20260610_enter-qty-validation/) |
|
||||
| BAT-034 | standard | release-candidate | REQ-002 (CHG-20260610-02), REQ-006 (CHG-20260610-02), REQ-007 (CHG-20260610-02), REQ-028 (CHG-20260610-01), REQ-032 (CHG-20260610-07) | dcy-023 (issue #22) | [bat-034](./bat-034_20260610_drop-allocated-capital/) |
|
||||
| BAT-035 | standard | confirmed | REQ-073, REQ-074, REQ-075, REQ-021 (CHG-20260611-01), REQ-034 (CHG-20260611-01), REQ-063 (CHG-20260611-01) | dcy-025 | [bat-035](./bat-035_20260611_strategy-read-surface-slots-req/) |
|
||||
| BAT-036 | standard | confirmed | REQ-048 (CHG-20260611-01), REQ-005 (CHG-20260611-01) | dcy-024 | [bat-036](./bat-036_20260611_safety-sell-disable-mode/) |
|
||||
|
||||
Reference in New Issue
Block a user