Files
trex-core/docs/srs/Interface/req-036_auto-sell-internal-path.md
T
genichinandClaude Opus 4.8 cc28e1fba5 fix(execution): dcy-012 매도 가격 버그 정정 — slot entry_price→limit_price rename (BAT-016)
매도(sell) 주문이 현재가가 아닌 매수가(entry_price) 지정가로 나가던 버그(issue #10)
정정. 슬롯의 매수 전용 entry_price 를 side 무관 "현재 pending 주문 지정가"
limit_price 로 내부 rename 하고, pending 이탈(→holding/→closed) 시 clear 해
매수 지정가가 매도로 누수되는 경로를 구조적으로 제거.

거버넌스: 전부 change-req (신규 REQ 없음, dcy-012 OQ-3).
- REQ-002: Slot entry_price→limit_price rename + clear-on-exit 생애주기
- REQ-006: daily_slot 컬럼 rename 마이그레이션 006 (idempotent) + persistence 매핑
- REQ-013: _dispatch 가 slot.limit_price 단일 필드로 가격/주문유형 결정
- REQ-007: SellIntent/sell payload optional limit_price + _admit_sell 운반
- REQ-036: SlotService.sell optional 가격 → 자율 매도(safety-sell/kill-switch) 시장가
- REQ-003: 컬럼 계약/드리프트 가드 limit_price 반영
- REQ-015: runtime-flows/interface-contract/data-model 정합

매도 정책(OQ-1 하이브리드): 가격 지정→지정가("00"), 미지정→시장가("01").
자율 매도는 가격 미전달 → 항상 시장가 (손절 미체결 pending_sell 갇힘 방지, issue #9 연계).

검증: 단위 286 passed/32 skipped, 인프라 게이트(PG+RabbitMQ) 318 passed, ruff clean.
신규 test_sell_pricing(recording broker)로 지정가 매수 슬롯의 매도가 매수가
재사용 안 함을 직접 검증. BAT-016 release-candidate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:41:46 +09:00

6.2 KiB

req-036: 자동 매도 내부 경로 — SlotService.sell + idempotency

  • Status: Implemented
  • Type: Interface
  • Priority: High
  • Owner: project maintainers

Intent

자율 안전 매도 트리거가 RabbitMQ intent RPC를 거치지 않고 직접 슬롯 매도를 제출할 수 있도록 SlotService.sell() 내부 메서드를 추가한다. RabbitMQ 장애와 독립적으로 동작해야 하는 transport-independent 매도 경로다. 이미 pending_sell 상태인 슬롯에 대한 중복 트리거를 방지하는 idempotency도 함께 보장한다(dcy-007 FR-3, FR-4, A-1).

Requirement

  • SlotService는 sell(slot_id, actor, reason) 메서드를 제공해야 한다. 이 메서드는 holding 슬롯을 pending_sell로 전이시키고 기존 outbox 내구성·execution 루프 경로를 따른다.
  • sell()은 내부 함수 직접 호출이며 RabbitMQ intent RPC를 거치지 않는다.
  • 대상 슬롯이 이미 pending_sell 상태이면 sell()은 추가 전이 없이 조용히 반환하거나 멱등 응답을 반환해야 한다(중복 트리거 방지).
  • 대상 슬롯이 holding 이 아니고 pending_sell도 아닌 상태이면 적절한 예외 또는 오류 응답을 반환한다.
  • sell()을 통해 제출된 매도는 기존 execution worker의 transit_slot(holding→pending_sell) + broker dispatch + ledger 기록 경로를 재사용해야 한다.

Acceptance Criteria

  1. Given holding 상태의 슬롯 S가 있을 때, When SlotService.sell(S, actor="safety-sell", reason="stop_loss") 를 호출하면, Then S의 상태가 pending_sell로 전이된다.
  2. Given pending_sell 상태의 슬롯 S가 있을 때, When sell(S, ...) 를 다시 호출하면, Then 슬롯 상태가 변경되지 않고 중복 매도 intent가 제출되지 않는다.
  3. Given idle 상태의 슬롯 S가 있을 때, When sell(S, ...) 를 호출하면, Then 오류(예외 또는 rejected 응답)가 반환되고 슬롯 상태는 변경되지 않는다.
  4. Given sell() 호출 성공 시, When execution worker가 이후 처리하면, Then 매도 주문이 broker에 제출되고 outbox 및 ledger 경로가 기존 intent RPC 경로와 동일하게 작동한다.
  5. Given RabbitMQ transport가 불가용 상태일 때, When sell() 을 호출하면, Then transport 상태와 무관하게 holding→pending_sell 전이가 성공한다.

Impacted Area

  • Docs: 없음 (런타임 흐름 변경은 REQ-037~039에서 발생, baseline 문서 갱신은 REQ-042 참조)
  • Modules:
    • trex_core/domain/slot/service.py — SlotService.sell(slot_id, actor, reason) 메서드 추가
  • Tests:
    • SlotService.sell() 단위 테스트 — holding→pending_sell 전이 확인
    • idempotency 테스트 — pending_sell 슬롯 중복 호출 시 무전이 확인
    • 잘못된 상태(idle) 슬롯 호출 시 오류 반환 확인

Notes

  • sell()은 transit_slot(slot_id, from_state=HOLDING, to_state=PENDING_SELL, ...) 패턴 위에 구현한다. 기존 advisory lock + Postgres commit 보장이 그대로 적용된다.
  • NFR-2(자동 매도 실패 시 outbox retry): broker 오류 발생 시 execution worker의 기존 retry 경로를 따른다. 별도 retry 로직 불필요.
  • actor 값은 트리거 구분을 위해 "safety-sell", "forced-close", "market-close" 등으로 구체화하는 것을 권장한다. 정확한 값은 batch 설계에서 결정한다.
  • 이 메서드는 dcy-007 FR-3의 "내부 자동 매도 trigger 경로"를 표준화한다. 이후 kill-switch Discovery(trex-core#3)에서도 재사용 가능하도록 격리한다.

Change Log

CHG-20260607-01

  • Date: 2026-06-07
  • Author: Justin Ko

Change Summary

  • dcy-007 confirmed → REQ-036 초안 생성

Intent

  • 자동 매도 내부 경로(FR-3, FR-4)를 독립 Interface REQ로 정규화

Acceptance Criteria Delta

  • Added: AC-1~5 전체

Impacted Area Delta

  • Modules: service.py (sell() 메서드 추가)
  • Tests: 단위 테스트 3종

Delivery Trace Delta

  • Batches: none (미할당)
  • Releases: none

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: keep-current
  • Follow-up Action: suggest-batch-reqs 후 batch 배정

CHG-20260607-02

  • Date: 2026-06-07
  • Author: Justin Ko

Change Summary

  • Proposed → Approved (confirm-req)

Intent

  • 승인 게이트 통과: 필수 필드·AC·Impacted Area·Change Log 완비 확인. dcy-007(confirmed) 범위 및 결정 사항과 모순 없음.

Acceptance Criteria Delta

  • (변경 없음)

Impacted Area Delta

  • (변경 없음)

Delivery Trace Delta

  • Batches: none (미할당)
  • Releases: none

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: keep-current
  • Follow-up Action: suggest-batch-reqs 후 batch 배정

CHG-20260608-01

  • Date: 2026-06-08
  • Author: Justin Ko

Change Summary

  • (change-req, dcy-012) SlotService.sell 에 optional limit_price 파라미터(default None) 추가. 자율 매도(safety-sell/kill-switch)는 가격 미전달 → 시장가로 즉시 체결(미체결 pending_sell 갇힘 방지), 재량 경로만 지정가 전달 가능. BAT-016 재구현·재검증 완료 → Implemented 유지.

Intent

  • 자동 매도 내부 경로가 매수 지정가에 걸리지 않고 시장가로 체결되도록(issue #10/#9 연계), 가격 파라미터를 optional 로 추가하되 기본값 None 으로 자율 경로 체결성을 보장.

Acceptance Criteria Delta

  • Updated:
    • SlotService.sell(..., limit_price=None) — 미전달 시 시장가(슬롯 limit_price None), 전달 시 지정가.

Impacted Area Delta

  • Modules: trex_core/domain/slot/service.py(sell)
  • Tests: tests/application/test_sell_pricing.py::test_safety_sell_dispatches_at_market

Delivery Trace Delta

  • Batches: BAT-016
  • Releases: none

Revalidation Impact

  • Reverification Needed: yes (BAT-016 에서 완료)
  • Existing Implementation Invalidated: no (시그니처 확장, 기존 호출 default None 동일 동작)
  • Status Recommendation: Implemented (change-req → BAT-016 재검증)
  • Follow-up Action: confirm-req-implemented(BAT-016).

Validation Plan

  • BAT-016: svc.sell 가격 미전달 → 시장가 + closed 전이 단위.