chore(governance): remove legacy StagePilot artifacts

This commit is contained in:
Hermes Agent
2026-08-08 21:36:27 +09:00
parent 536c534a50
commit 2e5f59e09c
601 changed files with 0 additions and 55555 deletions
@@ -1,371 +0,0 @@
# req-002: slot 순수 도메인 이식 및 공개 API 확정
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 검증된 slot 상태머신/서비스 계약을 인프라에 오염되지 않은 storage-agnostic 코어로 trex-core 에 이식해, trex-core 의 표준 도메인 작성 패턴(순수 도메인 + Protocol 저장소 경계)을 확립한다.
## Requirement
- trex-orbit 의 순수 6개 모듈(`state`/`models`/`errors`/`repository`/`service`/`in_memory_repository`)과 `__init__.py` 를 `trex_core.domain.slot` 네임스페이스로 이식하고, 모듈 간 import 경로를 `trex_core.domain.slot.*` 로 통일하며, 공개 API 를 인프라 심볼 없이 노출한다.
## Acceptance Criteria
1. Given 이식 완료, When `from trex_core.domain.slot import SlotState, Slot, SlotCapacity, SlotTransitionRecord, SlotRepository, SlotService, SlotDomainError, SlotNotFoundError, SlotStateMismatchError, SlotTransitionError, is_allowed_transition, SLOT_ADVISORY_LOCK_ID, ALLOWED_TRANSITIONS` 를 실행, Then 모두 import 에 성공한다.
2. Given 이식된 도메인 코드, When 정적 import 스윕, Then stdlib 와 `trex_core.domain.slot` 내부 참조 외 외부 의존(psycopg/네트워크/CLI/config) import 가 0이다. (NFR-1)
3. Given 공개 API, When `__init__.py` 의 `__all__` 을 확인, Then `PostgreSQLSlotRepository`·`check_slot_domain_schema_drift` 등 인프라 심볼이 노출되지 않는다.
4. Given `SlotService`, When 6 상태/9 base 전이(`closed→pending_buy` 포함, dcy-019)/advisory-lock 직렬화/`closed→idle` 재진입 +1/`→pending_buy` 시 slot `entry_count` +1(dcy-019)/`closed→pending_buy` clean-slate 점유 초기화/lock 보유 중 외부 I/O 금지 동작을 확인, Then 보존된다. (NFR-2 — 검증은 REQ-003)
5. (CHG-20260610-02, dcy-023/issue #22) Given allocated_capital 제거 후, Then `Slot` 모델과 `EXPECTED_SLOT_FIELDS` 에 `allocated_capital` 필드가 없고, `SlotService` 의 설정/전이 경로(buy 진입·전이 시 set/clear)에서 해당 파라미터가 제거된다.
6. (CHG-20260612-01, issue #25) Given `SlotRepository.list_slots(instance_key, status_filter=None)`, When `status_filter` 가 status 값 집합(예: `{"inactive"}`, `{"pending_buy","pending_sell"}`)이면, Then 해당 status 슬롯만 반환하고 `None`(미지정)이면 기존대로 전체를 반환한다(in-memory 구현 포함). 기존 무인자 호출자는 동작이 불변이다.
## Impacted Area
- Docs: docs/interface-contract.md, docs/data-model.md (계약 기준 — 큰 변경 없을 수 있음)
- Modules: trex_core/domain/slot/{__init__,state,models,errors,repository,service,in_memory_repository}.py, (CHG-20260610-02) models.py `Slot`/`EXPECTED_SLOT_FIELDS` + service.py allocated_capital 제거, (CHG-20260612-01) repository.py `SlotRepository.list_slots` 시그니처 `status_filter` 옵션 + in_memory_repository.py 구현
- Tests: REQ-003 에서 이식 단위테스트 + 계약 테스트로 검증
## Notes
- NFR-1(순수 경계)·NFR-2(불변식 보존)를 본 REQ 의 acceptance 로 흡수. NFR-3(컬럼 계약)은 REQ-003 계약 테스트가 강제한다.
- 이식 시 유일한 코드 수정은 `__init__.py` docstring 정리 수준이며 로직 변경은 없다(dcy-001 A-2).
- 네임스페이스 `trex_core.domain.slot` 은 dcy-001 OQ-1 결정. REQ-001(부트스트랩) 선행.
- 출처: dcy-001 FR-2.
## Change Log
### CHG-20260603-01
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- dcy-001 FR-2 로부터 최초 생성(Proposed). NFR-1·NFR-2 를 acceptance 로 흡수.
#### Intent
- slot 순수 도메인 이식 + 공개 API 확정 요구사항을 backlog 로 정규화.
#### Acceptance Criteria Delta
- Added:
- 공개 API import, 외부 의존 0, 인프라 심볼 비노출, 도메인 불변식 보존 4개 기준
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/interface-contract.md, docs/data-model.md
- Modules:
- trex_core/domain/slot/* (6 모듈 + __init__)
- Tests:
- REQ-003 에 위임
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch 편성(REQ-001 과 동일 batch 가능)
#### Validation Plan
- 공개 API import 성공 + import 스윕(외부 의존 0) + REQ-003 테스트 통과로 검증.
### CHG-20260603-02
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트(필수 필드·구체 AC·blocker 없음) 충족, source dcy-001(confirmed, handoff 승인)과 모순 없음 확인.
#### Acceptance Criteria Delta
- Added:
- 없음
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/srs/index.md (Register 상태 Approved)
- Modules:
- 없음
- Tests:
- 없음
#### Delivery Trace Delta
- Batches:
- none (batch 편성 전)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: suggest-batch-reqs / draft-batch 로 delivery batch 편성
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ 의 Acceptance Criteria 를 검증 기준으로 사용.
### CHG-20260603-03
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-001 release-candidate).
#### Intent
- BAT-001 verification.md 의 evidence(공개 API import / import 스윕 외부 의존 0 / `__all__` 인프라 심볼 0 / 도메인 불변식 테스트)로 AC1~AC4 충족 → 구현 완료 동기화.
#### Acceptance Criteria Delta
- Added:
- 없음
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/srs/index.md (Register Implemented)
- Modules:
- 없음
- Tests:
- 없음
#### Delivery Trace Delta
- Batches:
- BAT-001 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: draft-release 로 release 편성
#### Validation Plan
- BAT-001 verification evidence 재참조로 충분.
### CHG-20260608-01
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-012/issue #10) 슬롯 도메인 필드 `entry_price` → `limit_price`(side 무관 "현재 pending 주문 지정가") 내부 rename + 생애주기 정의: pending 진입 시 set, pending 이탈(→HOLDING/→CLOSED) 시 None clear. `transit_slot`/`_apply_transition_fields` 파라미터·`EXPECTED_SLOT_FIELDS` 반영. BAT-016 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 매수 지정가가 매도 주문에 누수되는 구조적 원인을 도메인 모델에서 제거(clear-on-exit). 가격 필드 의미를 side 무관으로 통일.
#### Acceptance Criteria Delta
- Updated:
- Slot.`entry_price` → `limit_price`; →HOLDING/→CLOSED 전이 시 limit_price clear, →PENDING_* 전이 시 set.
#### Impacted Area Delta
- Modules: `trex_core/domain/slot/models.py`(Slot/EXPECTED_SLOT_FIELDS), `trex_core/domain/slot/service.py`(transit_slot/_apply_transition_fields clear-on-exit)
- Tests: tests/domain/slot/test_service.py(holding clear), tests/domain/slot/test_contract.py(필드셋)
#### Delivery Trace Delta
- Batches: BAT-016
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-016 에서 완료)
- Existing Implementation Invalidated: yes (entry_price 필드명/유지 의미)
- Status Recommendation: Implemented (change-req → BAT-016 재검증)
- Follow-up Action: confirm-req-implemented(BAT-016).
#### Validation Plan
- BAT-016: 전이별 set/clear 단위 + 컬럼 계약 가드(REQ-003) 정합.
### CHG-20260609-01
- Date: 2026-06-09
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-019/issue #18) 슬롯 도메인에 (1) slot-scoped `Slot.entry_count`(기본 0) 필드 + `EXPECTED_SLOT_FIELDS` 추가, (2) 상태 머신 허용 전이에 `closed→pending_buy`(closed 슬롯 직접 재할당) 추가(8→9 base 전이), (3) `_apply_transition_fields` 에 closed→pending_buy clean-slate 점유 초기화 + 모든 `→pending_buy`(idle→/closed→) 시 `entry_count` +1 로직 반영. 기존 `daily_symbol_entries`(symbol-scoped, AC-3)는 무관·미변경. BAT-025 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 슬롯 자원을 고르게 재사용(최저 진입 우선)하고 idle 소진 시 closed 재할당을 허용하기 위해, 슬롯 단위 누적 진입 횟수를 도메인 정본에 영속하고 closed→pending_buy 직접 전이를 도메인 계약에 추가.
#### Acceptance Criteria Delta
- Updated:
- AC-4: "6 상태/8 전이" → "6 상태/9 base 전이(`closed→pending_buy` 포함)". 불변식 보존 대상에 `→pending_buy 시 entry_count +1`, `closed→pending_buy clean-slate 점유 초기화` 추가.
- Added:
- `Slot.entry_count`(int, 기본 0) 필드가 `EXPECTED_SLOT_FIELDS` 계약에 포함된다.
#### Impacted Area Delta
- Modules: `trex_core/domain/slot/models.py`(Slot.entry_count/EXPECTED_SLOT_FIELDS), `trex_core/domain/slot/state.py`(closed→pending_buy 전이), `trex_core/domain/slot/service.py`(clean-slate + entry_count +1)
- Tests: tests/domain/slot/test_state.py(전이 카운트 14→15), test_contract.py(필드셋), test_slot_entry_count.py(신규)
#### Delivery Trace Delta
- Batches: BAT-025
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-025 에서 완료)
- Existing Implementation Invalidated: no (additive — 기존 idle-only 동작은 closed 후보 부재 시 보존, 회귀 green)
- Status Recommendation: Implemented (change-req → BAT-025 재검증)
- Follow-up Action: confirm-req-implemented(BAT-025).
#### Validation Plan
- BAT-025: 전이 카운트/계약 가드 + entry_count 증분·보존 + closed→pending_buy clean-slate 단위 테스트 green; `daily_symbol_entries`(AC-3) 회귀 green.
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-020 자산 중심 슬롯 모델) 본 REQ 의 슬롯 도메인(6상태·`closed→idle` 복구·entry_count·익명 슬롯)이 dcy-020 으로 **재정의/폐기 예정**. 신규 REQ-057(상태머신 inactive↔pending_buy↔holding↔pending_sell·holding 로컬·인스턴스 스코프 lock)·REQ-056(영구 슬롯 필드·entry_count 제거)·REQ-062(qty hub 정본+미러)가 대체. **현재 코드는 불변이므로 Implemented 유지(keep-current)**, 실제 폐기/재정의는 dcy-020 delivery 배치(상태머신/스키마 BAT)에서 확정한다.
#### Intent
- 자산 1:1 영구 슬롯 모델 전환의 추적성을 본 REQ 에 forward-link.
#### Acceptance Criteria Delta
- Updated: 없음(본 주기 변경 없음 — dcy-020 delivery 배치에서 AC 재정의 예정)
#### Impacted Area Delta
- Docs: dcy-020, REQ-056/057/062
- Modules: (예정) domain/slot/state.py·models.py·service.py
- Tests: (예정) REQ-057 테스트로 대체
#### Delivery Trace Delta
- Batches: (예정) dcy-020 상태머신/스키마 배치
- Releases: none
#### Revalidation Impact
- Reverification Needed: no (현 시점)
- Existing Implementation Invalidated: no (코드 불변 — dcy-020 delivery 시 무효화·재정의)
- Status Recommendation: keep-current
- Follow-up Action: dcy-020 delivery 배치에서 Deprecated/재정의 + 그때 status 전환.
#### Validation Plan
- dcy-020 상태머신 배치의 verification 으로 대체.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-023/issue #22) 죽은 필드 `allocated_capital` 을 슬롯 도메인에서 제거 — `Slot` 모델·`EXPECTED_SLOT_FIELDS` 계약·`SlotService` 의 설정/전이(set/clear) 경로에서 삭제. 소비처(의사결정/회계/사이징) 0건 확인(dcy-023 §3). AC-5 추가, Implemented→Approved(재구현 대기).
#### Intent
- 실제 소비되는 필드만 슬롯 계약에 남겨 유지 비용과 "capital 이 사이징한다"는 오해를 제거. dcy-021 사이징 계약(전략이 qty 계산, core 미관여) 확정의 귀결.
#### Acceptance Criteria Delta
- Added:
- AC-5: Slot 모델·EXPECTED_SLOT_FIELDS·SlotService 경로에서 allocated_capital 부재.
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Modules: trex_core/domain/slot/models.py(Slot/EXPECTED_SLOT_FIELDS), trex_core/domain/slot/service.py(설정/전이 경로 파라미터 제거)
- Tests: tests/domain/slot/ 계약 테스트(필드셋) + allocated_capital 참조 테스트 정리
#### Delivery Trace Delta
- Batches: (예정) dcy-023 batch
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (dcy-023 batch 에서 수행)
- Existing Implementation Invalidated: yes (필드 제거 — 기존 필드셋 계약 evidence 무효)
- Status Recommendation: Approved (Implemented→Approved 되돌림)
- Follow-up Action: dcy-023 batch 구현·검증 후 confirm-req-implemented.
#### Validation Plan
- dcy-023 batch: 필드셋 계약 테스트(allocated_capital 부재) + 전체 suite 회귀 green.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-034(release-candidate) verification — allocated_capital 전 경로 제거(도메인/intent/영속/snapshot/CLI), 마이그레이션 013 테스트 DSN 멱등 round-trip + 컬럼 부재 확인, 전체 428 passed + PG 게이트 21 passed + ruff clean, grep 전수 0건. Blocking Issues 없음.
### CHG-20260612-01
- Date: 2026-06-12
- Author: Justin Ko
#### Change Summary
- (change-req, issue #25) `SlotRepository.list_slots` 에 optional `status_filter` 파라미터를 추가해 status 필터링을 저장소 경계로 내린다. 시그니처 `list_slots(instance_key, status_filter: Optional[set[str]] = None)` — `None` 은 기존(전체), 값 집합이면 해당 status 만 반환. in-memory 구현도 동일 의미로 갱신. slots RPC 핸들러(REQ-073)의 per-request full scan + Python 필터를 제거하기 위한 포트 확장. 신규 AC-6 추가 구현·검증 필요 → **Implemented → Approved 되돌림**.
#### Intent
- `trex.slots.req` 가 매 요청마다 전 슬롯을 fetch 한 뒤 Python 에서 거르던 구조(issue #25)를 DB 레벨 필터로 바꾸기 위해, 도메인 포트(`list_slots`)와 in-memory 더블을 먼저 확장한다. 기존 무인자 호출자(reconcile/safety-sell 등)는 default `None` 으로 동작 불변.
#### Acceptance Criteria Delta
- Added:
- AC-6: `list_slots(instance_key, status_filter)` — status 값 집합 필터 + `None` 전체, in-memory 포함, 기존 호출자 불변.
- Updated/Removed: 없음
#### Impacted Area Delta
- Docs: 없음
- Modules: `trex_core/domain/slot/repository.py`(Protocol 시그니처), `trex_core/domain/slot/in_memory_repository.py`(구현)
- Tests: in-memory `list_slots(status_filter)` 단위 — status 집합 필터 + None 전체 + 기존 무인자 회귀
#### Delivery Trace Delta
- Batches: BAT-040 (예정, issue #25)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-040 에서 AC-6 + 기존 AC 회귀)
- Existing Implementation Invalidated: no (추가 파라미터는 default None 으로 기존 동작 보존). 단 신규 AC-6 미구현으로 Implemented 유지 불가 → Approved.
- Status Recommendation: Implemented → **Approved**
- Follow-up Action: confirm-req → BAT-040 구현·검증 → confirm-req-implemented
#### Validation Plan
- BAT-040: in-memory `list_slots` status 집합 필터 + None 전체 단위 테스트, 기존 무인자 호출 회귀, 전체 suite + ruff clean.
### CHG-20260612-IMPL
- Date: 2026-06-12
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-040(release-candidate) verification — AC-6 `list_slots(status_filter)` in-memory 5종(None 전체/단일 status/pending 그룹/무매치/instance 스코프) PASSED, 무인자 호출자 default None 동작 보존(전체 439 passed), ruff clean. Blocking Issues 없음.
@@ -1,443 +0,0 @@
# req-007: intent 제출 HTTP API + 멱등
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 매수·매도 전략 데몬이 HTTP 로 intent 를 제출하면 코어가 단독으로 admission/검증 후 슬롯을 전이하도록 한다(전략은 제안, 코어가 집행). intent_id 멱등으로 재전송 안전을 보장한다.
## Requirement
- `POST /v1/intents/buy` 와 `POST /v1/intents/sell` 를 제공한다. 코어는 admission/검증 후 슬롯 전이(idle→pending_buy / holding→pending_sell)를 advisory lock 하 단일 writer 로 수행하고, 동기로 admit/reject 를 응답한다. 수락된 intent 는 같은 트랜잭션에서 `intent_log`(intent_id, payload, decision, ts) 에 durable 기록하며 `intent_id` 로 dedup 한다. `GET /v1/intents/{intent_id}` 로 결정을 재조회한다.
## Acceptance Criteria
1. Given 할당 가능 슬롯(idle ∪ closed, dcy-019), When `POST /v1/intents/buy`, Then `find_allocatable_slot`(entry_count→updated_at→slot_id 정렬)로 최저 진입 후보를 잡아 `slot.status→pending_buy`(idle→ 또는 closed→ 직접 재할당) 전이하고 `{admitted:true, slot_id}` 를 동기 응답한다. idle·closed 모두 소진 시 `no_idle_slot` 거부.
2. Given holding 슬롯, When `POST /v1/intents/sell`, Then 검증 통과 시 holding→pending_sell 로 전이하고 admit 결과를 동기 응답한다(거부 시 사유 포함).
3. Given 이미 처리된 `intent_id`, When 동일 intent 재전송, Then 슬롯이 중복 전이되지 않고 최초 결정과 동일한 응답을 돌려준다(멱등). (NFR-3)
4. Given 동일 슬롯에 대한 동시 intent, When 병렬 처리, Then advisory lock 으로 직렬화되어 단일 writer 불변식이 유지된다(매수·매도 전략은 슬롯을 직접 쓰지 않음). (NFR-2)
5. Given 수락된 intent, When `GET /v1/intents/{intent_id}`, Then 기록된 decision 을 반환한다.
6. (CHG-20260610-02, dcy-023/issue #22) Given buy intent payload, Then `allocated_capital` 은 계약 필드가 아니다 — `BuyIntent` 에 필드가 없고 admission 경로에서 전달되지 않으며, 외부 발신자가 payload 에 키를 포함해도 unknown key 로 무시된다(즉시 제거, dcy-023 OQ-1).
7. (CHG-20260615-01, issue #27) Given **rejected** sell intent 응답(`intent_type:"sell"`, `status:"rejected"`), Then additive `retryable: bool` 필드가 포함된다 — core 가 소유한 reason→retryable 매핑으로 채워지고 `reason` 은 유지된다. 매핑: `slot_state_changed`/`slot_not_holding:pending_buy`/`duplicate_in_flight` → `true`; `slot_not_found`/`slot_not_holding:inactive`/`slot_not_holding:pending_sell`/`slot_not_holding:error`/`bad_request:*` → `false`; 미인식 reason → `true`(안전 기본 — 멈춘 손절매가 hammering 보다 위험). admitted/processing/buy 응답·기존 필드는 불변(완전 additive·하위호환).
## Impacted Area
- Docs: docs/interface-contract.md(HTTP API 계약), docs/runtime-flows.md(요청 흐름) — REQ-009 에서 정합
- Modules: trex_core/ 하위 API 어댑터(FastAPI 라우터/스키마) + 애플리케이션 서비스; 도메인 패키지는 무의존 유지(NFR-1); (CHG-20260610-02) intents.py BuyIntent·admission + messaging_handlers.py payload 파싱 allocated_capital 제거
- Tests: API 통합테스트(정상/거부/멱등 재전송/동시성)
## Notes
- 동기 커밋 + intent_id 멱등 + intent_log(dcy-002 OQ-1). 완전 비동기 outbox 는 브로커 Discovery 로 Deferred.
- `intent_log` 테이블은 REQ-006 에서 생성. REQ-005(런타임)·REQ-006(영속화) 선행.
- NFR-2(단일 writer)·NFR-3(멱등) 흡수.
- 출처: dcy-002 FR-2, FR-4.
## Change Log
### CHG-20260603-01
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- dcy-002 FR-2·FR-4 로부터 최초 생성(Proposed). NFR-2·NFR-3 흡수.
#### Intent
- intent 제출 API + 멱등 요구사항을 backlog 로 정규화.
#### Acceptance Criteria Delta
- Added:
- buy/sell 전이, 멱등 재전송, 동시성 단일 writer, intent 재조회 5개 기준
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/interface-contract.md, docs/runtime-flows.md
- Modules:
- API 어댑터(FastAPI) + 애플리케이션 서비스
- Tests:
- API 통합테스트(정상/거부/멱등/동시성)
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch 편성
#### Validation Plan
- API 통합테스트(멱등 재전송 + 동시성 직렬화 포함)로 검증.
### CHG-20260603-02
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트(필수 필드·구체 AC·blocker 없음) 충족, source dcy-002(confirmed, handoff 승인)와 모순 없음 확인.
#### Acceptance Criteria Delta
- Added:
- 없음
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/srs/index.md (Register 상태 Approved)
- Modules:
- 없음
- Tests:
- 없음
#### Delivery Trace Delta
- Batches:
- none (batch 편성 전)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: suggest-batch-reqs / draft-batch 로 delivery batch 편성
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ 의 Acceptance Criteria 를 검증 기준으로 사용.
### CHG-20260603-03
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-002 release-candidate).
#### Intent
- BAT-002 verification.md 의 acceptance mapping + evidence(pytest 74 pass / PG 통합 / 데몬 E2E)로 모든 AC 충족 → 구현 완료 동기화.
#### Acceptance Criteria Delta
- Added:
- 없음
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/srs/index.md (Register Implemented)
- Modules:
- 없음
- Tests:
- 없음
#### Delivery Trace Delta
- Batches:
- BAT-002 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: draft-release 로 release 편성
#### Validation Plan
- BAT-002 verification evidence 재참조로 충분.
### CHG-20260608-01
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-011) buy intent admission 계약 변경: `portfolio_id` 필수화 + admission 시 universe(`SnapshotStore`) 에서 `symbol` resolve + universe 부재 시 `unknown_portfolio` 거부. 기존 symbol-필수/portfolio_id-optional 폐기(hard cutover, 하위호환 없음). BAT-015 에서 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 정식 식별자(asset_id=portfolio_id) 기반 원장 귀속·safety 보호 범위 정합(issue #6). `_admit_buy` 에 portfolio_id_required/unknown_portfolio reject + symbol resolve(`resolve_symbol` 주입) 추가.
#### Acceptance Criteria Delta
- Added:
- buy 는 portfolio_id 필수(누락 시 `portfolio_id_required`), symbol 은 서버 resolve(`SnapshotStore`), universe 부재 시 `unknown_portfolio` 거부.
- Updated:
- 기존 admission AC 의 symbol 입력 전제 → portfolio_id 기반으로 정정.
#### Impacted Area Delta
- Modules: `trex_core/application/intents.py`(BuyIntent portfolio_id 필수+symbol resolve, IntentService.resolve_symbol), `messaging_handlers.py`(buy payload), `runtime/daemon.py`(resolver 배선)
- Docs: `docs/interface-contract.md`, `docs/runtime-flows.md`
- Tests: intent/messaging buy 테스트 portfolio_id 기반 전환
#### Delivery Trace Delta
- Batches: BAT-015
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-015 에서 완료)
- Existing Implementation Invalidated: yes (symbol-필수 admission 경로)
- Status Recommendation: Implemented (change-req → BAT-015 재구현·재검증)
- Follow-up Action: confirm-req-implemented(BAT-015) 로 Implemented 동기화.
#### Validation Plan
- BAT-015 verification: portfolio_id_required/unknown_portfolio/symbol resolve 단위 + 전체 회귀(314 passed).
### CHG-20260608-02
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-012) sell intent 계약에 optional 매도 가격 필드 추가: `SellIntent.limit_price`(+ sell payload `limit_price`) → `_admit_sell` 이 슬롯 `limit_price` 로 운반. 지정 시 지정가 매도, 미지정 시 시장가(자율 매도 기본 경로). buy 의 `entry_price` 는 동일 슬롯 `limit_price` 로 매핑(동작 동일). BAT-016 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 매도 가격 하이브리드 정책(가격 유무 분기, dcy-012 OQ-1/OQ-2)을 intent 제출 계약에 반영. 기존 재량 매도 호출(가격 미지정)은 시장가로 안전 동작(NFR-3).
#### Acceptance Criteria Delta
- Added:
- sell intent/payload optional `limit_price`(미지정 → 시장가, 지정 → 지정가). admission 이 슬롯 limit_price 로 운반.
#### Impacted Area Delta
- Modules: `trex_core/application/intents.py`(SellIntent/_admit_sell, _admit_buy limit_price 매핑), `trex_core/application/messaging_handlers.py`(sell payload limit_price)
- Docs: docs/interface-contract.md
- Tests: tests/application/test_sell_pricing.py
#### Delivery Trace Delta
- Batches: BAT-016
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-016 에서 완료)
- Existing Implementation Invalidated: no (optional 추가, 기존 sell 호출 시장가로 호환)
- Status Recommendation: Implemented (change-req → BAT-016 재검증)
- Follow-up Action: confirm-req-implemented(BAT-016).
#### Validation Plan
- BAT-016: 가격 전달 매도 → 지정가 / 미전달 → 시장가 단위 + 핸들러 payload.
### CHG-20260608-03
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, REL-004 사전 run 검증에서 발견된 결함 수정) 데몬 buy 심볼 resolver 버그 정정: `Daemon._resolve_symbol` 이 `SnapshotStore.get()` 반환값(`SnapshotAsset`)에서 `asset.symbol` 을 접근했으나 symbol 은 `asset.item.symbol` 에 있어 `AttributeError` → 데몬 buy admission 이 매번 크래시(intent RPC 타임아웃). `asset.item.symbol` 로 수정. 단위 테스트가 stub resolver 를 주입해 실 데몬 배선을 한 번도 실행하지 않아 369 passed 에도 누락됐다 — 실 데몬 기동 + CLI e2e(REL-004 smoke)에서 검출. Implemented 유지.
#### Intent
- dcy-011/REQ-007 의 buy 심볼 서버 resolve 가 실 런타임(daemon + SnapshotStore)에서 동작하도록 배선 결함 수정 + 회귀 가드 추가.
#### Acceptance Criteria Delta
- (변경 없음 — AC 동일; 배선 결함 수정. 실 데몬 resolver 가 SnapshotAsset.item.symbol 을 읽음)
#### Impacted Area Delta
- Modules: `trex_core/runtime/daemon.py`(`_resolve_symbol` → `asset.item.symbol`)
- Tests: tests/runtime/test_daemon_resolve_symbol.py(실 Daemon._resolve_symbol × 실 SnapshotStore 회귀)
#### Delivery Trace Delta
- Batches: BAT-015
- Releases: REL-004 (사전 run 검증에서 검출·수정)
#### Revalidation Impact
- Reverification Needed: yes (REL-004 live smoke + 회귀 테스트로 완료)
- Existing Implementation Invalidated: yes (데몬 buy admission 경로 — 실 런타임에서 전면 실패였음)
- Status Recommendation: Implemented (배선 수정 + 회귀 가드)
- Follow-up Action: REL-004 confirm-release 전 live smoke 증거에 반영.
#### Validation Plan
- 실 데몬 기동(paper + test PG/RabbitMQ) + `trex-core enter pf-005930 --yes` → admitted/체결/ledger completed e2e + test_daemon_resolve_symbol 회귀.
### CHG-20260609-01
- Date: 2026-06-09
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-019/issue #18) buy admission(`_admit_buy`) 의 슬롯 선택을 `find_idle_slot` → `find_allocatable_slot`(idle ∪ closed, entry_count→updated_at→slot_id 정렬)로 일반화하고, 후보 status 를 따르도록 transit from_state 를 하드코딩 `IDLE` → `slot.status` 로 변경(closed 후보면 `closed→pending_buy` 직접 재할당). 마지막 슬롯 경합 재시도 루프·멱등(intent_log dedup)·단일 writer 불변식 보존. BAT-025 검증 완료 → Implemented 유지.
#### Intent
- idle 소진 시에도 closed 슬롯을 재할당해 슬롯 자원을 효율적으로 회전시키고, 슬롯 사용을 진입 횟수 기준으로 고르게 분산.
#### Acceptance Criteria Delta
- Updated:
- AC-1: 후보 = idle ∪ closed, `find_allocatable_slot` 선택 + `slot.status→pending_buy` 전이(closed 직접 재할당 포함), 양쪽 소진 시 `no_idle_slot` 거부로 일반화.
#### Impacted Area Delta
- Modules: `trex_core/application/intents.py`(`_admit_buy`: find_allocatable_slot + from_state=slot.status)
- Tests: tests/application/test_buy_admission_reallocation.py(신규: closed 재할당 admit/idle 우선/양쪽 소진 reject), tests/application/test_intent_concurrency.py(경합 회귀 보존)
#### Delivery Trace Delta
- Batches: BAT-025
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-025 에서 완료)
- Existing Implementation Invalidated: no (closed 후보 부재 시 기존 idle-only 동작과 동일 — 회귀 green)
- Status Recommendation: Implemented (change-req → BAT-025 재검증)
- Follow-up Action: confirm-req-implemented(BAT-025).
#### Validation Plan
- BAT-025: closed 재할당 admit / idle 우선 / 양쪽 소진 reject 단위 + 동시성 경합 회귀 green.
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-020) buy/sell admission 이 자산 중심으로 **재정의 예정** — REQ-059(FCFS·M캡·무치환·over-cap)·REQ-061(intent 자산 키 통일, `sell-by-slot_id` 폐기, already_active/not_holding)가 대체. `find_allocatable_slot`/idle·closed 배정 폐기. 외부 전략 계약 변경(NFR-4) 동반. 현재 코드 불변이라 Implemented 유지(keep-current), dcy-020 admission/intent 배치에서 확정(외부 계약 cutover 게이트).
#### Intent
- 신호 기반 자산 admission 전환 추적성 forward-link.
#### Acceptance Criteria Delta
- Updated: 없음(dcy-020 delivery 배치에서 admission/intent AC 재정의)
#### Impacted Area Delta
- Docs: dcy-020, REQ-059/061
- Modules: (예정) application/intents.py·메시지 핸들러/스키마
- Tests: (예정) intent/admission 테스트 재작성
#### Delivery Trace Delta
- Batches: (예정) dcy-020 admission/intent 배치(외부 계약 cutover)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no (현 시점)
- Existing Implementation Invalidated: no (코드 불변)
- Status Recommendation: keep-current
- Follow-up Action: dcy-020 admission/intent 배치에서 재정의 + status 전환. 외부 전략 모듈 동시 전환(NFR-4).
#### Validation Plan
- dcy-020 admission/intent 배치 verification 으로 대체.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-023/issue #22) buy intent payload 계약에서 `allocated_capital` 즉시 제거 — `BuyIntent` 데이터클래스 필드·admission 전달(`_admit_buy`→SlotService)·messaging handler payload 파싱(`body.get("allocated_capital")`) 삭제. 외부 발신자(trex-orb-v1)가 키를 계속 송신해도 unknown key 로 무시되어 무해(dcy-023 OQ-1 운영자 결정: 즉시 제거, 유예 없음). AC-6 추가, Implemented→Approved(재구현 대기).
#### Intent
- 사이징·회계 소비자가 없는 운반 전용 필드를 intent 계약에서 제거. dcy-021 명령형 qty 사이징 계약과 정합.
#### Acceptance Criteria Delta
- Added:
- AC-6: BuyIntent 에 allocated_capital 부재 + 수신 payload 의 해당 키 무시.
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Modules: trex_core/application/intents.py(BuyIntent/admission), trex_core/application/messaging_handlers.py(payload 파싱)
- Tests: intent admission·handler 파싱 테스트에서 allocated_capital 참조 정리 + 키 포함 payload 무시 테스트
#### Delivery Trace Delta
- Batches: (예정) dcy-023 batch
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (dcy-023 batch 에서 수행)
- Existing Implementation Invalidated: yes (BuyIntent 필드·파싱 제거)
- Status Recommendation: Approved (Implemented→Approved 되돌림)
- Follow-up Action: dcy-023 batch 구현·검증 후 confirm-req-implemented.
#### Validation Plan
- dcy-023 batch: allocated_capital 포함 payload 가 정상 admit 되며 슬롯·로그에 미반영(무시) + 전체 suite green.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-034(release-candidate) verification — allocated_capital 전 경로 제거(도메인/intent/영속/snapshot/CLI), 마이그레이션 013 테스트 DSN 멱등 round-trip + 컬럼 부재 확인, 전체 428 passed + PG 게이트 21 passed + ruff clean, grep 전수 0건. Blocking Issues 없음.
### CHG-20260615-01
- Date: 2026-06-15
- Author: Justin Ko
#### Change Summary
- (change-req, issue #27) rejected SellIntent 응답에 additive `retryable: bool` 추가. core 소유 reason→retryable 매핑으로 채우고 `reason` 유지. #26 sell-idempotency 논의(거부 sticky)의 후속 — 데몬이 reason 문자열 하드코딩 없이 권위 플래그로 retry/stop 판단(손절매 안전 경로 decoupling).
#### Intent
- 거부 retryability를 core 도메인 지식으로 캡슐화해, 새 reason 추가 시 데몬 분류가 조용히 drift하는 안전 실패 모드 제거(issue #27).
#### Acceptance Criteria Delta
- Added: AC-7 (rejected sell 응답 additive `retryable` + core 소유 매핑 + 미인식 기본 true + 완전 additive)
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/interface-contract.md(rejected sell 응답 `retryable` 필드)
- Modules: trex_core/application/messaging_handlers.py(intent 응답 빌더 — sell+rejected 시 retryable; core 소유 `_SELL_REJECT_RETRYABLE` 매핑)
- Tests: tests/application/(retryable 플래그 매핑 케이스 + additive 하위호환)
#### Delivery Trace Delta
- Batches: BAT-043(편성 예정)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (신규 AC-7만)
- Existing Implementation Invalidated: no (완전 additive — 기존 응답 필드/admit/buy 불변)
- Status Recommendation: revert-to-approved (Implemented → Approved — 신규 additive AC 구현·검증 대기)
- Follow-up Action: BAT-043 batch-lite 구현·검증 후 confirm-req-implemented
#### Validation Plan
- messaging_handlers 테스트: 각 reject reason → 기대 retryable 매핑, 미인식 reason → true, admitted/processing/buy 응답에 retryable 부재, 기존 reason 필드 유지.
### CHG-20260615-IMPL
- Date: 2026-06-15
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-043(release-candidate) verification — rejected sell 응답 additive `retryable`(core 소유 `_SELL_REJECT_RETRYABLE` 매핑 + `_sell_reject_retryable` helper, 미인식 true/`bad_request*` false). AC-7 evidence: `tests/application/test_sell_retryable_flag.py`(매핑 7 reason+미인식+None+bad_request, 응답 inactive/unknown_slot/bad_request→false, admitted/buy 부재). 487 passed, ruff clean. 기존 AC-1~6 불변. Blocking Issues 없음.
@@ -1,152 +0,0 @@
# req-008: 슬롯 read-only 조회 HTTP API
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 매도 전략이 보유 슬롯을 평가하고 운영자가 가용성을 모니터링할 수 있도록, 코어가 슬롯 스냅샷과 capacity 를 read-only 로 제공한다.
## Requirement
- `GET /v1/slots?status=holding`(status/trading_date 필터)로 슬롯 스냅샷을 read-only 로 반환하고, `GET /v1/capacity` 로 idle/holding/pending 카운트 + scarcity_ratio 를 반환한다. 이 엔드포인트는 슬롯을 쓰지 않는다(read-only).
## Acceptance Criteria
1. Given holding 슬롯이 있는 상태, When `GET /v1/slots?status=holding`, Then 해당 슬롯 스냅샷 목록을 반환한다(쓰기 부작용 없음).
2. Given status/trading_date 필터, When 조회, Then 필터에 맞는 슬롯만 반환한다.
3. Given 슬롯 분포, When `GET /v1/capacity`, Then idle/holding/pending 카운트와 scarcity_ratio 를 반환한다.
## Impacted Area
- Docs: docs/interface-contract.md(조회 API 계약) — REQ-009 에서 정합
- Modules: trex_core/ 하위 API 어댑터(읽기 라우터); 도메인 `compute_slot_capacity`/repo 조회 재사용
- Tests: 조회 API 통합테스트
## Notes
- 엔드포인트 집합은 dcy-002 OQ-3 결정. REQ-005(런타임)·REQ-006(영속화) 선행.
- read-only 라 단일 writer 불변식과 무관(쓰기 경로 아님).
- 출처: dcy-002 FR-3.
## Change Log
### CHG-20260603-01
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- dcy-002 FR-3 로부터 최초 생성(Proposed).
#### Intent
- 슬롯 read-only 조회 API 요구사항을 backlog 로 정규화.
#### Acceptance Criteria Delta
- Added:
- holding 스냅샷, 필터, capacity 3개 기준
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/interface-contract.md
- Modules:
- API 어댑터(읽기 라우터)
- Tests:
- 조회 API 통합테스트
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch 편성
#### Validation Plan
- 조회 API 통합테스트(스냅샷/필터/capacity)로 검증.
### CHG-20260603-02
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트(필수 필드·구체 AC·blocker 없음) 충족, source dcy-002(confirmed, handoff 승인)와 모순 없음 확인.
#### Acceptance Criteria Delta
- Added:
- 없음
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/srs/index.md (Register 상태 Approved)
- Modules:
- 없음
- Tests:
- 없음
#### Delivery Trace Delta
- Batches:
- none (batch 편성 전)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: suggest-batch-reqs / draft-batch 로 delivery batch 편성
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ 의 Acceptance Criteria 를 검증 기준으로 사용.
### CHG-20260603-03
- Date: 2026-06-03
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-002 release-candidate).
#### Intent
- BAT-002 verification.md 의 acceptance mapping + evidence(pytest 74 pass / PG 통합 / 데몬 E2E)로 모든 AC 충족 → 구현 완료 동기화.
#### Acceptance Criteria Delta
- Added:
- 없음
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/srs/index.md (Register Implemented)
- Modules:
- 없음
- Tests:
- 없음
#### Delivery Trace Delta
- Batches:
- BAT-002 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: draft-release 로 release 편성
#### Validation Plan
- BAT-002 verification evidence 재참조로 충분.
@@ -1,157 +0,0 @@
# req-025: HTTP `/v1` API 완전 제거 (healthz 포함, HTTP 표면 0)
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- RabbitMQ 단일 transport 결정(dcy-006 OQ-1)에 따라 trex-core 의 HTTP `/v1` API 표면을 0 으로 만든다. 전략-facing 엔드포인트뿐 아니라 `GET /v1/healthz` 같은 앱 레벨 헬스 표면까지 제거하고(OQ-7), liveness 는 프로세스 감독(systemd/supervisor/docker restart)이 담당한다. 이중 transport 병행을 두지 않는다.
## Requirement
- 아래 HTTP 엔드포인트와 그 어댑터를 trex-core 코드와 baseline 에서 제거한다.
- `POST /v1/intents/buy`, `POST /v1/intents/sell`
- `GET /v1/intents/{intent_id}`
- `GET /v1/slots`, `GET /v1/capacity`
- `GET /v1/healthz`
- dcy-005 가 HTTP 로 가정한 스냅샷 read 엔드포인트(아직 미구현인 경우 가정 자체 갱신)
- `trex_core/adapters/api/` HTTP 어댑터 패키지를 제거하고, FastAPI/uvicorn/Starlette 직접 의존을 코어 런타임에서 제거한다(테스트 전용 보조 import 도 마찬가지). `pyproject.toml` 의 `fastapi`/`uvicorn` 의존성을 정리한다.
- `TREX_API_HOST` / `TREX_API_PORT` env 와 그 로딩 코드를 폐기한다(`DaemonConfig`/`.env.example` 정리).
- 데몬 기동 후 HTTP 리스너가 어떤 포트에도 바인딩되어 있지 않아야 한다(HTTP 표면 0). 앱 레벨 헬스/관측성은 로그·메트릭으로 대체한다.
- dcy-002 의 HTTP intent API 가정과 dcy-005 의 HTTP pull 가정(FR-1/A-3)을 cross-reference 로 갱신한다.
## Acceptance Criteria
1. Given 새 트리, When `find trex_core -path '*/adapters/api/*'` 또는 `grep -r "fastapi\|uvicorn" trex_core/`, Then 결과가 비어 있다(HTTP 어댑터 잔존 0).
2. Given trex-core daemon, When 기동 후 포트 스캔, Then 어떤 TCP 포트에도 HTTP 리스너가 열려 있지 않다(HTTP 표면 0, dcy-006 S-6).
3. Given `DaemonConfig.from_env()`, When 환경 변수 로딩, Then `TREX_API_HOST`/`TREX_API_PORT` 를 더 이상 참조하지 않고, 누락되어도 기동에 영향이 없다.
4. Given `pyproject.toml`, When 의존성 목록을 점검, Then `fastapi`/`uvicorn`/`starlette` 가 코어 runtime 의존성에서 제거되어 있다.
5. Given dcy-002·dcy-005 의 HTTP 가정 본문, When 본 변경 완료 시점에 cross-reference 갱신을 확인, Then 두 Discovery 의 HTTP 가정이 "transport 는 RabbitMQ(dcy-006)" 로 일관되게 안내된다.
6. Given liveness 확인 시나리오, When 프로세스 감독(systemd/supervisor/docker restart)이 프로세스 죽음을 감지, Then 재시작이 broker 가용성과 무관하게 동작한다(broker 장애가 재시작 루프 유발 금지).
## Impacted Area
- Docs: docs/interface-contract.md(HTTP `/v1` 섹션 제거), docs/runtime-flows.md(HTTP 흐름 제거), docs/project-structure.md(adapters/api 제거), docs/discovery/dcy-002·dcy-005 cross-reference 갱신 — REQ-026 에서 정합.
- Modules:
- 제거 `trex_core/adapters/api/` 전체(`app.py`, `schemas.py`)
- 변경 `trex_core/runtime/daemon.py`(uvicorn import/실행 제거; REQ-022 의 sync+thread 런타임으로 교체)
- 변경 `trex_core/runtime/config.py`(`TREX_API_HOST`/`TREX_API_PORT` 폐기)
- 변경 `pyproject.toml`(fastapi/uvicorn 제거; httpx 는 ledger 어댑터 사용처가 있으므로 유지)
- 변경 `.env.example`(API_HOST/PORT 제거, `TREX_RABBITMQ_URL` 추가는 REQ-022 책임)
- Tests:
- 제거 `tests/adapters/api/` 전체(또는 messaging 등가 테스트로 이관)
- 추가 daemon HTTP-표면-0 회귀 가드(포트 스캔 또는 import 가드)
## Notes
- 출처: dcy-006 FR-5, OQ-1, OQ-7.
- 본 REQ 의 검증은 transport 가 RabbitMQ 로 대체 가능한 상태(REQ-021/REQ-022/REQ-023 구현)에 의존한다. 동일 batch 또는 직후 batch 에서 함께 deliver 해야 통신 단절 위험(R-5)을 피할 수 있다.
- httpx 는 본 REQ 가 제거 대상에서 제외한다(portfolio-hub ledger 어댑터가 사용).
- 외부 운영 가시성(메트릭/로그) 표준화는 본 REQ 범위 밖이며 후속 운영 트랙으로 추적한다.
## Change Log
### CHG-20260605-01
- Date: 2026-06-05
- Author: Justin Ko
#### Change Summary
- dcy-006 FR-5/OQ-1/OQ-7 로부터 최초 생성(Proposed). HTTP `/v1` API + healthz + adapters/api + API_HOST/PORT env + fastapi/uvicorn 의존 전부 제거 backlog 정규화.
#### Intent
- 이중 transport 병행 없이 HTTP 표면 0 을 달성하고 dcy-002·dcy-005 의 HTTP 가정을 갱신.
#### Acceptance Criteria Delta
- Added:
- HTTP 어댑터 잔존 0, HTTP 리스너 0, env 폐기, 의존성 제거, cross-reference 갱신, 프로세스 감독 liveness (총 6개 기준)
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Docs:
- docs/interface-contract.md, docs/runtime-flows.md, docs/project-structure.md, dcy-002/dcy-005 cross-reference
- Modules:
- adapters/api 제거, runtime/daemon.py, runtime/config.py, pyproject.toml, .env.example
- Tests:
- adapters/api 테스트 제거 또는 이관, daemon HTTP-표면-0 회귀 가드
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: yes (BAT-002 HTTP API 관련 구현 일부가 RabbitMQ 로 대체)
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 REQ-021~023 과 동일 batch 편성(통신 단절 R-5 회피).
#### Validation Plan
- 코드 grep + 포트 스캔 + env 누락 기동 + pyproject 의존성 검사 + cross-reference 리뷰 + 프로세스 감독 시나리오로 검증.
### CHG-20260605-02
- Date: 2026-06-05
- Author: Justin Ko
#### Change Summary
- Status 변경: Proposed -> Approved. confirm-req 승인 게이트 통과.
#### Intent
- HTTP `/v1` API 완전 제거(healthz 포함, HTTP 표면 0)와 fastapi/uvicorn 의존 정리를 delivery input 으로 승인.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: yes (BAT-002 HTTP API 관련 구현 일부 RabbitMQ 로 대체)
- Status Recommendation: Approved
- Follow-up Action: REQ-021/022/023 과 반드시 동일 batch 로 deliver(big-bang 마이그레이션 R-5 회피)
#### Validation Plan
- 기존 Acceptance Criteria 로 batch delivery 에서 검증.
### CHG-20260605-03
- Date: 2026-06-05
- Author: Justin Ko
#### Change Summary
- Status 변경: Approved -> Implemented. BAT-007 release-candidate verification evidence 기반.
#### Intent
- HTTP `/v1` API + healthz + adapters/api + fastapi/uvicorn 의존 + TREX_API_HOST/PORT 폐기를 구현 완료 상태로 동기화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-007 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: yes (BAT-002 HTTP API 관련 구현/테스트 일부 RabbitMQ 로 대체됨; tests/adapters/api/ 제거)
- Status Recommendation: Implemented
- Follow-up Action: release 단계에서 전략 모듈 cut-over 순서 합의.
#### Validation Plan
- AC-1: tests/runtime/test_daemon_no_http_surface.py::test_adapters_api_tree_does_not_exist + test_no_fastapi_or_uvicorn_in_trex_core_source.
- AC-2: tests/runtime/test_daemon_no_http_surface.py::test_daemon_module_has_no_fastapi_or_uvicorn_import.
- AC-3: tests/runtime/test_daemon_no_http_surface.py::test_config_env_no_longer_references_api_host_or_port.
- AC-4: tests/runtime/test_daemon_no_http_surface.py::test_pyproject_dependencies_have_no_fastapi_or_uvicorn.
- AC-5: docs/discovery/dcy-002_…md 헤더 supersede 메모 + dcy-005 cross-reference 보유.
- AC-6: Daemon.run 의 signal handler + 포트 바인딩 0 코드 review.
@@ -1,297 +0,0 @@
# req-028: 종목 스냅샷 read 메시지 계약 + envelope + degraded 신호
- Status: Deprecated
- Deprecated-By: REQ-073, REQ-074 (BAT-035, dcy-025, 2026-06-11)
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 전략 모듈이 dcy-006 snapshot RPC 로 종목 스냅샷을 받는 요청/응답 계약(transport-무관 logical)을 정의한다. 빈 응답과 가용성 degrade 의 시맨틱을 모호하지 않게 한다.
## Requirement
- 스냅샷 read 는 dcy-006 의 `trex.snapshot.req` request-reply RPC 위에서 동작한다. 요청 payload 는 선택적 `strategy_key`·`view` 를 가진다.
- 응답은 **envelope** 다: `assets` 는 항상 배열(비면 `[]`, null 금지)이고, meta 로 `view`(에코), `available_slots`, `degraded`, `reason` 을 포함한다.
- 각 자산 항목은 symbol, asset_id, cash_balance, asset_quantity, active_strategy_id, 전략파라미터(opaque)를 담고 가격은 제외한다.
- (CHG-20260608-01) envelope 은 universe `assets[]` 와 **별도로** read-only `slots[]` 배열을 운반한다 — 데몬 슬롯 테이블의 per-slot 상태(`slot_id`·`status`(idle/holding/pending_buy/pending_sell)·`symbol`·`qty`·`limit_price`·`avg_price`·`portfolio_id`). 슬롯이 없어도 `[]`(null 금지). strategy 소비자는 무시 가능(additive). 운영자 CLI(`trex-core slots`)는 이 `slots[]` 를 표시한다.
- portfolio-hub 가 불가해 권위 cash/position 을 유지할 수 없으면(write `*_after` 갱신 불가 또는 일일 fetch 실패) 응답에 `degraded=true` + machine-readable reason code(예: `portfolio_hub_unavailable`/`snapshot_fetch_failed`/`cash_position_stale`) + sanitize 된 message 를 실어 전략의 신규 매매 보류를 신호한다(빈 리스트/silent stale 금지).
## Acceptance Criteria
1. Given 정상 상태, When 스냅샷을 요청, Then `assets`(배열) + meta(`view`·`available_slots`·`degraded`·`reason`) envelope 를 반환하고, 자산이 없어도 `assets` 는 `[]`(null 아님)다.
2. Given portfolio-hub 불가(권위 cash/position 유지 불가), When 요청, Then `degraded=true` + reason code 가 포함되고 raw 예외/자격증명 등 민감정보는 노출되지 않는다.
3. Given 응답 항목, Then 필드는 symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params(opaque) 이고 가격 필드는 없다.
4. (CHG-20260608-01) Given 스냅샷 요청, Then envelope 에 read-only `slots[]` 배열을 포함한다 — 각 항목은 `slot_id`·`status`·`symbol`·`qty`·`limit_price`·`avg_price`·`portfolio_id` 를 담고, 슬롯이 없어도 `[]`(null 아님)다. `assets[]` 와 독립이며 strategy 소비자는 무시 가능(additive, 하위호환).
5. (CHG-20260610-01, dcy-023/issue #22) Given 스냅샷 응답, Then `slots[]` 항목에 `allocated_capital` 키가 없다 — 구현이 계약 외로 노출하던 죽은 필드를 제거해 AC-4 의 문서화된 필드 집합과 구현을 정렬한다.
## Impacted Area
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md, docs/discovery/dcy-016_20260608_operator-cli-rpc-commands.md, docs/interface-contract.md
- Modules: trex_core/adapters/messaging (snapshot RPC 핸들러), trex_core/application/portfolio.py (`build_snapshot_envelope` — `slots[]`, (CHG-20260610-01) allocated_capital 노출 제거), 응답 스키마(transport-무관), trex_core/runtime/cli.py (REQ-032 companion)
- Tests: envelope 스키마 검증(빈 응답 포함), degraded 주입 테스트, `slots[]` 스키마(빈 배열·status enum) + `trex-core slots` 실제 슬롯 상태 표시
## Notes
- transport 는 dcy-006(REQ-021/022) 의 snapshot RPC 를 사용하며 본 REQ 는 logical 계약만 정의한다.
- NFR-3(가용성 degrade, OQ-5) + OQ-6(빈 표현)을 본 REQ 로 흡수/반영한다.
- 정확한 reason code enum/필드 스키마는 구현 단계에서 확정한다(dcy-005 OQ-5/OQ-6 결정 범위 내).
## Change Log
### CHG-20260606-01
- Date: 2026-06-06
- Author: project maintainers
#### Change Summary
- dcy-005 FR-1/FR-3 + OQ-5/OQ-6 분해로 최초 생성(Proposed). NFR-3 흡수.
#### Intent
- 스냅샷 read 의 요청/응답 envelope 계약 + degrade 신호 정의.
#### Acceptance Criteria Delta
- Added:
- AC-1~3 신규
- Updated:
- none
- Removed:
- none
#### Impacted Area Delta
- Docs:
- dcy-005, interface-contract
- Modules:
- adapters/messaging snapshot RPC 핸들러, 응답 스키마
- Tests:
- envelope 스키마, degraded 주입
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req
#### Validation Plan
- envelope 스키마 검증 + portfolio-hub 불가 주입으로 degraded AC 검증.
### CHG-20260606-02
- Date: 2026-06-06
- Author: project maintainers
#### Change Summary
- 승인 게이트 통과 → Proposed → Approved.
#### Acceptance Criteria Delta
- Added: none
- Updated: none
- Removed: none
#### 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 / draft-batch
#### Validation Plan
- 승인 기록. 구현 전 재검증 불필요.
### CHG-20260606-03
- Date: 2026-06-06
- Author: Justin Ko
#### Change Summary
- Status 변경: Approved → Implemented. BAT-008 release-candidate verification evidence 기반.
#### Intent
- snapshot RPC envelope 응답 + degraded 신호 + sanitization 구현 완료 상태로 동기화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-008 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: release 단계는 별도 진행
#### Validation Plan
- AC-1: tests/application/test_snapshot_handler.py::test_envelope_shape_returned + test_snapshot_selection.py::test_empty_envelope_assets_is_list_not_null.
- AC-2: tests/application/test_snapshot_handler.py::test_degraded_signal_does_not_leak_credentials + 실 daemon 운영 검증.
- AC-3: tests/application/test_snapshot_selection.py::test_envelope_shape_no_price_field.
### CHG-20260608-01
- Date: 2026-06-08
- Author: project maintainers
#### Change Summary
- dcy-016 후속 정정. `trex-core slots`(REQ-032)가 universe `assets`(portfolio: asset_id/symbol/asset_quantity)를 **슬롯 상태로 오인 표시**하던 갭 — snapshot envelope 이 슬롯 상태 목록을 운반하지 않아 발생(운영자 관측: 10개 슬롯인데 universe portfolio 1개만, status 없음). envelope 에 **read-only per-slot 상태 목록 `slots[]` 를 additive 로 추가**한다(dcy-017 의 per-slot `watchdog` 동봉 선례와 동일 방식). BAT-007 에서 HTTP 슬롯 read(REQ-008/025) 제거 후 슬롯 상태 read 표면이 부재했던 점을 함께 해소.
#### Intent
- 운영자가 데몬의 **실제 슬롯 상태(idle/holding/pending_buy/pending_sell)** 를 snapshot RPC 로 관측할 수 있게 한다. strategy-facing `assets[]`(universe) 계약은 그대로 유지하고, 슬롯 상태는 별도 `slots[]` 로 분리 노출한다.
#### Acceptance Criteria Delta
- Added:
- AC-4: Given 스냅샷 요청, Then envelope 에 read-only `slots[]` 배열을 포함한다 — 각 항목은 `slot_id`·`status`·`symbol`·`qty`·`limit_price`·`avg_price`·`portfolio_id` 를 담고, 슬롯이 없어도 `[]`(null 아님)다. `assets[]`(universe) 와 독립이며 strategy 소비자는 무시 가능(additive, 하위호환).
- Updated:
- none (AC-1~3 의 `assets[]`/degraded/no-price 계약 불변)
- Removed:
- none
#### Impacted Area Delta
- Docs:
- docs/interface-contract.md(snapshot 응답에 `slots[]` 필드 추가), dcy-005/dcy-016
- Modules:
- trex_core/application/portfolio.py(`build_snapshot_envelope` 에 `slots[]`), trex_core/application/messaging_handlers.py(envelope), trex_core/runtime/cli.py(REQ-032 companion — `slots` 가 `slots[]` 를 읽도록, `universe` 는 `assets[]` 유지)
- Tests:
- envelope `slots[]` 스키마(빈 배열 포함), `trex-core slots` 가 universe 가 아닌 실제 슬롯 상태(status 포함)를 표시
#### Delivery Trace Delta
- Batches:
- BAT-008 (REQ-028 최초 구현), BAT-020 (dcy-016 — `slots` CLI 가 갭 노출). 정정 구현은 신규 BAT-022 (예정).
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: yes (신규 AC-4)
- Existing Implementation Invalidated: no (AC-1~3 assets/degraded/no-price 근거 유지)
- Status Recommendation: Implemented → Approved (신규 AC-4 미구현)
- Follow-up Action: REQ-032 companion change-req + draft-batch(BAT-022) → 구현/검증
#### Validation Plan
- AC-4: envelope `slots[]` 스키마 테스트(빈 배열·status enum 포함) + `trex-core slots` 통합 검증(universe 가 아닌 실제 슬롯 상태 N개를 status 와 함께 표시).
### CHG-20260608-02
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- Status 변경: Approved → Implemented. BAT-022 release-candidate verification evidence 기반(AC-4 envelope `slots[]`).
#### Intent
- envelope `slots[]`(operator-facing per-slot 상태) 구현 완료 상태로 동기화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-022 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no (BAT-022 에서 완료)
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: release 단계 별도 진행
#### Validation Plan
- AC-4: tests/application/test_snapshot_selection.py::test_envelope_shape_no_price_field + test_snapshot_handler.py::test_envelope_shape_returned(envelope `slots` list). 운영 재현: 신규 코드 데몬 + 실 PostgreSQL/RabbitMQ 에서 `trex-core slots` → slots=10·status 표시·DB `(2026-06-08,idle,10)` 일치(BAT-022 verification). pytest 인프라 게이트는 Human Approval Memo 수용 잔여.
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-023/issue #22) snapshot envelope `slots[]` 에서 `allocated_capital` 노출 제거 — `build_snapshot_envelope`(trex_core/application/portfolio.py) 가 계약(AC-4 필드 집합) 외로 노출하던 죽은 필드를 삭제해 문서화된 계약과 구현을 정렬. AC-5 추가, Implemented→Approved(재구현 대기).
#### Intent
- Slot 도메인에서 allocated_capital 이 제거(REQ-002 CHG-20260610-02)됨에 따라 read 표면에서도 동일 필드를 제거. strategy/operator 소비자가 죽은 필드를 참조할 여지 차단.
#### Acceptance Criteria Delta
- Added:
- AC-5: slots[] 항목에 allocated_capital 키 부재.
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Modules: trex_core/application/portfolio.py(build_snapshot_envelope slots[] 매핑)
- Tests: snapshot envelope slots[] 스키마 테스트에서 allocated_capital 부재 확인 + 기존 fixture 정리
#### Delivery Trace Delta
- Batches: (예정) dcy-023 batch
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (dcy-023 batch 에서 수행)
- Existing Implementation Invalidated: yes (slots[] 노출 필드 변경)
- Status Recommendation: Approved (Implemented→Approved 되돌림)
- Follow-up Action: dcy-023 batch 구현·검증 후 confirm-req-implemented. CLI slots detail 표시 제거는 REQ-032 CHG-20260610-07 이 소유.
#### Validation Plan
- dcy-023 batch: envelope slots[] 스키마 테스트(allocated_capital 부재) + 전체 suite green.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-034(release-candidate) verification — allocated_capital 전 경로 제거(도메인/intent/영속/snapshot/CLI), 마이그레이션 013 테스트 DSN 멱등 round-trip + 컬럼 부재 확인, 전체 428 passed + PG 게이트 21 passed + ruff clean, grep 전수 0건. Blocking Issues 없음.
### CHG-20260611-01
- Date: 2026-06-11
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-025) 본 REQ 가 소유한 snapshot read 계약(`trex.snapshot.req` 요청 view/strategy_key, 응답 envelope `assets[]`/`available_slots`/`watchdog[]`/degraded)이 **폐기 예정** — `trex.slots.req`(REQ-073) + 슬롯 단일 행 스키마(REQ-074)로 대체된다(즉시 교체, dcy-025 OQ-1). degraded/reason/message health 신호 의미는 REQ-073 으로 승계. 현재 코드는 불변이므로 Implemented 유지(keep-current, REQ-005 CHG-20260610-01 선례), dcy-025 delivery 배치에서 표면 제거와 함께 **Deprecated** 전환.
#### Intent
- snapshot→slots 표면 교체의 추적성 forward-link.
#### Acceptance Criteria Delta
- Updated: 없음(dcy-025 delivery 배치에서 본 REQ 의 envelope AC 폐기)
#### Impacted Area Delta
- Docs: dcy-025, REQ-073/074/075
- Modules: (예정) messaging_handlers.py snapshot 핸들러·portfolio.py envelope 빌더 제거/대체
#### Delivery Trace Delta
- Batches: (예정) dcy-025 delivery 배치
- Releases: none
#### Revalidation Impact
- Reverification Needed: no (현 시점 — 코드 불변)
- Existing Implementation Invalidated: no (배치 구현 시점에 무효화·Deprecated 전환)
- Status Recommendation: keep-current
- Follow-up Action: dcy-025 배치에서 표면 제거 + 본 REQ Deprecated 전환.
#### Validation Plan
- dcy-025 배치 verification 으로 대체(snapshot 표면 부재 + slots 표면 계약 검증).
@@ -1,215 +0,0 @@
# req-029: 자산 선별(slot overlay) + view 모드 + strategy_key 필터
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 스냅샷 응답에 담을 자산 집합을 core 의 권위 슬롯 상태로 선별한다. 보유(holding)는 포함하되 일시·불안전 상태는 마스킹하고, 전략 타입별 view 와 전략별 필터를 제공한다.
## Requirement
- 응답 base 집합은 요청 `view`(`all` 기본 | `buyable` | `held`)로 선택한다: `all` = universe 전체(portfolio-hub 보유 + holding 슬롯), `buyable` = universe − 슬롯 점유, `held` = holding 슬롯 자산만.
- 마스킹(pending·warning·pause)은 전 모드에 균일 적용한다. pending 은 모든 모드에서 마스킹되므로 `held` 는 holding 만 포함한다. 포함/마스킹 판정은 core 권위 슬롯 상태 + 정합 결과 + pause 상태를 portfolio-hub 보유 여부보다 우선한다(slot overlay, 불변식 A).
- 선택적 `strategy_key`(요청 시) 는 자산의 단일 `active_strategy_id` 와 대소문자 구분 정확 일치로 직교 필터링한다. `strategy_key` 는 사람이 읽는 안정 유일 slug(예: `target-value-v1`)다.
- 최종 합성: `assets = base(view) − mask(pending·warning·pause) − (strategy_key 필터, 주어진 경우)`. `buyable` 은 `available_slots=0` 이면 `[]` 다.
## Acceptance Criteria
1. Given 같은 종목이 holding 슬롯·pending 슬롯에 각각 있을 때, When `view=all`, Then holding 자산은 포함되고 pending 자산은 마스킹된다.
2. Given `available_slots=0`, When `view=buyable`, Then `[]` 를 반환한다.
3. Given `view=held`, Then holding 슬롯 자산만 반환하고 pending 은 제외한다.
4. Given `strategy_key` 제공, Then `active_strategy_id` 가 일치하는 자산만 반환하고, 생략 시 (마스킹 후) 전체 자산을 반환한다.
5. Given warning 또는 pause 자산, When 임의 `view`, Then 해당 자산은 마스킹된다.
## Impacted Area
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md
- Modules: trex_core/application 스냅샷 선별/slot overlay 로직(slot repository 재사용), strategy_key 필터
- Tests: view 모드별·마스킹·strategy_key 필터 합성 테스트
## Notes
- core 권위 슬롯 상태(불변식 A)가 portfolio-hub 보유 여부보다 우선한다.
- OQ-4(in-flight 합성)·OQ-9(strategy_key)·OQ-11/OQ-12(view 모드) 반영.
- holding 자산의 보유 수량 표기를 core 슬롯 vs 스냅샷 중 무엇 기준으로 할지(holding→ledger flush 갭)는 설계 시 확정(dcy-005 OQ-4 잔여).
- (orb-v1 소비 참고, CHG-04) 첫 전략 orb-v1 은 `strategy_key` 없이 `view=buyable` 로 조회한다. 즉 전략 설정과 무관하게 universe 전체를 대상으로 하고, slot 점유(holding·pending)·warning(정합 불일치)·pause(사용자) 만 제외하면 된다 — 이는 `view=buyable` + `strategy_key` 생략의 기존 동작과 정확히 일치한다. pending(in-flight) 제외는 중복 주문 방지, warning 제외는 틀린 baseline 매매 차단(REQ-031) 목적으로 orb-v1 의도에 부합한다(사용자 확인). 따라서 단일 전략 단계에서는 `/v1/portfolios` PortfolioItem 의 전략 필드(active_strategy_id/strategy_params) 부재가 orb-v1 동작에 무해하다. (2번째 전략부터는 strategy_key 라우팅이 필요해져 전략 필드 부재 해소가 재대두된다.)
## Change Log
### CHG-20260606-01
- Date: 2026-06-06
- Author: project maintainers
#### Change Summary
- dcy-005 FR-2/FR-8 + OQ-4/9/11/12 분해로 최초 생성(Proposed).
#### Intent
- 응답 자산 선별(slot overlay·view·strategy_key) 규칙 정의.
#### Acceptance Criteria Delta
- Added:
- AC-1~5 신규
- Updated:
- none
- Removed:
- none
#### Impacted Area Delta
- Docs:
- dcy-005
- Modules:
- 스냅샷 선별/slot overlay, strategy_key 필터
- Tests:
- view/마스킹/필터 테스트
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req
#### Validation Plan
- 슬롯 상태 주입 후 view/마스킹/strategy_key 합성 테스트로 AC 검증.
### CHG-20260606-02
- Date: 2026-06-06
- Author: project maintainers
#### Change Summary
- 승인 게이트 통과 → Proposed → Approved.
#### Acceptance Criteria Delta
- Added: none
- Updated: none
- Removed: none
#### 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 / draft-batch
#### Validation Plan
- 승인 기록. 구현 전 재검증 불필요.
### CHG-20260606-03
- Date: 2026-06-06
- Author: Justin Ko
#### Change Summary
- Status 변경: Approved → Implemented. BAT-008 release-candidate verification evidence 기반.
#### Intent
- `build_snapshot_envelope` 의 base(view) 산출 + masking OR 합성 + strategy_key 직교 필터 구현 완료 상태로 동기화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-008 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: release 단계는 별도 진행
#### Validation Plan
- AC-1: tests/application/test_snapshot_selection.py::test_view_all_includes_holding_excludes_pending_for_same_symbol.
- AC-2: ::test_view_buyable_with_zero_available_slots_returns_empty.
- AC-3: ::test_view_held_returns_only_holding_slot_assets.
- AC-4: ::test_strategy_key_orthogonal_filter + ::test_strategy_key_missing_includes_everything_unmasked.
- AC-5: ::test_warning_overlay_masks_asset_uniformly_across_views + ::test_pause_overlay_masks_asset.
### CHG-20260606-04
- Date: 2026-06-06
- Author: Justin Ko
#### Change Summary
- 첫 전략 orb-v1 의 스냅샷 소비 패턴을 Notes 참고 사항으로 추가(본문 비변경). AC/요구사항/계약 변경 없음.
#### Intent
- orb-v1 은 전략 설정(active_strategy_id/strategy_params)과 무관하게 모든 자산을 대상으로 하며 `strategy_key` 없이 `view=buyable` 로 조회한다는 소비 계약을 명시해, `/v1/portfolios` PortfolioItem 의 전략 필드 부재가 orb-v1 에 무해함을 기록한다.
#### Acceptance Criteria Delta
- Added: none
- Updated: none
- Removed: none
#### Impacted Area Delta
- Docs:
- 본 REQ Notes 에 orb-v1 소비 참고 사항 1건 추가
- Modules: 없음
- Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-008 (release-candidate) — 영향 없음(기존 구현/검증 그대로 유효)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented 유지)
- Follow-up Action: orb-v1 Discovery 착수 시 본 참고 사항을 입력으로 사용. 2번째 전략 도입 시 strategy_key/strategy_params 필요 → PortfolioItem 전략 필드 부재 해소(detail strategy_set 보강 또는 별도 change-req) 재검토.
#### Validation Plan
- 문서 전용 변경. 기존 AC-1~5 테스트 그대로 유효하며 재실행 불필요.
### CHG-20260608-01
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-018) 수량/현금 source 정합: 슬롯 오버레이(REQ-029)는 **유지**(lifecycle 중 슬롯 = 코어 권위 즉시값, 불변식 A). 스냅샷 응답에 미정산 ledger 가 있는 자산은 `cash_balance += pending delta` + `cash_estimated:true` 라벨로 **추정 현금 오버레이**(OQ-4 (i))를 노출하고, option D write-back 도착 시 권위값 수렴. BAT-023 재구현·재검증 완료 → Implemented 유지.
#### Intent
- "수량 live·현금 stale" 비대칭 제거 — 수량은 슬롯 오버레이(정확), 현금은 추정 오버레이(라벨)로 즉시성 확보 후 권위값 수렴.
#### Acceptance Criteria Delta
- Added:
- 스냅샷 자산에 추정 현금 오버레이(`cash_estimated` 플래그) — 미정산 outbox delta 기반. 슬롯 오버레이는 그대로 유지(변경 없음).
#### Impacted Area Delta
- Modules: `trex_core/application/messaging_handlers.py`(`_apply_cash_estimate`)
- Docs: `docs/interface-contract.md`(envelope `cash_estimated`)
- Tests: tests/application/test_ledger_option_d.py(estimate overlay)
#### Delivery Trace Delta
- Batches: BAT-023
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-023 에서 완료)
- Existing Implementation Invalidated: no (오버레이 유지 + 추정 additive)
- Status Recommendation: Implemented (change-req → BAT-023 재검증)
- Follow-up Action: confirm-req-implemented(BAT-023).
#### Validation Plan
- BAT-023: 미정산 자산 cash_estimated + 추정 cash 단위, write-back 후 수렴.
@@ -1,464 +0,0 @@
# req-032: 런타임 pause/resume 제어
- Status: Implemented
- Type: Interface
- Priority: Medium
- Owner: project maintainers
## Intent
- 운영자가 특정 자산을 런타임에 매매에서 제외(pause)하거나 다시 포함(resume)할 수 있게 한다. 프로그램 이상·이벤트 시 안전 통제를 위한 수동 overlay 다.
## Requirement
- pause/resume 단위는 `portfolio_id`(= asset_id)다.
- 제어는 **CLI** 와 **dcy-006 RPC 제어 메시지** 둘 다로 가능하며, 둘은 동일한 pause 상태를 변경한다. config 리로드 방식은 채택하지 않는다.
- pause 상태는 **Postgres 에 영속**(portfolio_id 키)하며 daemon 재시작 후에도, 일일 스냅샷 refresh 후에도 유지된다(refresh 는 universe/포지션만 갱신, pause overlay 불변).
- 적용 범위는 **전역** — pause 된 자산은 모든 view/전략 요청에서 마스킹된다.
- pause 는 request-time mask 이므로 resume 시 다음 요청부터 즉시 응답에 복귀한다.
- (CHG-20260609-01, issue #17) 운영자 CLI `enter` 는 시간 기반 자동청산을 위해 **`--forced-close-at <ISO8601>` (절대시간)** 옵션을 제공한다. CLI 는 이를 buy intent payload 의 기존 `forced_close_at` 필드에 매핑하며, 도메인·forced-close 루프(REQ-037)는 불변이다. 상대시간 옵션은 채택하지 않는다.
## Acceptance Criteria
1. Given 운영자가 `portfolio_id` 를 pause, When 임의 `view`/`strategy_key` 로 스냅샷을 요청, Then 그 자산은 응답에서 마스킹된다.
2. Given pause 상태에서 daemon 재시작 또는 일일 refresh 발생, When 이후 요청, Then pause 가 유지된다.
3. Given 운영자가 resume, When 다음 요청, Then 그 자산이 응답에 다시 포함된다.
4. Given CLI 로 pause 후 RPC 제어로 조회(또는 그 반대), Then 동일한 pause 상태가 보인다.
5. (CHG-20260609-01) Given 운영자가 `trex-core enter <portfolio_id> ... --forced-close-at <ISO8601>`, When buy intent 가 제출·admit, Then payload 에 파싱된 `forced_close_at` 절대시각이 실리고 admitted 슬롯의 `forced_close_at` 이 그 값으로 설정된다.
6. (CHG-20260609-01) Given `--forced-close-at` 미지정, Then payload 에 `forced_close_at` 을 포함하지 않고 기존 enter 동작이 불변이다. Given 잘못된 timestamp 형식, Then 제출 전 검증 오류로 거부된다.
7. (CHG-20260610-06, issue #23) Given 운영자가 `trex-core enter <portfolio_id>` 에 `--qty` 를 지정하지 않으면, Then CLI 가 intent 제출 전에 즉시 오류를 반환하고 RPC 는 호출되지 않는다.
8. (CHG-20260610-07, dcy-023/issue #22) Given 운영자 CLI, Then `enter` 는 `--capital` 옵션을 받지 않고(지정 시 argparse unknown argument 거부), buy intent payload 에 `allocated_capital` 을 싣지 않으며, `slots` detail 표시에서 `allocated_capital` 행이 제거된다.
## Impacted Area
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md
- Modules: pause 상태 store(Postgres), CLI 제어, dcy-006 RPC 제어 메시지 핸들러, 응답 산출 시 pause 마스킹, (CHG-20260609-01) `trex_core/runtime/cli.py` `_cmd_enter` `--forced-close-at` 옵션 → buy intent `forced_close_at` 매핑, (CHG-20260610-06) `trex_core/runtime/cli.py` `_cmd_enter` `--qty` 미지정 시 제출 전 오류 처리, (CHG-20260610-07) `trex_core/runtime/cli.py` `--capital` argparse 제거 + payload `allocated_capital` 제거 + `_print_slot_detail` 행 제거
- Tests: pause→호출→resume→호출 시퀀스, 재시작/refresh 후 영속, (CHG-20260609-01) enter `--forced-close-at` payload 매핑·형식 검증, (CHG-20260610-06) enter `--qty` 누락 오류 + RPC 미호출, (CHG-20260610-07) `--capital` argparse 거부 + payload allocated_capital 부재
## Notes
- pause(수동·영속) vs warning(자동·일시, REQ-031)은 독립 overlay 이며 OR 합성(둘 중 하나라도면 마스킹).
- OQ-10 반영.
## Change Log
### CHG-20260606-01
- Date: 2026-06-06
- Author: project maintainers
#### Change Summary
- dcy-005 FR-9 + OQ-10 분해로 최초 생성(Proposed).
#### Intent
- 런타임 pause/resume 제어(단위·제어 표면·영속·범위) 정의.
#### Acceptance Criteria Delta
- Added:
- AC-1~4 신규
- Updated:
- none
- Removed:
- none
#### Impacted Area Delta
- Docs:
- dcy-005
- Modules:
- pause store, CLI, RPC 제어, 마스킹
- Tests:
- pause/resume 시퀀스, 영속
#### Delivery Trace Delta
- Batches:
- none
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req
#### Validation Plan
- pause→호출→resume→호출 + 재시작 영속 테스트로 AC 검증.
### CHG-20260606-02
- Date: 2026-06-06
- Author: project maintainers
#### Change Summary
- 승인 게이트 통과 → Proposed → Approved.
#### Acceptance Criteria Delta
- Added: none
- Updated: none
- Removed: none
#### 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 / draft-batch
#### Validation Plan
- 승인 기록. 구현 전 재검증 불필요.
### CHG-20260606-03
- Date: 2026-06-06
- Author: Justin Ko
#### Change Summary
- Status 변경: Approved → Implemented. BAT-008 release-candidate verification evidence 기반.
#### Intent
- pause/resume CLI + RPC 제어 + Postgres 영속 구현 완료 상태로 동기화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-008 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: release 단계는 별도 진행
#### Validation Plan
- AC-1: tests/application/test_pause_handler.py::test_pause_then_list + test_snapshot_selection.py::test_pause_overlay_masks_asset.
- AC-2: tests/adapters/portfolio/test_postgresql_pause_store.py::test_durability_simulated_via_fresh_store_instance.
- AC-3: tests/application/test_pause_handler.py::test_resume_clears_pause.
- AC-4: tests/application/test_pause_handler.py::test_cli_pause_visible_to_rpc_list_via_shared_store + 실 daemon RPC 운영 검증.
### CHG-20260608-01
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-016) 운영자 CLI 확장: `universe`/`slots`/`enter`/`exit` 서브커맨드 추가(전부 데몬 RabbitMQ RPC). 인스턴스 라우팅(`--config` canonical/`--instance` 단축/default), enter/exit 안전장치(확인 프롬프트 기본 ON + `--yes`(paper)/`--yes --live`(live 이중 ack)/`--dry-run`), 전 명령 `--json`. pause/resume/paused 는 기존 direct-DB 유지(OQ-3). BAT-020 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 운영자가 조회·매수(enter)·매도(exit)·일시정지를 CLI 로 수행하되, 매매는 데몬 admission(단일 writer)을 거쳐 불변식·portfolio_id 검증을 보존(DB 직접 쓰기 없음, NFR-1).
#### Acceptance Criteria Delta
- Added:
- universe/slots(snapshot RPC)·enter(buy intent RPC)·exit(sell intent RPC) CLI + 인스턴스 라우팅 + enter/exit 안전장치 + `--json`.
#### Impacted Area Delta
- Modules: `trex_core/runtime/cli.py`(서브커맨드/가드/라우팅/RPC 클라이언트)
- Docs: `docs/interface-contract.md`, `docs/runtime-flows.md`
- Tests: tests/runtime/test_cli_operator.py
#### Delivery Trace Delta
- Batches: BAT-020
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-020 에서 완료)
- Existing Implementation Invalidated: no (pause/resume 불변, 명령 추가)
- Status Recommendation: Implemented (change-req → BAT-020 재검증)
- Follow-up Action: confirm-req-implemented(BAT-020).
#### Validation Plan
- BAT-020: CLI universe/slots/enter/exit RPC payload·안전장치·라우팅·--json 단위.
### CHG-20260608-02
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-017) `trex-core slots` 가 snapshot 응답의 `watchdog` 필드를 읽어 `expired=true` 슬롯을 **WATCHDOG-OWNED(전략 이탈)** 로 표시(+`watchdog_owned` 카운트). dcy-016 `slots` 확장. BAT-021 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 운영자가 CLI 로 워치독 소유(전략 이탈) 슬롯을 즉시 인지.
#### Acceptance Criteria Delta
- Updated:
- `slots` 출력에 워치독 소유 표시(snapshot watchdog 필드 기반).
#### Impacted Area Delta
- Modules: `trex_core/runtime/cli.py`(_cmd_slots watchdog 표시)
- Tests: tests/runtime/test_cli_operator.py::test_slots_marks_watchdog_owned
#### Delivery Trace Delta
- Batches: BAT-021
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-021 에서 완료)
- Existing Implementation Invalidated: no (표시 추가)
- Status Recommendation: Implemented (change-req → BAT-021 재검증)
- Follow-up Action: confirm-req-implemented(BAT-021).
#### Validation Plan
- BAT-021: slots watchdog-owned 표시 단위.
### CHG-20260608-03
- Date: 2026-06-08
- Author: project maintainers
#### Change Summary
- (change-req, dcy-016 후속) `trex-core slots` 가 universe `assets[]`(portfolio: asset_id/symbol/asset_quantity)를 **슬롯 상태로 오인 표시**하던 갭 정정(운영 관측: 10개 슬롯인데 universe 1개·status 없음). snapshot envelope 의 신규 read-only `slots[]`(REQ-028 CHG-20260608-01, AC-4)를 읽어 **실제 슬롯 상태(`slot_id`·`status`(idle/holding/pending_buy/pending_sell)·`symbol`·`qty`·`limit_price`·`avg_price`)** 를 표시한다. `universe` 명령은 `assets[]`(universe) 유지로 둘을 명확히 분리. watchdog-owned 표시(CHG-20260608-02)는 `slots[]` 항목과 결합.
#### Intent
- 운영자가 `trex-core slots` 로 데몬의 실제 슬롯 상태(idle/holding/pending_*)를 관측하게 한다. `universe`(거래 대상 portfolio)와 `slots`(데몬 슬롯 할당 상태)를 표면상 명확히 구분.
#### Acceptance Criteria Delta
- Updated:
- `slots` 출력은 universe `assets[]` 가 아니라 envelope `slots[]`(슬롯 상태, `status` 포함)를 표시한다. `--status held/holding/...` 필터는 슬롯 상태 기준으로 적용된다.
- Added: none
- Removed: none
#### Impacted Area Delta
- Modules: `trex_core/runtime/cli.py`(`_cmd_slots` → `resp["slots"]` 읽기). 전제: REQ-028 envelope `slots[]`(CHG-20260608-01).
- Tests: `slots` 가 universe 가 아닌 실제 슬롯 상태(status 포함)를 표시, universe 와 구분.
#### Delivery Trace Delta
- Batches: BAT-020 (`slots` 최초 구현 — 갭 발생). 정정은 신규 BAT-022 (REQ-028 AC-4 와 함께).
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes
- Existing Implementation Invalidated: yes (`slots` 가 universe assets 를 표시하던 부분이 슬롯 상태 의도와 불일치)
- Status Recommendation: Implemented → Approved (REQ-028 `slots[]` 의존, BAT-022 재구현/재검증)
- Follow-up Action: REQ-028 AC-4 구현 후 draft-batch(BAT-022) → 구현/검증
#### Validation Plan
- BAT-022: `trex-core slots` 가 envelope `slots[]` 의 실제 슬롯 상태(status enum 포함)를 표시하고 universe(`assets[]`)와 구분됨을 단위/통합 검증.
### CHG-20260608-04
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- Status 변경: Approved → Implemented. BAT-022 release-candidate verification evidence 기반(`slots` 가 envelope `slots[]` 표시, CHG-20260608-03).
#### Intent
- `trex-core slots` 가 실제 슬롯 상태(status)를 표시하는 정정 구현 완료 동기화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-022 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no (BAT-022 에서 완료)
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: release 단계 별도 진행
#### Validation Plan
- tests/runtime/test_cli_operator.py::test_slots_shows_real_slot_state_not_universe / ::test_slots_status_filters_by_slot_status / ::test_slots_marks_watchdog_owned. 운영 재현(BAT-022): 신규 코드 데몬 + 실 인프라 `trex-core slots` → slots=10 status·`--status holding`=0·universe(assets=1) 분리·비침습. pytest 인프라 게이트는 Human Approval Memo 수용 잔여.
### CHG-20260609-01
- Date: 2026-06-09
- Author: Justin Ko
#### Change Summary
- (change-req, issue #17) `trex-core enter` 에 **`--forced-close-at <ISO8601>` (절대시간) 옵션** 추가. 운영자가 매수 진입 명령 하나로 시간 기반 자동청산(forced_close) 시각을 지정. CLI 는 이 값을 buy intent payload 의 **기존** `forced_close_at` 필드에 매핑한다(계약: REQ-007/021 buy intent body 가 이미 `forced_close_at` optional 수용, 도메인 `Slot.forced_close_at`(REQ-066), forced-close 만기 매도 루프 REQ-037 — 전부 구현·불변). 상대시간(`--hold-minutes`)은 **미채택**(사용자 결정: 절대시간만).
#### Intent
- 운영자가 진입 명령 하나로 시간 기반 매매 계획(자동청산 시각 포함)을 표현하게 한다. 현재는 `--stop-loss`/`--take-profit` 만 노출돼 시간 기반 청산은 별도 수동/스케줄 `exit` 가 필요했다(issue #17 갭). 도메인 능력은 이미 존재하고 CLI 노출만 보완.
#### Acceptance Criteria Delta
- Added:
- AC-5: `trex-core enter <portfolio_id> ... --forced-close-at <ISO8601 timestamp>` 가 주어지면 CLI 는 buy intent payload 에 `forced_close_at`(파싱된 절대시각)을 실어 제출하고, admitted 슬롯의 `forced_close_at` 이 그 값으로 설정된다.
- AC-6: `--forced-close-at` 미지정 시 payload 에 `forced_close_at` 을 포함하지 않으며 기존 enter 동작은 불변(하위호환). 잘못된 timestamp 형식은 제출 **전** 검증 오류로 거부한다.
- Updated: none
- Removed: none
#### Impacted Area Delta
- Modules: `trex_core/runtime/cli.py`(`_cmd_enter` payload 에 `forced_close_at` 추가 + `--forced-close-at` 인자/파싱·검증). buy intent 핸들러·도메인·forced-close 루프는 불변(이미 수용).
- Docs: `docs/interface-contract.md`(enter 옵션 표 + buy intent payload `forced_close_at` 노출), 필요 시 `docs/runtime-flows.md`.
- Tests: `tests/runtime/test_cli_operator.py`(enter `--forced-close-at` → payload `forced_close_at` 매핑 + 잘못된 형식 거부).
#### Delivery Trace Delta
- Batches: 신규 batch-lite(차기 BAT) — enter `--forced-close-at` 노출.
- Releases: none (차기 release 또는 통합 편입).
#### Revalidation Impact
- Reverification Needed: yes (신규 batch 에서 AC-5/6 검증)
- Existing Implementation Invalidated: no (pause/resume/universe/slots/enter/exit 기존 AC 불변, 옵션 additive)
- Status Recommendation: Implemented → Approved (신규 AC-5/6 미구현 — batch 재검증 후 Implemented 복귀; 기존 AC-1~4 및 CLI 명령은 구현 유지)
- Follow-up Action: draft-batch(batch-lite) → run-batch-implementation → verification → confirm-req-implemented
#### Validation Plan
- 신규 BAT: `enter --forced-close-at <ts>` → buy intent payload 에 `forced_close_at` 정확 매핑 단위, 잘못된 형식(예 `--forced-close-at notatime`) 제출 전 거부 단위, 미지정 시 payload 미포함(회귀). (가능 시) 실 데몬 e2e: `enter --forced-close-at <근접시각>` → admitted 슬롯 `forced_close_at` 설정 → forced-close 루프(REQ-037) 만기 매도 확인.
### CHG-20260609-02
- Date: 2026-06-09
- Author: Justin Ko
#### Change Summary
- Status 변경: Approved → Implemented. BAT-024 release-candidate verification evidence 기반(CHG-20260609-01 AC-5/6).
#### Intent
- 운영자 `enter --forced-close-at`(절대시간) → buy intent `forced_close_at` 매핑 구현 완료 동기화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Impacted Area Delta
- Docs/Modules/Tests: 없음
#### Delivery Trace Delta
- Batches:
- BAT-024 (release-candidate)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no (BAT-024 에서 완료)
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: release 단계 별도 진행(차기 REL 또는 통합 편입)
#### Validation Plan
- tests/runtime/test_cli_operator.py::test_enter_with_forced_close_at_maps_to_payload (AC-5) / ::test_enter_without_forced_close_at_omits_field (AC-6 하위호환) / ::test_enter_rejects_malformed_forced_close_at_before_submit (AC-6 형식 거부). 전체 단위 353 passed, ruff clean.
### CHG-20260610-06
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, issue #23) `trex-core enter`에 **`--qty` 미지정 시 제출 전 즉시 오류 반환** 추가. 현재 `--qty` 생략 → `qty=None` → admitted 응답 → 집행 루프 KIS 거절 → `pending_buy→inactive` 자동 롤백으로 "접수 성공처럼 보이지만 실제 매수 안 됨" 혼동 발생. CLI 단에서 admission 전에 차단.
#### Intent
- 운영자가 수량 없이 `enter`를 실행하면 RPC 제출 이전에 즉시 오류를 보고 혼동 없이 재시도할 수 있도록 한다.
#### Acceptance Criteria Delta
- Added:
- AC-7: `trex-core enter <portfolio_id>` 에 `--qty` 를 지정하지 않으면 CLI 가 intent 제출 전에 즉시 오류를 반환하고 RPC 는 호출되지 않는다.
- Updated: none
- Removed: none
#### Impacted Area Delta
- Modules: `trex_core/runtime/cli.py`(`_cmd_enter` 또는 argparse에 `--qty` 검증 추가)
- Tests: `tests/runtime/test_cli_operator.py`(enter `--qty` 누락 오류 + RPC 미호출 검증)
#### Delivery Trace Delta
- Batches: 신규 batch-lite(차기 BAT) — enter `--qty` 필수 검증
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (신규 batch-lite 에서 AC-7 검증)
- Existing Implementation Invalidated: no (AC-1~6 기존 동작 불변, additive 검증 추가)
- Status Recommendation: Implemented → Approved (AC-7 미구현; 기존 AC-1~6 구현은 유효)
- Follow-up Action: draft-batch(batch-lite) → run-batch-implementation → verify → confirm-req-implemented
#### Validation Plan
- 신규 batch-lite: `enter` 에 `--qty` 없이 실행 → rc=1 + RPC calls=0 단위. `--qty 10`과 함께 실행 → 정상 submit 불변(회귀) 단위.
### CHG-20260610-07
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-023/issue #22) 운영자 CLI 에서 `--capital` 옵션 제거 — `enter` argparse 인자 삭제(지정 시 unknown argument 거부), `_cmd_enter` summary·payload 의 `allocated_capital` 제거, `slots` detail(`_print_slot_detail`)의 `allocated_capital` 행 제거. AC-8 추가, Implemented→Approved(재구현 대기).
#### Intent
- `--capital` 이 사이징한다는 오해를 CLI 표면에서 원천 제거. 실제 수량은 `--qty`(AC-7 필수)만이 결정하며, capital 은 어떤 경로에서도 소비되지 않음(dcy-023 §3 전수 추적).
#### Acceptance Criteria Delta
- Added:
- AC-8: `--capital` argparse 거부 + payload allocated_capital 부재 + slots detail 행 제거.
- Updated:
- 없음
- Removed:
- 없음
#### Impacted Area Delta
- Modules: trex_core/runtime/cli.py(`--capital` 인자, `_cmd_enter` summary/payload, `_print_slot_detail`)
- Tests: tests/runtime/test_cli_operator.py — 기존 enter 테스트의 `--capital` 인자 제거 + argparse 거부 테스트 추가
#### Delivery Trace Delta
- Batches: (예정) dcy-023 batch. BAT-033(AC-7, release-candidate)의 enter 테스트와 같은 파일을 수정하므로 dcy-023 batch 에서 정합 유지.
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (dcy-023 batch 에서 수행)
- Existing Implementation Invalidated: yes (enter 인터페이스 변경 — 기존 --capital 사용 테스트/스크립트 무효)
- Status Recommendation: Approved (Implemented→Approved 되돌림)
- Follow-up Action: dcy-023 batch 구현·검증 후 confirm-req-implemented. AC-1~7 의 기존 evidence 는 유지되나 enter 표면 변경분 재검증 필요.
#### Validation Plan
- dcy-023 batch: `enter --capital` argparse 거부(단위) + enter payload allocated_capital 부재 + slots detail 표시 + 전체 suite green.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-034(release-candidate) verification — allocated_capital 전 경로 제거(도메인/intent/영속/snapshot/CLI), 마이그레이션 013 테스트 DSN 멱등 round-trip + 컬럼 부재 확인, 전체 428 passed + PG 게이트 21 passed + ruff clean, grep 전수 0건. Blocking Issues 없음.
@@ -1,236 +0,0 @@
# req-034: per-slot 워치독 — snapshot RPC 기반 전략 모듈 활성 감지
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
전략 모듈이 슬롯을 활성 관리 중인지 데몬이 감지하기 위해, snapshot RPC 응답 시 해당 슬롯들의 `last_seen_at` 타임스탬프를 in-memory 워치독 store에 기록한다. `TREX_WATCHDOG_TIMEOUT` 이상 갱신되지 않은 슬롯은 "전략 모듈 미감시" 상태로 판정해 자율 안전 매도 체크 대상이 된다(dcy-007 FR-5).
## Requirement
- 시스템은 `trex.snapshot.req` 요청을 처리할 때, 응답 envelope에 포함되는 `holding` 슬롯들의 `last_seen_at`을 in-memory 워치독 store(`dict[slot_id, datetime]`)에 현재 시각(UTC 또는 KST 일관 적용)으로 갱신해야 한다.
- 시스템은 `now() − last_seen_at > TREX_WATCHDOG_TIMEOUT(초)` 조건이 성립하는 슬롯을 "워치독 만료(watchdog-expired)"로 판정해야 한다.
- 데몬 기동 후 `TREX_WATCHDOG_GRACE_PERIOD(초)` 동안은 워치독 만료 판정을 유예해야 한다(grace period). grace period 중에는 어떤 슬롯도 만료로 판정하지 않는다.
- 워치독 store는 Postgres에 영속하지 않으며 데몬 재시작 시 초기화된다.
## Acceptance Criteria
1. Given `trex.snapshot.req` handler가 응답을 산출할 때, When 응답 슬롯 목록에 `slot_id = S`가 포함되면, Then `watchdog_store[S]`가 현재 시각으로 갱신된다.
2. Given `TREX_WATCHDOG_TIMEOUT=120`이고 slot S의 `watchdog_store[S]`가 121초 전일 때, When 워치독 만료 여부를 평가하면, Then S는 만료로 판정된다.
3. Given `TREX_WATCHDOG_TIMEOUT=120`이고 slot S의 `watchdog_store[S]`가 60초 전일 때, When 워치독 만료 여부를 평가하면, Then S는 만료로 판정되지 않는다.
4. Given 데몬이 기동된 지 `TREX_WATCHDOG_GRACE_PERIOD=60` 초 이내일 때, When 워치독 만료 평가를 수행하면, Then 모든 슬롯의 만료 판정이 유예된다(store 비어 있는 슬롯 포함).
5. Given 데몬 재시작이 발생하면, When 기동 직후 워치독 store를 조회하면, Then store는 비어 있다.
6. Given 전략 모듈이 `TREX_WATCHDOG_TIMEOUT / 2` 미만 주기로 snapshot RPC를 보낼 때, When 정상 동작 중이면, Then 해당 슬롯의 워치독이 만료되지 않는다(NFR-4 관계식 검증).
## Impacted Area
- Docs:
- `docs/runtime-flows.md` — 워치독 갱신 흐름 추가 (REQ-042 참조)
- `docs/interface-contract.md` — snapshot RPC가 watchdog 갱신 신호임을 명시 (REQ-042 참조)
- Modules:
- `trex_core/application/messaging_handlers.py` — `make_snapshot_rpc_handler` 확장: 응답 슬롯의 `last_seen_at` 갱신
- `trex_core/application/portfolio.py` 또는 신규 `trex_core/application/watchdog.py` — WatchdogStore (`dict[slot_id, datetime]`), grace period 시작 타임스탬프 관리
- Tests:
- `make_snapshot_rpc_handler` 단위 테스트 — `last_seen_at` 갱신 확인
- 워치독 만료 판정 단위 테스트 — 만료/비만료/grace period 시나리오
## Notes
- 워치독 store 갱신은 snapshot RPC 응답 슬롯 기준이다. intent RPC(매수/매도)는 갱신 신호가 아니다(`update_thresholds` 액션은 제외 — REQ-040 참조).
- NFR-4 권장 관계식: `snapshot RPC 호출 주기 < TREX_WATCHDOG_TIMEOUT / 2`. 기본값 기준 전략 모듈은 60초 이내 주기로 snapshot RPC를 호출해야 한다. 관계식 위반 시 정상 동작 슬롯에서도 워치독 오탐 발생.
- 워치독 store 구현 위치(portfolio.py 확장 vs 신규 watchdog.py)는 batch planning에서 결정한다.
- `TREX_WATCHDOG_TIMEOUT`, `TREX_WATCHDOG_GRACE_PERIOD` env var 파싱은 REQ-041 참조.
## Change Log
### CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- dcy-007 confirmed → REQ-034 초안 생성
#### Intent
- per-slot 워치독 메커니즘(FR-5)을 독립 구현·검증 단위로 정규화
#### Acceptance Criteria Delta
- Added: AC-1~6 전체
#### Impacted Area Delta
- Docs: runtime-flows.md, interface-contract.md (REQ-042에서 처리)
- Modules: messaging_handlers.py, watchdog store 신규/확장
- Tests: snapshot handler + 워치독 판정 단위 테스트
#### 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-016) 워치독 갱신 부수효과를 운영자 조회에서 억제: snapshot RPC 핸들러가 `touch_watchdog=false`/`actor="operator"` 요청에 대해 holding 슬롯 `last_seen_at` 갱신을 건너뛴다. 전략 폴링 기본 동작은 불변(REQ-034 핵심 의미 유지). BAT-020 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 운영자 CLI(`universe`/`slots`) 조회가 워치독 생존 신호로 작동해 죽은 전략의 safety-sell 을 억제하는 안전 결함(R-4)을 제거.
#### Acceptance Criteria Delta
- Updated:
- 워치독 `last_seen_at` 갱신은 전략 폴링(기본)에만 적용; 운영자 억제 플래그 요청은 제외.
#### Impacted Area Delta
- Modules: `trex_core/application/messaging_handlers.py`(snapshot 핸들러 워치독 분기)
- Tests: tests/application/test_messaging_snapshot_consumer.py::test_operator_query_suppresses_watchdog_touch
#### Delivery Trace Delta
- Batches: BAT-020
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-020 에서 완료)
- Existing Implementation Invalidated: no (기본 전략 폴링 동작 불변)
- Status Recommendation: Implemented (change-req → BAT-020 재검증)
- Follow-up Action: confirm-req-implemented(BAT-020).
#### Validation Plan
- BAT-020: operator 요청 시 watchdog.update 미호출, 기본 요청 시 호출 단위.
### CHG-20260608-02
- Date: 2026-06-08
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-017/issue #12) 워치독 상태 가시화: `WatchdogStore.last_seen(slot_id)` read-only getter 추가, snapshot RPC 응답에 holding 슬롯 워치독 상태(`expired`/`last_seen`) read-only 동봉(best-effort). 판정 로직·timeout 불변(관측만 추가). BAT-021 재구현·재검증 완료 → Implemented 유지.
#### Intent
- 전략 이탈로 슬롯이 안전망(워치독) 소유로 넘어간 상태를 운영자가 인지 가능하게(무성 → 가시화).
#### Acceptance Criteria Delta
- Added:
- snapshot 응답 워치독 상태 노출 + `last_seen` getter. 판정 동작 불변.
#### Impacted Area Delta
- Modules: `trex_core/application/watchdog.py`(last_seen), `trex_core/application/messaging_handlers.py`(_attach_watchdog)
- Tests: tests/application/test_messaging_snapshot_consumer.py::test_snapshot_exposes_watchdog_state_for_holding_slots
#### Delivery Trace Delta
- Batches: BAT-021
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-021 에서 완료)
- Existing Implementation Invalidated: no (관측만 추가, 판정 불변)
- Status Recommendation: Implemented (change-req → BAT-021 재검증)
- Follow-up Action: confirm-req-implemented(BAT-021).
#### Validation Plan
- BAT-021: 워치독 만료 holding 슬롯의 expired/last_seen 노출 단위.
### CHG-20260611-01
- Date: 2026-06-11
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-025) 워치독 갱신 트리거 표면을 `trex.snapshot.req` → **`trex.slots.req`**(REQ-073)로 정합한다. 갱신 시맨틱: 기본 조회(holding 슬롯 포함)가 `last_seen_at` 을 터치하고, **`spy=true` 면 무터치**(기존 `actor="operator"`/`touch_watchdog=false` ad-hoc 플래그의 일반화·대체). 응답 노출은 top-level `watchdog[]` 배열이 아니라 슬롯 행의 `watchdog:{expired,last_seen}`(REQ-074). 만료 판정·grace period·in-memory store 는 불변.
#### Intent
- read 표면 교체 후에도 전략 폴링=생존 신호 / 비침습 조회 구분(R-4)을 보존.
#### Acceptance Criteria Delta
- Updated:
- 워치독 갱신 트리거: `trex.snapshot.req` 처리 시 → `trex.slots.req` 기본 조회 시(holding 슬롯 last_seen 갱신).
- 비침습 조회: `actor="operator"`/`touch_watchdog=false` → `spy=true`(무터치).
- 노출: 응답 `watchdog[]` 배열 → 슬롯 행 `watchdog:{expired,last_seen}`.
- Added/Removed: none
#### Impacted Area Delta
- Modules: messaging_handlers.py(터치 분기), portfolio.py(slot_to_dict watchdog 흡수)
- Docs: docs/interface-contract.md(REQ-075)
- Tests: spy 무터치/기본 터치, 행 watchdog 필드
#### Delivery Trace Delta
- Batches: 신규 batch(REQ-073/074/075 와 동일 배치, dcy-025)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (신규 batch 에서 갱신 AC 검증)
- Existing Implementation Invalidated: yes (snapshot 표면 기반 터치·watchdog[] 노출 evidence 가 표면 교체로 무효화)
- Status Recommendation: Implemented → Approved (batch 재구현·재검증 후 복귀)
- Follow-up Action: draft-batch → 구현/검증 → confirm-req-implemented
#### Validation Plan
- 신규 BAT: 기본 조회 터치/spy 무터치 단위(REQ-073 AC-4 와 공유), 행 watchdog 필드(REQ-074 AC-1), 만료·grace 회귀.
@@ -1,151 +0,0 @@
# 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 전이 단위.
@@ -1,151 +0,0 @@
# req-040: update_thresholds intent RPC 액션
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
전략 모듈이 매수 이후에도 손절·익절 임계값과 강제 만기 시각을 갱신할 수 있도록 `trex.intent.req` 채널에 `action: "update_thresholds"` 메시지 액션을 추가한다. 수신 시 해당 슬롯의 `stop_loss_price`·`take_profit_price`·`forced_close_at`를 DB에 갱신하고, 해당 슬롯의 워치독 `last_seen_at`을 현재 시각으로 리셋해 전략 모듈 활성 신호로 활용한다(dcy-007 FR-7).
## Requirement
- 시스템은 `trex.intent.req` 채널의 `action: "update_thresholds"` 메시지를 처리해야 한다.
- 메시지 payload는 `{action: "update_thresholds", slot_id, stop_loss_price?, take_profit_price?, forced_close_at?}` 형식이며, 세 필드는 각각 독립적으로 포함하거나 생략할 수 있다. 생략된 필드는 현재 값을 유지한다.
- 처리 성공 시 요청한 필드를 DB에 갱신하고 해당 슬롯의 워치독 `last_seen_at`을 현재 시각으로 리셋해야 한다.
- 대상 슬롯이 `holding` 상태인 경우에만 갱신을 수행한다.
- 대상 슬롯이 `holding`이 아닌 경우의 처리(무시 또는 에러 응답)는 구현 시 결정한다(OQ-6 Deferred — 선택 옵션: `{status: ignored, reason: "not_holding"}` 응답 또는 silent discard).
- `reply_to`가 있으면 갱신 결과(`{status: updated|ignored, slot_id}`)를 응답으로 반환한다.
## Acceptance Criteria
1. Given `holding` 상태의 슬롯 S가 있을 때, When `{action: "update_thresholds", slot_id: S, stop_loss_price: 50000}`을 `trex.intent.req`에 발행하면, Then S의 `stop_loss_price`가 `50000`으로 DB에 갱신된다.
2. Given `holding` 상태의 슬롯 S가 있을 때, When `{action: "update_thresholds", slot_id: S, take_profit_price: 80000, forced_close_at: "2026-06-07T15:10:00+09:00"}`를 발행하면, Then S의 `take_profit_price`와 `forced_close_at`가 DB에 갱신된다.
3. Given `holding` 상태의 슬롯 S가 있을 때, When `update_thresholds`를 수신하면, Then S의 워치독 `last_seen_at`이 현재 시각으로 리셋된다.
4. Given `update_thresholds` 메시지에 `stop_loss_price`만 포함되고 `take_profit_price`와 `forced_close_at`는 생략될 때, When 처리되면, Then `stop_loss_price`만 갱신되고 나머지 두 필드는 기존 값을 유지한다.
5. Given `null` 값으로 `stop_loss_price: null`을 명시할 때, When 처리되면, Then `stop_loss_price`가 `NULL`로 갱신된다(임계값 해제).
6. Given 대상 슬롯이 `holding`이 아닌 상태일 때, When `update_thresholds`를 수신하면, Then 슬롯 필드가 변경되지 않는다. `reply_to`가 있으면 `{status: ignored, reason: "not_holding"}` 응답을 반환한다(OQ-6 구현 결정).
7. Given `reply_to`가 있는 요청에서 갱신이 성공하면, When 처리가 완료되면, Then `{status: updated, slot_id}`가 `reply_to`로 반환된다.
## Impacted Area
- Docs:
- `docs/interface-contract.md` — `update_thresholds` action 계약 추가 (REQ-042 참조)
- Modules:
- `trex_core/application/messaging_handlers.py` — `make_intent_rpc_handler` 확장: `update_thresholds` action 라우팅 + DB 갱신 + `last_seen_at` 리셋
- `trex_core/domain/slot/service.py` — `SlotService.update_thresholds(slot_id, stop_loss_price, take_profit_price, forced_close_at)` 메서드 추가
- Tests:
- `update_thresholds` handler 단위 테스트 — holding 슬롯 갱신 확인, last_seen_at 리셋 확인
- 필드 부분 갱신 테스트 (일부만 포함된 payload)
- null 값 처리 테스트
- non-holding 슬롯 무시 테스트
## Notes
- OQ-6(Deferred → REQ AC): `holding`이 아닌 슬롯 요청 처리 방식. 구현 시 `{status: ignored, reason: "not_holding"}` 응답 반환을 권장한다. silent discard도 허용되며 batch에서 결정한다.
- `update_thresholds` 수신은 워치독 `last_seen_at` 리셋을 겸한다. 전략 모듈이 임계값을 갱신하면 활성 신호로 처리돼 그 시점부터 `TREX_WATCHDOG_TIMEOUT` 타이머가 재시작된다(REQ-034).
- 기존 intent RPC dedup(`intent_log.try_insert`) 적용 여부는 batch 설계에서 결정한다. `update_thresholds`는 상태 read-modify가 아닌 idempotent SET이므로 dedup 생략이 적절할 수 있다.
## Change Log
### CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- dcy-007 confirmed → REQ-040 초안 생성
#### Intent
- update_thresholds intent RPC 액션(FR-7)을 독립 Interface REQ로 정규화. OQ-6 Deferred 처리 방식을 AC-6에 명시.
#### Acceptance Criteria Delta
- Added: AC-1~7 전체
#### Impacted Area Delta
- Docs: interface-contract.md (REQ-042에서 처리)
- Modules: messaging_handlers.py (handler 확장), service.py (`update_thresholds()` 추가)
- Tests: handler 단위 테스트 4종
#### 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-20260607-03
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-011 release-candidate).
#### Intent
- BAT-011 verification.md 의 AC↔evidence(`update_thresholds` 부분 갱신·null 해제·last_seen_at 리셋·non-holding ignored·미존재 slot_not_found·updated 응답)로 AC-1~7 충족 → 구현 완료 동기화. OQ-6 은 AC-6 의 `{ignored, not_holding}` 응답으로 확정 구현.
#### Acceptance Criteria Delta
- (변경 없음)
#### Impacted Area Delta
- (변경 없음)
#### Delivery Trace Delta
- Batches: BAT-011 (release-candidate)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: draft-release 로 BAT-011 배포 편성.
@@ -1,148 +0,0 @@
# req-043: trex.control.req 제어 채널 + action dispatch
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
기존 `trex.pause.req` 단일 목적 큐를 `trex.control.req` 제어 채널로 개념 확장하고, payload `action` 필드 기반 dispatch로 운영자 제어 명령을 단일 채널에서 처리한다. 기능마다 큐/consumer 스레드를 늘리지 않기 위한 단일 제어 채널 + action discriminator 패턴(dcy-008 OQ-1 Answered). 기존 pause/resume/list 동작을 보존하면서 kill-switch(REQ-045)와 resume_kill_switch(REQ-046) 라우팅 진입점을 추가한다.
## Requirement
- 데몬은 단일 제어 큐 `trex.control.req` 를 소비하고 메시지 payload 의 `action` 필드로 핸들러를 분기한다.
- 기존 제어 action(`pause`/`resume`/`list`, REQ-032)의 동작·응답 계약을 그대로 유지한다.
- 신규 action 라우팅을 추가한다: `kill_switch`(REQ-045), `resume_kill_switch`(REQ-046). 본 REQ는 라우팅·메시지 계약 골격만 정의하고 실제 청산/해제 동작은 각 REQ에서 정의한다.
- 알 수 없는 `action` 은 `{status: "error", reason: "unknown_action:<action>"}` 으로 응답한다.
- 기존 `trex.pause.req` consumer 스레드를 control consumer(`trex.control.req`)로 교체한다. 데몬 워커 스레드 총수는 불변(7개 유지).
- 하위호환: `trex.pause.req` 를 사용하던 기존 클라이언트 호환 방식(별칭 큐 유지 vs `trex.control.req` 단일화)은 배포 영향이 있으므로 Notes 에 결정 필요로 남긴다.
## Acceptance Criteria
1. Given `trex.control.req` 에 `{action: "pause", portfolio_id}` 발행, When 처리되면, Then 기존 REQ-032 pause 동작과 동일하게 `snapshot_pause` 에 반영되고 `{status: "ok", paused[], action}` 응답을 반환한다.
2. Given `{action: "resume", portfolio_id}` / `{action: "list"}`, When 처리되면, Then 각각 기존 resume/list 동작과 동일한 응답을 반환한다.
3. Given `{action: "kill_switch", ...}`, When 처리되면, Then kill-switch 핸들러(REQ-045)로 라우팅된다.
4. Given `{action: "resume_kill_switch", ...}`, When 처리되면, Then resume 핸들러(REQ-046)로 라우팅된다.
5. Given `{action: "bogus"}`, When 처리되면, Then `{status: "error", reason: "unknown_action:bogus"}` 를 반환한다.
6. Given 데몬 기동, When 워커 스레드를 확인하면, Then pause consumer 가 control consumer 로 교체되어 총 워커 스레드 수가 7로 불변이다.
## Impacted Area
- Docs:
- `docs/interface-contract.md` — 제어 채널 계약(`trex.control.req` + action 목록) (REQ-047 처리)
- Modules:
- `trex_core/adapters/messaging/topology.py` — `CONTROL_REQ_QUEUE = "trex.control.req"` 추가(또는 `PAUSE_REQ_QUEUE` 대체)
- `trex_core/application/messaging_handlers.py` — `make_control_rpc_handler`(action dispatch) 신설 또는 `make_pause_rpc_handler` 확장
- `trex_core/runtime/daemon.py` — pause consumer → control consumer 교체
- Tests:
- control dispatch 단위 테스트(pause/resume/list 회귀 + kill_switch/resume_kill_switch 라우팅 + unknown action)
## Notes
- dcy-008 OQ-1 Answered: 단일 제어 채널 + action discriminator. 새 큐 추가 없음.
- 하위호환 결정 필요(배포): 기존 `trex.pause.req` 토픽 이름을 유지(별칭)할지, `trex.control.req` 로 단일화하고 전략/운영 클라이언트를 함께 갱신할지 — batch planning/release 단계에서 확정. 현재 CLI pause/resume 는 store 직접 호출이라 영향 없음(RPC 경로만 대상).
- kill_switch/resume_kill_switch 의 payload 상세(scope/portfolio_id)는 REQ-045/046 에서 정의.
## Change Log
### CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- dcy-008(confirmed) → REQ-043 초안 생성.
#### Intent
- kill-switch 트리거 표면(OQ-1 Answered)을 단일 제어 채널 Interface REQ 로 정규화.
#### Acceptance Criteria Delta
- Added: AC-1~6 전체
#### Impacted Area Delta
- Docs: interface-contract.md (REQ-047)
- Modules: topology.py, messaging_handlers.py, daemon.py
- Tests: control dispatch 단위
#### Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 로 승인.
### CHG-20260607-02
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트 통과: 필수 필드·구체 AC·Impacted Area·Change Log 완비. dcy-008(confirmed) 범위·결정(OQ-1/2/4 Answered, OQ-3 Deferred)과 모순 없음. 하위호환(큐 rename)은 batch/release 단계 비핵심 운영 결정으로 승인 blocker 아님.
#### 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 / draft-batch 로 delivery 편성.
### CHG-20260607-03
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-012 release-candidate).
#### Intent
- BAT-012 verification 의 AC↔evidence(control dispatch 9 단위: pause/resume/list 회귀 + kill_switch/resume_kill_switch 라우팅 + unknown action + 워커 스레드 불변 + e2e control RPC)로 AC-1~6 충족.
#### Acceptance Criteria Delta
- (변경 없음)
#### Impacted Area Delta
- (변경 없음)
#### Delivery Trace Delta
- Batches: BAT-012 (release-candidate)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: draft-release 로 BAT-012 배포 편성. 제어 큐 하위호환은 release rollout 결정.
@@ -1,155 +0,0 @@
# req-045: kill-switch 실행 — 범위별 holding 즉시 청산 + 이력 로깅
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
운영자가 `trex.control.req` 에 `action: "kill_switch"` 를 발행하면 대상 범위(portfolio 단위 또는 전역)의 모든 `holding` 슬롯을 즉시 청산한다. 기존 `SlotService.sell()`(REQ-036)을 재사용해 순차 매도를 제출하고, 같은 발동에서 대상 범위를 당일 제외(REQ-044/046)로 표시한다. 자율 안전 매도(dcy-007)와 독립적으로 동작하며, 발동 이력을 로깅한다(dcy-008 FR-1/4/5/6, NFR-1/2).
## Requirement
- `action: "kill_switch"` payload: `{action, scope: "portfolio"|"global", portfolio_id?(scope=portfolio 시 필수), actor?}`.
- 발동 시 대상 범위의 모든 `holding` 슬롯에 `SlotService.sell(actor="kill-switch", reason="emergency_stop")` 을 순차 호출한다.
- scope=portfolio: 해당 `portfolio_id` 의 holding 슬롯만.
- scope=global: 당일 전체 holding 슬롯.
- 이미 `pending_sell` 인 슬롯은 중복 sell 하지 않는다(REQ-036 idempotency).
- 발동과 동시에 대상 범위를 당일 제외로 표시한다(REQ-044 store 의 `exclude(...)` 호출). masking 동작 자체는 REQ-046.
- 발동 이력(actor, 발동 시각, scope, portfolio_id, 처리 슬롯 수)을 데몬 로그에 1건 기록한다.
- 응답: `{status: "ok", scope, portfolio_id?, liquidated: <처리 슬롯 수>}`. scope=portfolio 인데 `portfolio_id` 누락 시 `{status: "error", reason: "portfolio_id_required"}`.
- kill-switch 실행은 자율 안전 매도 루프(dcy-007)와 상태/스레드를 공유하지 않으며 서로 영향을 주지 않는다.
## Acceptance Criteria
1. Given holding 슬롯 N개(전역), When `{action:"kill_switch", scope:"global"}` 처리, Then N개 모두 `holding→pending_sell`(actor=kill-switch, reason=emergency_stop) 전이되고 응답 `liquidated=N`.
2. Given portfolio `pf-A` 에 holding 2개 + `pf-B` 에 holding 1개, When `{action:"kill_switch", scope:"portfolio", portfolio_id:"pf-A"}`, Then `pf-A` 2개만 청산되고 `pf-B` 는 holding 유지.
3. Given 대상 중 이미 `pending_sell` 인 슬롯, When kill_switch 처리, Then 그 슬롯에 중복 sell 호출이 없다(REQ-036 idempotency, transition_log 중복 없음).
4. Given scope=portfolio 인데 `portfolio_id` 누락, When 처리, Then `{status:"error", reason:"portfolio_id_required"}`.
5. Given kill_switch 발동, When 처리 완료, Then 대상 범위가 REQ-044 store 에 당일 제외로 기록된다(`list_excluded(today)` 에 포함).
6. Given kill_switch 발동, When 로그를 확인, Then actor/발동 시각/scope/portfolio_id/처리 슬롯 수를 담은 이력 1건이 기록된다.
7. Given 자율 안전 매도 루프(dcy-007)가 동작 중, When kill_switch 가 발동, Then 두 경로가 독립적으로 동작하며(REQ-036 idempotency 로 충돌 없음) safety-sell 루프가 중단/오류 없이 유지된다.
8. Given holding N개, When kill_switch 처리, Then 전체 sell() 제출 완료까지 지연이 N×100ms + 5s 이내이다(순차, outbox 전송 제외; A-4 N<10 가정).
## Impacted Area
- Docs:
- `docs/runtime-flows.md` — kill-switch 발동 흐름(트리거→순차 sell()→당일 제외 표시) (REQ-047 처리)
- `docs/interface-contract.md` — kill_switch payload/응답 계약 (REQ-047 처리)
- Modules:
- `trex_core/application/messaging_handlers.py` — kill_switch handler(REQ-043 dispatch 하위)
- `trex_core/domain/slot/service.py` 또는 신규 application 서비스 — 범위별 holding 조회 + 순차 sell() 진입점
- REQ-044 store 연동(당일 제외 표시)
- Tests:
- kill_switch handler 단위 테스트(전역/portfolio/idempotency/portfolio_id 누락/이력 로깅/독립성)
## Notes
- NFR-1(지연)·NFR-2(dcy-007 독립)는 본 REQ AC-8/AC-7 로 흡수(별도 REQ 미승격 — 독립 backlog 가치 낮음, dcy-008 정합).
- pending_buy 슬롯 처리는 dcy-008 OQ-3 Deferred → 기본 구현은 HOLDING 만 대상. pending_buy 롤백은 후속(REQ 추가 또는 change-req).
- R-1(큐 부하): sell()은 PENDING_SELL 전이(DB write 1회)로 빠름. execution worker 순차 처리 유지.
- R-3(브로커 오류): sell()→PENDING_SELL 성공 시 기존 outbox retry 가 eventual consistency 보장.
## Change Log
### CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- dcy-008(confirmed) → REQ-045 초안 생성.
#### Intent
- kill-switch 즉시 청산(FR-1/4/5/6)과 NFR-1/2 흡수를 Interface REQ 로 정규화.
#### Acceptance Criteria Delta
- Added: AC-1~8 전체
#### Impacted Area Delta
- Docs: runtime-flows.md, interface-contract.md (REQ-047)
- Modules: messaging_handlers.py, service.py(또는 신규 서비스), REQ-044 store 연동
- Tests: kill_switch handler 단위
#### Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 로 승인.
### CHG-20260607-02
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트 통과: 필수 필드·구체 AC(1~8)·Impacted Area·Change Log 완비. dcy-008(confirmed) 범위와 모순 없음. NFR-1/2 흡수, OQ-3(pending_buy) REQ Deferred 는 비핵심 후속으로 승인 blocker 아님(기본 구현 HOLDING 한정).
#### 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 / draft-batch 로 delivery 편성.
### CHG-20260607-03
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-012 release-candidate).
#### Intent
- BAT-012 verification 의 AC↔evidence(실행 6 단위: 전역/portfolio 범위/idempotency/당일 제외 표시/resume 비가역/no-holding + e2e kill_switch global liquidated=2 → closed, emergency_stop reason)로 AC-1~8 충족. NFR-1/2 흡수 확인.
#### Acceptance Criteria Delta
- (변경 없음)
#### Impacted Area Delta
- (변경 없음)
#### Delivery Trace Delta
- Batches: BAT-012 (release-candidate)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: draft-release 로 BAT-012 배포 편성. 실 KIS 라이브 발동은 운영 실증 이월.
@@ -1,154 +0,0 @@
# req-046: kill-switch 당일 제외 masking + 자동 해제 + 수동 resume
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
kill-switch 발동(REQ-045)으로 표시된 당일 제외 상태를 snapshot RPC 응답에 반영해 대상 자산을 당일 전략 실행에서 제외한다(추가 매수 차단). 제외는 day-scoped 라 다음 거래일 자동 복귀하며(REQ-044 `trading_date` 키), 운영자는 같은 거래일 내 `action: "resume_kill_switch"` 로 수동 해제할 수 있다(dcy-008 FR-2/3, NFR-3, OQ-4 Answered).
## Requirement
- snapshot RPC 응답 산출 시 masking 소스에 "kill-switch 당일 제외"(REQ-044 `list_excluded(today)`)를 추가한다: `mask = pending | warning | pause | killswitch_today`.
- scope=portfolio 제외는 해당 `portfolio_id` 자산만, 전역 제외는 당일 전체 자산을 마스킹한다.
- 마스킹된 자산은 buyable/held 뷰에 노출되지 않아 당일 추가 매수 의도가 거부된다.
- 당일 제외는 `trading_date` 기준 day-scoped 다. 다음 거래일 첫 조회/부팅 시 `list_excluded(다음 날)` 에 포함되지 않아 자동 복귀한다(별도 해제 동작 불필요).
- 영속성: 데몬 재시작 후에도 같은 거래일이면 masking 이 유지된다(REQ-044 영속, NFR-3).
- 수동 해제: `action: "resume_kill_switch"` payload `{action, scope, portfolio_id?, actor?}` 처리 시 대상 범위의 당일 제외를 해제(REQ-044 `clear(...)`)해 다음 조회부터 정상 매매 대상으로 복귀시킨다.
- resume 은 **당일 제외(매매 차단)만 해제**하며 이미 청산(매도)된 슬롯을 되돌리지 않는다(매도 비가역).
- 응답: `{status: "ok", scope, portfolio_id?}`. scope=portfolio 인데 `portfolio_id` 누락 시 `{status:"error", reason:"portfolio_id_required"}`.
## Acceptance Criteria
1. Given `pf-A` 가 당일 제외(REQ-044)로 표시됨, When snapshot RPC(view=buyable/all) 처리, Then `pf-A` 자산이 응답 assets 에서 마스킹되어 노출되지 않는다.
2. Given 전역 당일 제외 표시, When snapshot RPC 처리, Then 당일 전체 자산이 마스킹된다.
3. Given 당일 제외 표시 후, When 당일 추가 매수 intent 가 해당 자산에 들어오면, Then buyable 마스킹으로 거부/비노출된다.
4. Given `pf-A` 당일(D) 제외, When 거래일 D+1 로 snapshot RPC 처리, Then `pf-A` 가 다시 노출된다(자동 복귀, 별도 resume 불필요).
5. Given `pf-A` 제외 후 데몬 재시작(같은 거래일 D), When snapshot RPC 처리, Then 여전히 마스킹된다(영속, NFR-3).
6. Given `pf-A` 당일 제외 상태, When `{action:"resume_kill_switch", scope:"portfolio", portfolio_id:"pf-A"}` 처리, Then 다음 snapshot RPC 부터 `pf-A` 가 정상 노출되고 응답 `{status:"ok"}`.
7. Given resume_kill_switch scope=portfolio 인데 `portfolio_id` 누락, When 처리, Then `{status:"error", reason:"portfolio_id_required"}`.
8. Given resume_kill_switch 처리, When 이미 청산된 슬롯을 확인, Then 슬롯 상태(pending_sell/closed)는 되돌려지지 않는다(매도 비가역).
## Impacted Area
- Docs:
- `docs/interface-contract.md` — masking 소스에 kill-switch 당일 제외 + resume_kill_switch 계약 (REQ-047 처리)
- `docs/runtime-flows.md` — 당일 제외 masking / 자동 복귀 / 수동 resume 흐름 (REQ-047 처리)
- Modules:
- `trex_core/application/portfolio.py`(또는 snapshot envelope builder) — masking 소스에 `list_excluded(today)` 추가
- `trex_core/application/messaging_handlers.py` — `resume_kill_switch` handler(REQ-043 dispatch 하위) + snapshot 핸들러에 killswitch store 주입
- REQ-044 store 연동(`list_excluded`/`clear`)
- Tests:
- masking 단위 테스트(portfolio/전역/추가매수 거부) + day-scoped 자동 복귀(날짜 mock) + 재시작 영속 + resume 단위
## Notes
- dcy-008 OQ-4 Answered: 수동 해제 지원(`resume_kill_switch`). 자동 복귀(day-scoped)와 병행.
- NFR-3(영속 후 재시작 masking 유지)는 본 REQ AC-5 로 흡수.
- 전역 제외 sentinel 해석은 REQ-044 store 계약을 따른다.
- masking 합성은 기존 pause masking 패턴(`portfolio.py`)을 재사용(A-2).
## Change Log
### CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- dcy-008(confirmed) → REQ-046 초안 생성.
#### Intent
- 당일 제외 masking/자동 복귀/수동 resume(FR-2/3, OQ-4, NFR-3 흡수)을 Interface REQ 로 정규화.
#### Acceptance Criteria Delta
- Added: AC-1~8 전체
#### Impacted Area Delta
- Docs: interface-contract.md, runtime-flows.md (REQ-047)
- Modules: portfolio.py, messaging_handlers.py, REQ-044 store 연동
- Tests: masking + day-scoped + 영속 + resume 단위
#### Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 로 승인.
### CHG-20260607-02
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트 통과: 필수 필드·구체 AC(1~8)·Impacted Area·Change Log 완비. dcy-008(confirmed) OQ-4 결정(resume_kill_switch) 반영, NFR-3 흡수. 범위·결정과 모순 없음.
#### 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 / draft-batch 로 delivery 편성.
### CHG-20260607-03
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-012 release-candidate).
#### Intent
- BAT-012 verification 의 AC↔evidence(masking·resume 7 단위: portfolio/전역 masking + buyable 차단 + day-scoped 자동복귀(날짜) + 영속 + resume 재포함 + 청산 비가역 + backward-compat; e2e resume_kill_switch → exclusion 0)로 AC-1~8 충족. NFR-3 흡수.
#### Acceptance Criteria Delta
- (변경 없음)
#### Impacted Area Delta
- (변경 없음)
#### Delivery Trace Delta
- Batches: BAT-012 (release-candidate)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: draft-release 로 BAT-012 배포 편성.
@@ -1,147 +0,0 @@
# req-049: instance_key 기반 동적 큐명 + default 하위호환
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
다중 인스턴스가 동일 RabbitMQ 에서 경쟁 소비(round-robin)로 split-brain 을 일으키지 않도록, 수신 큐명을 `instance_key` 기반으로 인스턴스별 분리한다. `topology.py` 의 고정 큐명 상수를 동적 함수로 교체하고, `declare_topology(instance_key)` + 각 consumer 가 인스턴스 전용 큐를 구독하게 한다. `instance_key="default"` 는 기존 리터럴 큐명을 그대로 사용해 하위호환을 보장한다(dcy-009 FR-2, FR-5, NFR-1/2/3).
## Requirement
- `topology.py` 의 고정 큐명 상수(`SNAPSHOT_REQ_QUEUE` 등)를 동적 빌더 함수로 교체/보강한다: `intent_queue(instance_key)`, `snapshot_queue(instance_key)`, `control_queue(instance_key)`.
- **하위호환 규칙**: `instance_key in (None, "default")` 이면 기존 리터럴 큐명(`trex.intent.req` / `trex.snapshot.req` / `trex.control.req`)을 반환한다. 그 외에는 `{base}.{instance_key}` 를 반환한다(FR-5: default 무회귀).
- `rabbitmq.py` `declare_topology(instance_key=...)` 가 인스턴스 전용 큐를 선언한다. `daemon.py` 의 intent/snapshot/control consumer 가 동일 `instance_key` 의 전용 큐를 `consume_rpc_forever` 로 구독한다.
- `daemon.py` 는 설정(REQ-048 TOML)에서 읽은 `instance_key` 를 큐 선언/구독에 일관되게 전달한다.
- 기존 pika `BlockingConnection` per-thread 패턴을 유지한다 — 큐 분리로 인해 추가 스레드/커넥션을 만들지 않는다(NFR-2). 워커 스레드 수 불변.
## Acceptance Criteria
1. Given `instance_key="inst-1"`, When `intent_queue("inst-1")`/`snapshot_queue`/`control_queue`, Then 각각 `trex.intent.req.inst-1`/`trex.snapshot.req.inst-1`/`trex.control.req.inst-1` 를 반환한다.
2. Given `instance_key="default"`(또는 None), When 동일 빌더, Then 기존 리터럴 `trex.intent.req`/`trex.snapshot.req`/`trex.control.req` 를 반환한다(하위호환).
3. Given `declare_topology("inst-1")`, When 선언, Then `*.inst-1` 인스턴스 전용 큐가 선언된다(S-1 일부).
4. Given `instance_key="default"` 데몬, When 전체 pytest 스위트 실행, Then 회귀 없음(FR-5/NFR-1, 기존 큐명 테스트 통과).
5. Given 데몬 기동, When 워커 스레드 확인, Then per-thread connection 패턴 유지 + 스레드 수 불변(NFR-2).
6. Given `instance_key="inst-1"` 와 `inst-2` 동시 운영(전용 큐 분리), When 각자 큐만 소비, Then 한 인스턴스의 snapshot/intent 소비가 다른 인스턴스 큐에 영향을 주지 않는다(NFR-3 split-brain 방지 기반).
## Impacted Area
- Docs:
- `docs/runtime-flows.md`, `docs/project-structure.md` — 동적 큐명/토폴로지 (REQ-051 처리)
- Modules:
- `trex_core/adapters/messaging/topology.py` — 동적 큐명 빌더(default 하위호환)
- `trex_core/adapters/messaging/rabbitmq.py` — `declare_topology(instance_key)`
- `trex_core/runtime/daemon.py` — consumer 가 instance_key 전용 큐 구독
- Tests:
- `tests/adapters/messaging/` — 큐명 빌더(default vs named) + declare/consume 분리 + 기존 회귀
## Notes
- 하위호환 핵심: default = 리터럴 큐명(특수 처리)이라 기존 테스트/배포 무영향. FR-2 의 suffix 규칙은 named instance 에 적용.
- NFR-3(split-brain 방지)는 인스턴스 전용 큐로 구조적으로 달성 — 다중 인스턴스 e2e 는 verification 에서 확인.
- exchange/binding(트래픽 라우팅)은 REQ-050.
## Change Log
### CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- dcy-009(confirmed) → REQ-049 초안 생성.
#### Intent
- instance_key 동적 큐명 + default 하위호환(FR-2/FR-5)을 Interface REQ 로 정규화.
#### Acceptance Criteria Delta
- Added: AC-1~6 전체
#### Impacted Area Delta
- Docs: runtime-flows.md, project-structure.md (REQ-051)
- Modules: topology.py, rabbitmq.py, daemon.py
- Tests: tests/adapters/messaging
#### Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 로 승인.
### CHG-20260607-02
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트 통과: 필수 필드·구체 AC·Impacted Area·Change Log 완비. dcy-009(confirmed) FR-2/FR-5 와 일치. default 하위호환 규칙 명확.
#### 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 / draft-batch 로 delivery 편성.
### CHG-20260607-03
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-013 release-candidate).
#### Intent
- BAT-013 verification 의 AC↔evidence(빌더 단위 named suffix/default 리터럴 + declare_topology(instance_key) + 전체 301 passed 로 default 무회귀)로 AC-1~6 충족. NFR-1/2/3 흡수.
#### Acceptance Criteria Delta
- (변경 없음)
#### Impacted Area Delta
- (변경 없음)
#### Delivery Trace Delta
- Batches: BAT-013 (release-candidate)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: draft-release 로 BAT-013 배포 편성.
@@ -1,135 +0,0 @@
# req-057: 자산 영구 슬롯 상태머신 재정의 + 인스턴스 스코프 advisory lock
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 영구 자산 슬롯에 맞춰 슬롯 상태머신을 재정의하고, holding 을 코어 로컬 정본으로 두며, 공유 DB 다중 인스턴스에서 단일 writer 불변식을 인스턴스 단위로 보존한다. (dcy-020 FR-6/FR-3/NFR-1)
## Requirement
- 상태 집합을 `inactive → pending_buy → holding → pending_sell → inactive` (+ 모든 비-error → `error`, `error → {inactive, holding}` 운영자 resolve)로 재정의한다. 기존 `idle`·`closed` 는 영구 슬롯에서 단일 `inactive` 로 합치고 `closed→idle` 복구 전이를 제거한다. `holding`(포지션 열림)은 코어 슬롯의 로컬 정본으로 체결 시 동기 set, 매도 체결 시 동기 clear 한다(portfolio-hub `asset_quantity` 로 판단하지 않음). advisory lock 을 **인스턴스 스코프**(`pg_advisory_xact_lock(SLOT_LOCK_ID, hash(instance_key))`)로 두어 인스턴스 간 교차 직렬화를 제거한다.
## Acceptance Criteria
1. Given 상태머신, When 허용 전이 집합을 확인, Then `{inactive→pending_buy, pending_buy→holding, pending_buy→inactive, holding→pending_buy, holding→pending_sell, pending_sell→inactive, pending_sell→holding, *→error, error→inactive, error→holding}` 와 정확히 일치한다(dcy-021 CHG-20260610-03: `holding→pending_buy` 증액 전이 추가).
2. Given 영구 슬롯, When 매도 체결로 종료, Then 슬롯은 `inactive` 로 돌아가고(별도 `closed`·`closed→idle` 없음) holding 로컬 플래그가 clear 된다.
3. Given 서로 다른 instance_key 의 두 슬롯, When 동시에 전이, Then 인스턴스별 락으로 서로를 차단하지 않는다(교차 경합 없음).
4. Given 같은 슬롯에 대한 동시 전이, When 병렬 처리, Then 인스턴스 스코프 락으로 직렬화되어 단일 writer 불변식이 유지된다.
5. Given 보유(holding) 슬롯 증액, When `holding→pending_buy` 전이, Then 허용되고 체결 시 `pending_buy→holding` 으로 복귀한다(dcy-021 REQ-066). 부분 매도 잔량은 기존 `pending_sell→holding` 전이로 holding 을 유지한다.
## Impacted Area
- Docs: docs/runtime-flows.md(전이 흐름), docs/data-model.md(상태)
- Modules: trex_core/domain/slot/state.py, trex_core/domain/slot/service.py, trex_core/domain/slot/models.py
- Tests: tests/domain/slot/test_state.py, tests/domain/slot/test_service.py
## Notes
- 기존 REQ-002(상태머신·서비스) 재정의 change-req 동반. dcy-001 의 6상태/closed→idle 모델 폐기.
- holding 로컬 정본 근거(offline 안전·universe 누락 생존·hub 지연·capacity 원자성)는 dcy-020 FR-3.
- 출처: dcy-020 FR-6, FR-3, NFR-1, OQ-7.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-020 FR-6/FR-3/NFR-1 로부터 최초 생성(Proposed). 상태머신 재정의(idle/closed→inactive, closed→idle 제거) + holding 로컬 정본 + 인스턴스 스코프 advisory lock.
#### Intent
- 영구 자산 슬롯 상태머신·holding 로컬·인스턴스 단위 단일 writer 를 backlog 로 정규화.
#### Acceptance Criteria Delta
- Added:
- 전이 집합/inactive 종료/인스턴스별 락 비교차/동일 슬롯 직렬화 4개 기준
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/runtime-flows.md, docs/data-model.md
- Modules: domain/slot/state.py, service.py, models.py
- Tests: test_state.py, test_service.py
#### Delivery Trace Delta
- Batches: none
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no (신규 정의; REQ-002 재정의 change-req 로 기존 폐기)
- Status Recommendation: keep-current
- Follow-up Action: confirm-req. REQ-002 change-req 동반.
#### Validation Plan
- 전이 허용/거부 집합 + 인스턴스 락 단위테스트 green.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-020(confirmed, handoff 승인)과 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md (Register Approved) / Modules: 없음 / Tests: 없음
#### 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 / draft-batch.
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ AC 를 검증 기준으로 사용.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-027(토대)+BAT-030(literal inactive·별칭 제거) — 모든 AC 가 release-candidate 배치 verification 의 evidence 와 연결됨(단위 367/PG 29/MQ 21 passed + run-the-app 자산 중심 e2e). Blocking Issues 없음.
### CHG-20260610-03
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징, issue #1) 반영: 상태 전이 집합에 **`holding→pending_buy`(보유 슬롯 증액)** 를 추가하고, `pending_sell→holding`(기존)을 부분 매도 잔량 holding 유지 경로로 명시. 전량 매도만 `pending_sell→inactive`.
#### Intent
- 보유 자산 슬롯이 holding 을 유지한 채 수량 증액(추가 매수)·부분 감액을 표현하도록 상태머신을 additive 확장(dcy-020 이 고정한 "종료=전량 청산" 경계 해제).
#### Acceptance Criteria Delta
- Added: AC-5(holding→pending_buy 증액 전이 허용·체결 시 holding 복귀, 부분 매도 잔량 pending_sell→holding)
- Updated: AC-1 허용 전이 집합에 holding→pending_buy 포함
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/runtime-flows.md, docs/data-model.md (REQ-067 정합)
- Modules: trex_core/domain/slot/state.py(전이 추가), service.py(증액 qty/avg_price = REQ-066)
- Tests: tests/domain/slot/test_state.py(전이 집합·size), test_service.py
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (전이 집합 변경 — test_state 갱신·증액 경로 검증)
- Existing Implementation Invalidated: no (기존 전이 보존, additive) — 단 AC-1 "정확히 일치"가 신규 전이를 포함하도록 확장되어 재검증 필요
- Status Recommendation: revert-to-approved (신규 전이 미구현 — dcy-021 배치에서 구현·검증 후 confirm-req-implemented)
- Follow-up Action: dcy-021 배치 구현 + test_state 전이 집합 갱신 후 Implemented 복귀.
#### Validation Plan
- ALLOWED_TRANSITIONS 에 holding→pending_buy 포함·size 갱신 단위 테스트 + 증액 end-to-end(REQ-066).
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
@@ -1,94 +0,0 @@
# req-059: 활성 capacity 제어 + 신호 기반 admission (FCFS·M캡·무치환·over-cap)
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 익명 슬롯 배정 대신 "동시 활성(holding) 최대 M개" 정책으로 capacity 를 제어하고, 매수/매도 신호를 해당 자산 슬롯의 활성화/비활성화로 처리한다. (dcy-020 FR-2/FR-3/OQ-1/OQ-8)
## Requirement
- 매수 신호는 해당 자산 슬롯을 활성화(`inactive→pending_buy`)한다. 활성(holding+pending_buy) 수 < M 이면 즉시 활성화, == M 이면 **거부(`capacity_full`)** 한다. 코어는 자리를 만들려고 기존 holding 을 **자율 청산(치환)하지 않는다**(FCFS·무치환). 동시 후보 tie-break 은 `updated_at` asc → `portfolio_id`(alpha 비사용). M 을 현재 보유 수보다 작게 바꿔 over-cap 이 되면 **신규 활성화만 차단**하고 기존 보유는 자연 종료까지 유지한다(강제 청산 없음). 마지막 슬롯 경합은 인스턴스 스코프 advisory lock + 재시도로 직렬화한다.
## Acceptance Criteria
1. Given 활성 수 < M, When 자산 매수 신호, Then 그 자산 슬롯이 `pending_buy` 로 활성화된다.
2. Given 활성 수 == M, When 새 자산 매수 신호, Then `capacity_full` 로 거부되고 기존 holding 은 청산되지 않는다.
3. Given 이미 활성(pending_buy/holding/pending_sell)인 자산, When 또 매수 신호, Then 멱등 거부(`already_active`)된다.
4. Given M 을 현재 보유 수보다 작게 변경(over-cap), When 신규 매수 신호, Then 활성 수가 M 이하로 내려갈 때까지 신규만 거부되고 기존 보유는 유지된다.
5. Given 동시 매수 신호 경합, When 병렬 처리, Then 인스턴스 스코프 락으로 직렬화되어 M 초과 활성화가 발생하지 않는다.
## Impacted Area
- Docs: docs/runtime-flows.md(admission→활성화 흐름)
- Modules: trex_core/application/intents.py, trex_core/application/portfolio.py(capacity 개념)
- Tests: tests/application/test_intent_concurrency.py, tests/application/test_*admission*.py
## Notes
- M 값 출처는 REQ-060(per-instance TOML). 기존 REQ-007(admission) 재정의 change-req 동반(find_allocatable_slot/idle 배정 폐기).
- 출처: dcy-020 FR-2, FR-3, OQ-1, OQ-8.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-020 FR-2/FR-3/OQ-1/OQ-8 로부터 최초 생성(Proposed). FCFS + M 캡 + capacity_full 거부 + 무치환 + over-cap(신규만 차단) + already_active.
#### Intent
- 신호 기반 활성화/비활성화와 동시 활성 M 제어를 backlog 로 정규화.
#### Acceptance Criteria Delta
- Added: 활성화/거부/already_active/over-cap/경합 직렬화 5개 기준
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/runtime-flows.md
- Modules: application/intents.py, portfolio.py
- Tests: test_intent_concurrency.py, admission 테스트
#### Delivery Trace Delta
- Batches: none
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req. REQ-007 재정의 change-req·REQ-060(M) 의존.
#### Validation Plan
- FCFS/거부/over-cap/경합 단위·통합 테스트 green.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-020(confirmed, handoff 승인)과 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md (Register Approved) / Modules: 없음 / Tests: 없음
#### 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 / draft-batch.
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ AC 를 검증 기준으로 사용.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-028(+BAT-030 단일 경로·capacity_full e2e) — 모든 AC 가 release-candidate 배치 verification 의 evidence 와 연결됨(단위 367/PG 29/MQ 21 passed + run-the-app 자산 중심 e2e). Blocking Issues 없음.
@@ -1,219 +0,0 @@
# req-061: intent 계약 자산(portfolio_id) 키 통일 + 중복/무효 규칙
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 전략↔코어 intent 계약을 **코어 native 키인 `slot_id`** 로 통일한다(CHG-20260610-03, 사용자 결정으로 FR-7 의 portfolio_id 키를 slot_id 로 재정의). 자산 중심 영구 슬롯이라 universe 모든 자산에 슬롯이 선존재하므로 매수도 slot_id 로 지정 가능하다. 스냅샷 `slots[]` 가 계약의 1차 단위이며 portfolio_id 는 표시/자산 정체성으로 잔존(계약 키 아님). (dcy-020 FR-7 재정의/NFR-4)
## Requirement
- 매수·매도 intent 를 모두 **`slot_id`** 키로 식별한다. 매수 = 그 슬롯 활성화(`inactive→pending_buy`, symbol 은 슬롯의 `portfolio_id` 로 resolve), 매도 = 비활성화(`holding→pending_sell`). 매도는 이미 slot_id 계약(불변). **매수는 기존 portfolio_id 계약에서 slot_id 로 이동하되, 외부 전략 무중단을 위해 portfolio_id 를 레거시 dual-accept**(자산 중심 모드에서 portfolio_id → `find_slot_by_portfolio` 로 슬롯 매핑); portfolio_id 매수 계약 완전 폐기는 BAT-δ. 중복/무효 신호 규칙: 이미 활성(`pending_buy`/`holding`/`pending_sell`)인 슬롯에 매수 → 멱등 거부(`already_active`); 보유(holding) 아닌 슬롯에 매도 → 거부(`not_holding`). `intent_id` 멱등(intent_log) 보존.
## Acceptance Criteria
1. Given 매수 신호, When `slot_id` 로 제출(자산 중심 모드), Then 그 슬롯이 `inactive→pending_buy` 로 활성화되고 symbol 은 슬롯의 portfolio_id 로 resolve 된다.
2. Given 이미 활성(pending_buy/holding/pending_sell)인 슬롯, When 매수, Then `already_active` 로 멱등 거부된다.
3. Given 보유(holding) 아닌 슬롯, When 매도, Then `not_holding`(또는 not-holding 사유)로 거부된다.
4. Given 레거시 매수(`portfolio_id`), When 제출, Then `find_slot_by_portfolio` 로 슬롯에 매핑되어 동일하게 처리된다(dual-accept, 무중단).
5. Given 같은 `intent_id` 재전송, When 처리, Then 슬롯 중복 전이 없이 최초 결정과 동일 응답(멱등).
6. Given 보유(holding) 슬롯, When **증액 매수 intent**(qty+price)를 제출, Then `holding→pending_buy` 로 추가 매수가 집행된다(dcy-021, 이미 active 라도 증액은 허용 — `already_active` 예외).
7. Given 보유 슬롯, When **부분 매도 intent**(qty+price)를 제출, Then 명시 수량으로 `holding→pending_sell` 집행된다(집행 수량 정책 REQ-062). 사이징 intent 는 명령형(전략이 qty+price 계산·전송), core 는 target/의도 수량을 저장·추적하지 않는다.
## Impacted Area
- Docs: docs/runtime-flows.md(intent 흐름), docs/interface-contract.md(메시지 계약)
- Modules: trex_core/application/intents.py, 메시지 핸들러/스키마
- Tests: tests/application/test_messaging_intent_consumer.py, tests/application/test_*intent*.py
## Notes
- 기존 REQ-007(intent API) 재정의 change-req 동반(sell-by-slot_id 폐기·자산 키 통일). NFR-4(전략 계약 호환): 외부 전략 모듈 동시 전환 또는 한시적 하위호환 — REQ/배치 cutover 에서 명시.
- 출처: dcy-020 FR-7, NFR-4.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-020 FR-7/NFR-4 로부터 최초 생성(Proposed). intent 자산(portfolio_id) 키 통일 + sell-by-slot_id 폐기 + already_active/not_holding.
#### Intent
- 매수·매도 신호를 자산 키로 통일하는 계약 변경을 backlog 정규화.
#### Acceptance Criteria Delta
- Added: 매도 자산키/already_active/not_holding/intent_id 멱등 4개 기준
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/runtime-flows.md, docs/interface-contract.md
- Modules: application/intents.py, 메시지 핸들러/스키마
- Tests: test_messaging_intent_consumer.py, intent 테스트
#### Delivery Trace Delta
- Batches: none
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no (REQ-007 재정의 change-req 로 기존 폐기)
- Status Recommendation: keep-current
- Follow-up Action: confirm-req. NFR-4 외부 전략 계약 cutover 명시.
#### Validation Plan
- 자산 키 매도/거부 규칙/멱등 단위·통합 테스트 green.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-020(confirmed, handoff 승인)과 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md (Register Approved) / Modules: 없음 / Tests: 없음
#### 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 / draft-batch.
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ AC 를 검증 기준으로 사용.
### CHG-20260610-03
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-020 FR-7 재정의 — 사용자 결정) intent 계약 키를 `portfolio_id` → **`slot_id`**(buy·sell 공통)로 재정의. 근거: trex-core 는 슬롯 기준 관리이고 스냅샷이 `slots[]` 를 단위로 주므로 코어 native 키(slot_id)로 round-trip 하는 것이 일관적이며 portfolio-hub 식별 체계의 계약 누수를 막는다. 자산 영구 슬롯이라 매수도 slot_id 로 지정 가능(슬롯 선존재). 매도는 이미 slot_id(불변); 매수만 portfolio_id→slot_id 이동(레거시 portfolio_id dual-accept, 폐기 BAT-δ). Approved 유지(사용자 재승인).
#### Intent
- 전략↔코어 계약을 슬롯 native 키로 통일.
#### Acceptance Criteria Delta
- Updated: AC 전체를 slot_id 기준으로 재작성(AC-1 매수 slot_id 활성화·symbol resolve, AC-4 portfolio_id dual-accept 추가).
- Removed: "매도 portfolio_id 제출" 전제(매도는 slot_id 유지).
#### Impacted Area Delta
- Modules: application/intents.py(BuyIntent slot_id·_admit_buy_asset_centric), 메시지 핸들러 buy 파싱, runtime/cli.py enter
- Tests: test_asset_centric_admission(slot_id), 메시지 consumer
- 연동: REQ-059(자산 admission)·REQ-007(buy intent) — buy 키 slot_id 로 정합(BAT-029).
#### Delivery Trace Delta
- Batches: BAT-029
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-029)
- Existing Implementation Invalidated: BAT-028 의 portfolio_id 매수 admission 은 dual-accept 로 흡수(레거시 경로 유지) — 무효화 아님
- Status Recommendation: keep-current (Approved, 사용자 재승인)
- Follow-up Action: BAT-029 구현. REQ-059/007 정합.
#### Validation Plan
- BAT-029: 매수 slot_id 활성화 / portfolio_id dual-accept / already_active / 매도 slot_id / 멱등 단위·통합.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-029(+BAT-030 trading_date 제거·e2e slot_id 매수) — 모든 AC 가 release-candidate 배치 verification 의 evidence 와 연결됨(단위 367/PG 29/MQ 21 passed + run-the-app 자산 중심 e2e). Blocking Issues 없음.
### CHG-20260610-04
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징) 반영: intent 계약에 **사이징 intent**(보유 슬롯 증액 매수 / 부분 매도)를 추가. 명령형 — 전략이 스냅샷 cash+quantity 로 **정수 주식 수(qty)+가격(price)** 을 계산해 보내고, core 는 실행만 한다(target/의도 수량 미저장·미추적). 증액은 이미 active 슬롯에도 허용(전량 매수 활성화의 `already_active` 와 구분).
#### Intent
- 보유 자산의 수량 조정을 기존 명령형 buy/sell 계약의 최소 additive 확장으로 표현(dcy-021 OQ-1/OQ-2 확정).
#### Acceptance Criteria Delta
- Added: AC-6(증액 매수 intent → holding→pending_buy), AC-7(부분 매도 intent qty → holding→pending_sell, 명령형·core 미저장)
- Updated: 없음(기존 활성/청산 계약 보존)
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/interface-contract.md(사이징 intent payload), docs/runtime-flows.md
- Modules: trex_core/application/intents.py(증액/부분 매도 admission), messaging_handlers.py(payload)
- Tests: tests/application/test_*intent*.py, 사이징 admission 신규
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (신규 사이징 계약 경로)
- Existing Implementation Invalidated: no (기존 slot_id 매수·전량 매도 계약 보존, additive)
- Status Recommendation: revert-to-approved (사이징 계약 미구현 — dcy-021 배치에서 구현·검증)
- Follow-up Action: dcy-021 배치 구현 후 Implemented 복귀.
#### Validation Plan
- 증액 매수·부분 매도 intent admission 단위 + end-to-end(REQ-066). 명령형·멱등·core 미저장 검증.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
### CHG-20260610-05
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-022 실행 정책) buy/sell intent 계약에 **실행 정책 필드**(optional `timeout_sec`·`slippage_pct`) 추가. `timeout_sec`: 주문 유효시간(N초 미체결 시 core 가 cancel_order 송신·롤백). `slippage_pct`: 체결 보호밴드(entry_price 기준 ±pct, entry_price 없으면 무시). 두 필드 모두 optional — 미지정 시 기존 경로 하위호환. `timeout_sec` 미지정 시 운영자 per-instance config(`default_order_timeout_sec`) 적용(미설정=OFF=무기한). Implemented → Approved 되돌림(신규 계약 필드 미구현, BAT-032 에서 재구현·confirm-req-implemented 복귀).
#### Intent
- 전략이 intent 제출 시 실행 정책을 함께 실어 미체결 고착을 원천 차단한다(dcy-022 FR-1).
#### Acceptance Criteria Delta
- Added:
- AC-8: buy/sell intent 에 optional `timeout_sec` 포함 시 core 가 파싱해 슬롯에 기록하고 집행 루프가 timeout 초과 시 cancel_order 를 송신한다.
- AC-9: buy/sell intent 에 optional `slippage_pct` 포함 시 `entry_price` 기준 실효 지정가를 산출해 주문을 제출한다(`entry_price` 없으면 무시).
- AC-10: `timeout_sec`/`slippage_pct` 미지정 시 기존 매수/매도 경로와 동일하게 처리된다(하위호환).
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/interface-contract.md(payload 확장)
- Modules: BuyIntent/SellIntent(+timeout_sec/slippage_pct), messaging_handlers.py(파싱), intents.py(transit 전달), slot models(+timeout_sec/slippage_pct 컬럼), execution.py(dispatch slippage·poll timeout)
- Tests: timeout/slippage 파싱·집행 단위, 하위호환 회귀
#### Delivery Trace Delta
- Batches: BAT-032
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (신규 계약 필드 경로)
- Existing Implementation Invalidated: no (기존 slot_id 매수·매도 계약 보존, additive)
- Status Recommendation: revert-to-approved (신규 필드 미구현 — BAT-032 에서 구현·검증)
- Follow-up Action: BAT-032 구현 후 Implemented 복귀.
#### Validation Plan
- timeout_sec/slippage_pct 파싱·슬롯 기록·집행 단위. 미지정 회귀. end-to-end timeout 취소 시나리오.
### CHG-20260611-IMPL
- Date: 2026-06-11
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-032(release-candidate) verification — 실행 정책(timeout_sec·slippage_pct) 계약·집행·운영자 cancel 백스톱 전 AC acceptance mapping 존재(신규 71 tests), 단위 425 passed 회귀 없음, baseline 2문서 수동 확인(M5). Blocking Issues 없음.
@@ -1,135 +0,0 @@
# req-063: 운영자 표면 단일화 — slots = 자산 포지션 단일 뷰
- Status: Implemented
- Type: Interface
- Priority: Medium
- Owner: project maintainers
## Intent
- universe(자산 리스트)와 slots(슬롯 상태)의 이중 표면(BAT-022 혼동 원인)을 해소하기 위해, 슬롯=자산 1:1 모델에서 `trex-core slots` 가 자산 포지션을 단일 뷰로 제공한다. (dcy-020 FR-8)
## Requirement
- `trex-core slots` 가 자산 슬롯(슬롯=자산)을 단일 뷰로 표시한다: `portfolio_id`/symbol/status(inactive/pending_buy/holding/pending_sell/error)/holding 수량 미러/`universe_detached`(tombstone)/`retired`. universe(자산 리스트)와 slots(자산 포지션)는 같은 자산 집합 위의 view 가 되며, 데몬 RPC(스냅샷)로 통일한다(직접 DB 쓰기 없음). 운영자는 자산별 포지션·활성 여부·tombstone 여부를 한 표면에서 본다.
## Acceptance Criteria
1. Given universe N개 자산, When `trex-core slots`, Then N개 자산 슬롯이 status·holding·tombstone 표시와 함께 단일 뷰로 출력된다.
2. Given tombstone(universe-detached holding) 슬롯, When `slots`, Then `universe_detached` 로 구분 표시된다.
3. Given `--status` 필터, When 조회, Then 자산 슬롯 status 로 필터된다.
## Impacted Area
- Docs: docs/runtime-flows.md, docs/interface-contract.md(snapshot envelope slots[])
- Modules: trex_core/runtime/cli.py, snapshot envelope 빌더
- Tests: tests/application/test_messaging_snapshot_consumer.py, CLI 테스트
## Notes
- 기존 REQ-032(운영자 CLI)·REQ-028/029(snapshot envelope) 와 연계 change-req. BAT-022 슬롯 가시화의 자산 중심 재정의.
- 출처: dcy-020 FR-8.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-020 FR-8 로부터 최초 생성(Proposed). `trex-core slots` = 자산 포지션 단일 뷰(universe↔slots 이중 표면 해소).
#### Intent
- 운영 관측 단일화(자산별 포지션·활성·tombstone)를 backlog 정규화.
#### Acceptance Criteria Delta
- Added: 단일 뷰 출력/tombstone 표시/status 필터 3개 기준
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/runtime-flows.md, docs/interface-contract.md
- Modules: runtime/cli.py, snapshot envelope 빌더
- Tests: test_messaging_snapshot_consumer.py, CLI 테스트
#### Delivery Trace Delta
- Batches: none
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no (REQ-032/028/029 연계 change-req)
- Status Recommendation: keep-current
- Follow-up Action: confirm-req.
#### Validation Plan
- slots 단일 뷰 출력·tombstone·필터 단위테스트 green.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-020(confirmed, handoff 승인)과 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md (Register Approved) / Modules: 없음 / Tests: 없음
#### 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 / draft-batch.
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ AC 를 검증 기준으로 사용.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-029(+BAT-030 trading_date 키 제거·buyable=inactive 필터) — 모든 AC 가 release-candidate 배치 verification 의 evidence 와 연결됨(단위 367/PG 29/MQ 21 passed + run-the-app 자산 중심 e2e). Blocking Issues 없음.
### CHG-20260611-01
- Date: 2026-06-11
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-025) 운영자 CLI(`trex-core slots`/`universe`)의 데몬 RPC 를 `trex.snapshot.req` → **`trex.slots.req`**(REQ-073)로 교체한다. 운영자 조회는 **`spy=true`** 로 발신(기존 `actor="operator"`/`touch_watchdog=false` 대체 — 비침습 유지). `--status` 필터는 새 `filter`(status 단일: all/inactive/pending/holding/error)로 매핑. 출력 행은 REQ-074 병합 스키마(asset_quantity+qty 미러+warned, cash_balance+cash_estimated, watchdog nested, paused) 사용. universe↔slots 단일 표면 의도(본 REQ Intent)는 새 표면에서 완성된다.
#### Intent
- 운영자 단일 뷰를 새 read 표면 위로 이전(비침습·필터·병합 행 유지).
#### Acceptance Criteria Delta
- Updated:
- AC-1~3 의 underlying RPC 가 `trex.slots.req` 이고, 조회는 `spy=true`(워치독 무터치)로 수행된다. `--status` → `filter` 매핑(buyable→inactive 동치 포함).
- Added:
- AC-4: `slots` 출력 행에 REQ-074 병합 필드(asset_quantity/qty/warned/cash_balance/cash_estimated/watchdog/paused)가 표시된다.
- Removed: none
#### Impacted Area Delta
- Modules: trex_core/runtime/cli.py(`_cmd_slots`/`_cmd_universe` — 새 큐·spy·filter·행 필드)
- Docs: docs/interface-contract.md CLI↔RPC 매핑(REQ-075)
- Tests: tests/runtime/test_cli_operator.py(새 payload·행 표시)
#### Delivery Trace Delta
- Batches: 신규 batch(REQ-073/074/075 와 동일 배치, dcy-025)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (신규 batch 에서 갱신 AC 검증)
- Existing Implementation Invalidated: yes (snapshot RPC 기반 CLI evidence 가 표면 교체로 무효화)
- Status Recommendation: Implemented → Approved (batch 재구현·재검증 후 복귀)
- Follow-up Action: draft-batch → 구현/검증 → confirm-req-implemented
#### Validation Plan
- 신규 BAT: CLI payload(`trex.slots.req`/spy=true/filter 매핑) 단위 + 행 필드 표시 단위 + buyable→inactive 동치 회귀.
@@ -1,95 +0,0 @@
# req-066: 보유 자산 포지션 사이징 — 증액·부분 감액 (수량/avg_price 재계산)
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- dcy-021: 자산 중심 영구 슬롯(dcy-020)의 "수량 가변 전제" 위에, 보유(holding) 자산 슬롯의 **수량을 holding 을 유지한 채 조정**(증액·부분 감액)하는 end-to-end 동작과 수량/avg_price 재계산 규칙을 정의한다. 전량 청산만 종료(inactive)한다. (issue #1, dcy-020 OQ-4 후속)
## Requirement
- 보유 슬롯 **증액**: 같은 슬롯이 `HOLDING→PENDING_BUY→HOLDING` 로 순환하며 **실제 체결분만큼** 보유 수량이 누적되고, `avg_price = (기존수량×기존평단 + 체결수량×체결가) / 총수량` 가중평균으로 재계산된다(REQ-057 전이·REQ-061 intent 계약 사용).
- 보유 슬롯 **부분 감액**: 같은 슬롯이 `HOLDING→PENDING_SELL` 로 전이하고, 체결 후 브로커 정본 수량을 반영해 잔량>0 이면 `HOLDING`(**cost basis=avg_price 유지**), 잔량 0(전량)이면 `INACTIVE` 로 종료한다(집행 수량 정책은 REQ-062).
- **부분 체결**: 증액·감액 모두 **실제 체결분만** 슬롯 수량/원장에 반영하고, 미체결 잔량은 core 가 추적·재시도하지 않는다(재수렴은 전략이 스냅샷 기준으로 재발행). 실현손익은 core 가 계산하지 않고 ledger/portfolio-hub 가 소유한다.
- 활성 자산 수(M 캡 대상, REQ-059)는 증액으로 증가하지 않는다(이미 active 인 자산의 수량 변경).
- 기존 활성/전량 청산/admission 경로는 무회귀(additive 확장).
## Acceptance Criteria
1. Given 100주 holding(avg 1000) 슬롯, When 50주(@1200) 증액 매수가 전량 체결, Then 슬롯은 holding 유지·수량 150·avg_price = (100×1000+50×1200)/150 = 1066.67(반올림 규칙 적용)로 재계산된다.
2. Given 100주 holding 슬롯, When 60주 부분 매도가 전량 체결, Then 슬롯은 holding 유지·수량 40·avg_price(cost basis) 불변이다.
3. Given 100주 holding 슬롯, When 전량(또는 잔고 이상) 매도가 체결, Then 슬롯은 INACTIVE 로 종료되고 점유 필드가 초기화된다.
4. Given 증액/부분 매도 주문이 일부만 체결(예: 50 중 30), When 집행, Then 실제 체결분(30)만 슬롯 수량·ledger 에 반영되고 미체결 잔량은 추적되지 않는다.
5. Given dcy-020 기존 경로(신규 활성·전량 청산·admission·M 캡), When 사이징 도입 후 회귀, Then 무회귀(green)다.
## Impacted Area
- Docs: docs/data-model.md(수량 가변·avg_price 재계산), docs/runtime-flows.md(사이징 흐름) — REQ-067 에서 정합
- Modules: trex_core/domain/slot/service.py(qty 누적·avg_price 가중평균·cost basis 유지), trex_core/domain/slot/state.py(REQ-057 change-req), trex_core/application/execution.py(부분 체결 반영), trex_core/application/intents.py(REQ-061 change-req)
- Tests: 증액 avg_price 가중평균, 부분 매도 잔량/전량 분기, 부분 체결 실제만 반영, 회귀 가드
## Notes
- 계약 형태(명령형 qty+price)는 dcy-021 OQ-1, 단위(정수 주식 수+가격)는 OQ-2, avg_price/cost basis/실현손익은 OQ-3, 트리거(intent 당 1회)는 OQ-4 확정.
- 본 REQ 는 사이징의 **도메인 수량/avg_price 의미·end-to-end 동작**을 소유한다. 상태 전이(REQ-057)·intent 계약(REQ-061)·집행 매도 수량(REQ-062)의 계약 변경은 각 change-req 로 기록한다.
- 반올림 규칙: avg_price 는 기존 슬롯 `avg_price`(float/NUMERIC) 정밀도를 따른다(별도 통화 반올림 정책 없음). 주식 수는 정수.
- 출처: dcy-021 FR-1/FR-2 + NFR-1/NFR-2.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-021(포지션 사이징, issue #1)로부터 최초 생성(Proposed). 보유 슬롯 증액·부분 감액 end-to-end + 수량/avg_price 재계산.
#### Intent
- 자산 영구 슬롯의 수량 가변 전제 위에 보유 포지션 리사이즈를 정규화.
#### Acceptance Criteria Delta
- Added: 증액 가중평균/부분 감액 잔량·전량/부분 체결 실제만/무회귀 5개 기준
- Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: data-model/runtime-flows(REQ-067)
- Modules: domain/slot service·state(REQ-057), application/execution·intents(REQ-061/062)
- Tests: 증액·부분 매도·부분 체결·회귀
#### Delivery Trace Delta
- Batches: dcy-021 신규 배치(예정) / Releases: none
#### Revalidation Impact
- Reverification Needed: yes / Existing Implementation Invalidated: no / Status Recommendation: keep-current / Follow-up Action: confirm-req → dcy-021 배치.
#### Validation Plan
- 단위(avg_price 가중평균·잔량 분기·부분 체결) + run-the-app end-to-end.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-021(confirmed, handoff 승인, OQ-1~4 Answered)과 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md(Register Approved) / Modules: 없음 / Tests: 없음
#### 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 → draft-batch.
#### Validation Plan
- 승인 후 dcy-021 배치 planning 에서 본 REQ AC 를 검증 기준으로 사용.
### CHG-20260610-IMPL
- Date: 2026-06-10
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-031(release-candidate) verification — 단위 378 / 통합 422 passed + run-the-app 사이징 e2e(증액 가중평균·부분 매도 잔량·전량 매도) green. Blocking Issues 없음.
@@ -1,97 +0,0 @@
# req-068: intent 실행 정책 계약 — timeout_sec + slippage_pct
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- buy/sell intent 계약에 **실행 정책 필드**(`timeout_sec`·`slippage_pct`)를 추가해 전략이 "어떻게 체결할지"를 함께 선언한다. core 는 수신 측 먼저 배포 가능(optional, 하위호환). (dcy-022 FR-1)
## Requirement
- buy/sell intent payload 에 optional 필드 추가: `timeout_sec`(주문 유효시간 — N초 미체결 시 core 가 cancel_order 송신·롤백) · `slippage_pct`(체결 보호밴드 — entry_price 기준 ±pct 실효 지정가). 두 필드 모두 optional — 미지정 시 기존 동작 하위호환(무기한 지정가/시장가). `timeout_sec` 미지정 시 per-instance TOML `default_order_timeout_sec`(opt-in, 미설정=OFF=무기한) 를 기본값으로 적용하고 per-intent 값이 override 한다. `slippage_pct` 기본값 없음(미지정=보호밴드 없음). core 수신 측 먼저 배포(누락 시 무시 — orb-v1 발신과 lockstep 불필요). deprecate 없음(전부 신규 optional 필드, 기존 계약 보존).
## Acceptance Criteria
1. Given buy intent 에 `timeout_sec=60` 포함, When core 수신, Then 슬롯에 `timeout_sec=60` 이 기록되어 집행 루프가 읽을 수 있다.
2. Given buy intent 에 `slippage_pct=0.1` 포함, When core 수신, Then 슬롯에 `slippage_pct=0.1` 이 기록되어 dispatch 시 실효 지정가 산출에 쓰인다.
3. Given `timeout_sec` 미지정 intent, When per-instance config `default_order_timeout_sec=120`, Then 슬롯에 `timeout_sec=120` 이 기록된다(config 기본값 적용).
4. Given `timeout_sec` 미지정 + config 미설정, When 수신, Then 슬롯 `timeout_sec` 이 None — 기존 무기한 동작과 동일(하위호환).
5. Given 기존 buy/sell intent(timeout/slippage 필드 없음), When 수신, Then 기존 경로와 byte-동등하게 처리된다(회귀 없음).
6. Given per-intent `timeout_sec` 와 config `default_order_timeout_sec` 둘 다 있음, When 수신, Then per-intent 값이 우선한다(override).
## Impacted Area
- Docs: docs/interface-contract.md(payload 확장)
- Modules: trex_core/application/intents.py(BuyIntent/SellIntent +timeout_sec/slippage_pct, IntentService +default_order_timeout_sec), trex_core/application/messaging_handlers.py(파싱), trex_core/domain/slot/models.py(+컬럼), trex_core/domain/slot/service.py(transit_slot 전달), trex_core/adapters/persistence/sql/012_add_execution_policy_fields.sql(DB)
- Config: DaemonInstanceConfig +default_order_timeout_sec
- Tests: 파싱·슬롯 기록·config 기본값·하위호환 단위
## Notes
- `timeout_sec` 는 코어-타이밍(N초 후 cancel_order 송신) 이며 IOC/FOK 등 네이티브 TIF 는 후속 주기(dcy-022 OQ-1).
- `slippage_pct` 는 `entry_price` 있을 때만 유효(OQ-2). 필드 역할: `entry_price`=기준·목표, `slippage_pct`=허용폭 → 실효 limit = entry_price*(1±pct). `timeout_sec` ≠ `forced_close_at`(포지션 만기 청산, REQ-037).
- 출처: dcy-022 FR-1, OQ-1/OQ-2/OQ-3/OQ-4.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-022 FR-1 로부터 최초 생성(Proposed). intent 실행 정책 계약(timeout_sec + slippage_pct) 신규 정의.
#### Intent
- 실행 정책 optional 필드 계약을 backlog 로 정규화.
#### Acceptance Criteria Delta
- Added: AC-1~6 (timeout_sec 기록·config 기본값·slippage_pct 기록·하위호환·override 6개 기준)
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/interface-contract.md
- Modules: BuyIntent/SellIntent, messaging_handlers, intents, slot models, service, migration 012
- Tests: 파싱·기록·config·하위호환 단위
#### Delivery Trace Delta
- Batches: none
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 BAT-032 편성.
#### Validation Plan
- timeout_sec/slippage_pct 파싱·슬롯 기록·config 기본값·하위호환 단위 테스트.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req). 필수 필드·구체 AC 충족, source dcy-022(confirmed, OQ-1~4 Answered, Freeze 승인)과 모순 없음.
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md (Register Approved) / Modules: 없음 / Tests: 없음
#### Delivery Trace Delta
- Batches: none / Releases: none
#### Revalidation Impact
- Reverification Needed: no / Existing Implementation Invalidated: no / Status Recommendation: keep-current / Follow-up Action: BAT-032 편성.
#### Validation Plan
- 승인 후 batch planning 에서 본 REQ AC 를 검증 기준으로 사용.
### CHG-20260611-IMPL
- Date: 2026-06-11
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-032(release-candidate) verification — 실행 정책(timeout_sec·slippage_pct) 계약·집행·운영자 cancel 백스톱 전 AC acceptance mapping 존재(신규 71 tests), 단위 425 passed 회귀 없음, baseline 2문서 수동 확인(M5). Blocking Issues 없음.
@@ -1,89 +0,0 @@
# req-071: 운영자 강제 취소 백스톱 — trex-core cancel <slot_id>
- Status: Implemented
- Type: Interface
- Priority: Medium
- Owner: project maintainers
## Intent
- timeout 미지정·취소 실패로 잔여 고착된 pending 슬롯을 운영자가 `trex-core cancel <slot_id>` 로 강제 취소·롤백할 수 있는 백스톱 경로를 제공한다. dcy-013 Alert-only 는 기본 유지(REQ-014 회귀 없음). (dcy-022 FR-5)
## Requirement
- CLI `trex-core cancel <slot_id>` 가 daemon 의 control RPC 채널(`trex.control.req`, REQ-043)에 `cancel_pending` 액션을 전송한다. daemon 수신 시: ① 슬롯이 `pending_buy`/`pending_sell` 이면 `broker.cancel_order` 를 송신하고, 다음 집행 루프 poll 에서 rollback 이 수렴한다(기존 is_terminal_reject/is_partial_cancel 경로). ② 슬롯이 HOLDING/INACTIVE 이면 `not_pending` 응답(무동작). ③ 슬롯 없으면 `slot_not_found`. 기존 kill_switch·pause 와 동일하게 운영자 단일-writer 준수(슬롯 직접 쓰기 없음 — cancel_order 만 송신, 상태 전이는 집행 루프).
## Acceptance Criteria
1. Given pending_buy 슬롯, When `trex-core cancel <slot_id>`, Then broker.cancel_order 가 호출되고 응답 `{status: "ok", slot_id: ...}` 를 반환한다.
2. Given cancel_order 가 호출된 후, When 집행 루프 다음 poll, Then 슬롯이 inactive/holding 으로 수렴한다(기존 is_terminal_reject/is_partial_cancel 경로 재사용).
3. Given pending_sell 슬롯, When `trex-core cancel <slot_id>`, Then pending_buy 와 동일하게 cancel_order 호출 + ok 응답.
4. Given holding/inactive 슬롯, When `cancel` 시도, Then `{status: "ignored", reason: "not_pending"}` 응답(무동작).
5. Given 존재하지 않는 slot_id, When `cancel` 시도, Then `{status: "error", reason: "slot_not_found"}`.
6. Given `--dry-run` 옵션, When `cancel`, Then cancel_order 미송신·응답 없이 대상 슬롯 정보만 출력(안전 확인).
## Impacted Area
- Docs: docs/runtime-flows.md(백스톱 취소 흐름)
- Modules: trex_core/runtime/cli.py(`cancel` 서브커맨드), trex_core/application/messaging_handlers.py(`cancel_pending` 액션 추가), execution.py / broker: cancel_order 호출 배선(daemon 제어 핸들러)
- Tests: tests/runtime/test_cli.py(cancel 서브커맨드), messaging_handlers cancel 단위
## Notes
- 운영자 처분은 백스톱(FR-5) — timeout 미지정 또는 cancel_order 실패 잔여 고착 대비. dcy-013 stale-alert(Alert-only) 는 회귀 없이 유지.
- 슬롯 직접 쓰기 없이 cancel_order 만 송신 → 집행 루프가 다음 poll 에서 전이. 단일 writer 불변식 유지(REQ-013 NFR-2).
- 출처: dcy-022 FR-5, NFR-1.
## Change Log
### CHG-20260610-01
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- dcy-022 FR-5 로부터 최초 생성(Proposed). 운영자 강제 취소 백스톱 CLI + control RPC 액션.
#### Intent
- 잔여 고착 pending 슬롯의 운영자 처분 경로를 backlog 로 정규화.
#### Acceptance Criteria Delta
- Added: AC-1~6 (pending 취소, 집행 루프 수렴, holding 무동작, not_found, dry-run 6개 기준)
#### Impacted Area Delta
- Modules: cli.py(cancel 서브커맨드), messaging_handlers(cancel_pending), daemon 제어 배선
- Tests: cli cancel, messaging cancel_pending 단위
#### Delivery Trace Delta
- Batches: none
#### Revalidation Impact
- Reverification Needed: no / Existing Implementation Invalidated: no / Status Recommendation: keep-current
#### Validation Plan
- cancel CLI 송신 + control RPC cancel_pending + 집행 루프 수렴 단위.
### CHG-20260610-02
- Date: 2026-06-10
- Author: Justin Ko
#### Change Summary
- Status Proposed → Approved (confirm-req).
#### Intent
- delivery input 으로 승격.
#### Acceptance Criteria Delta
- Added: 없음 / Updated: 없음 / Removed: 없음
#### Impacted Area Delta
- Docs: docs/srs/index.md (Register Approved)
#### Delivery Trace Delta
- Batches: none
#### Revalidation Impact
- Reverification Needed: no / Existing Implementation Invalidated: no / Status Recommendation: keep-current / Follow-up Action: BAT-032.
#### Validation Plan
- 승인 후 batch planning 에서 AC 검증 기준으로 사용.
### CHG-20260611-IMPL
- Date: 2026-06-11
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-032(release-candidate) verification — 실행 정책(timeout_sec·slippage_pct) 계약·집행·운영자 cancel 백스톱 전 AC acceptance mapping 존재(신규 71 tests), 단위 425 passed 회귀 없음, baseline 2문서 수동 확인(M5). Blocking Issues 없음.
@@ -1,206 +0,0 @@
# req-073: 전략 read 표면 — `trex.slots.req` RPC 계약 (filter/spy, snapshot.req 즉시 교체)
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 자산 중심 영구 슬롯 모델(dcy-020)에서 전략 read 표면을 슬롯 단일 테이블 RPC 로 재설계한다. `trex.snapshot.req`(view/assets[]/available_slots/watchdog[] 구조)를 폐기하고 `trex.slots.req` 하나로 교체해, 전략·운영자가 슬롯 테이블 하나로 universe·포지션·워치독을 읽게 한다. (dcy-025 FR-1/2/4/5/6)
## Requirement
- per-instance 큐 `trex.slots.req`(기존 큐명 규칙 — default 는 literal, 그 외 `.{instance_key}` 접미)를 신설하고 `trex.snapshot.req` 파이프라인(큐 선언·핸들러·legacy stub 경로)을 **같은 배포에서 제거**한다(즉시 교체, 과도기 없음 — 전략 모듈 lockstep cutover, dcy-025 OQ-1).
- 요청 payload: `{filter?: str, spy?: bool}`.
- `filter` 는 **status 단일 값**(상호배타) `{all, inactive, pending, holding, error}`. 미지정 시 `all`. `pending` = `pending_buy ∪ pending_sell`. `inactive` 판정 키는 슬롯 **status**(hub `asset_quantity` 아님). 파생 view(ALL/BUYABLE/HELD)와 `View` enum 은 폐기한다 — 매수 가능 목록 = `filter=inactive`.
- `spy=true` 면 워치독을 갱신하지 않는다(생존 신호 미발생 — 기존 `actor="operator"`/`touch_watchdog=false` 의 일반화, REQ-034 정합). 기본 `false`(holding 슬롯 워치독 터치).
- 응답 payload: `{slots: [...], available_slots: int|null, degraded: bool, reason, message}`. `assets[]`·`watchdog[]` 는 응답에 포함하지 않는다(워치독은 슬롯 행에 흡수 — REQ-074). `available_slots` 는 capacity hint — `max_active_slots` 미설정 시 `null`, 설정 시 `max(0, M − count_active)`. admission gate(`capacity_full`)는 별도로 유지되며 `available_slots` 가 이를 대체하지 않는다.
- `strategy_id`/`strategy_key`/`strategy_params`/`active_strategy_id` 는 본 표면에서 제외한다(요청 필터·응답 필드 모두 없음). 인스턴스=다중 전략이나 전략↔자산 할당 모델은 portfolio-hub 주도 후속 discovery — 확정 시 strategy 필드를 additive 로 재도입한다(dcy-025 OQ-4).
## Acceptance Criteria
1. Given 기동된 데몬, When 토폴로지 선언, Then `trex.slots.req`(per-instance) 큐가 존재하고 `trex.snapshot.req` 큐·핸들러·legacy stub 경로는 존재하지 않는다.
2. Given `{filter: "inactive"}` 요청, When 처리, Then status 가 `inactive` 인 슬롯 행만 반환된다(매수 가능 목록). `{filter: "pending"}` 은 `pending_buy ∪ pending_sell`, 미지정은 전체. 잘못된 filter 값은 `all` 또는 명시 거부로 일관 처리된다.
3. Given 응답 payload, When 키 집합 검사, Then `slots`/`available_slots`/`degraded`/`reason`/`message` 가 있고 `assets`·`watchdog`·strategy 계열 키는 없다.
4. Given `spy=true` 요청, When holding 슬롯 포함 조회, Then 워치독 `last_seen_at` 이 갱신되지 않는다. Given 기본(`spy` 미지정/false) 요청, Then holding 슬롯 워치독이 갱신된다(REQ-034 시맨틱 보존).
5. Given degraded 상태(universe fetch 실패 등), When 조회, Then `degraded=true` + `reason` 이 기존 REQ-028 신호 의미대로 운반된다.
6. Given `max_active_slots` 미설정 인스턴스, When 조회, Then `available_slots = null`. Given `max_active_slots = M` 설정 인스턴스 + 현재 active N, When 조회, Then `available_slots = max(0, M − N)`. `available_slots` 는 hint 이며 admission gate 를 대체하지 않는다.
## Impacted Area
- Docs: docs/interface-contract.md(snapshot→slots 계약 — REQ-075), docs/runtime-flows.md
- Modules: trex_core/adapters/messaging/topology.py(큐명), trex_core/application/messaging_handlers.py(slots 핸들러·snapshot 핸들러 제거; (CHG-20260612-02) status 필터 repo 위임 + watchdog 조회 재사용), trex_core/application/portfolio.py(`View` enum 폐기)
- Tests: tests/application/(slots 핸들러 filter/spy/응답 키 집합), tests/adapters/messaging/(토폴로지)
## Notes
- 즉시 교체(과도기 없음)이므로 전략 모듈(trex-orb-v1) 소비 측을 같은 전환점에 lockstep 변경해야 한다(dcy-025 R-1/NFR-3) — 배포 전 orb-v1 의 `trex.slots.req` 대응 준비 확인. dcy-020 cutover 선례와 동일하게 단일 전환점 관리.
- 행 스키마(자산·워치독·overlay 흡수, 정본 라벨)는 REQ-074 가 소유한다.
- 운영자 CLI 의 새 표면 사용은 REQ-063 change-req(CHG-20260611-01).
- 출처: dcy-025 FR-1/2/4/5/6, NFR-1(워치독 일관성)·NFR-3(cutover 안전)은 본 REQ AC/Notes 에 흡수.
## Change Log
### CHG-20260615-02
- Date: 2026-06-15
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented, BAT-042). 신규 AC-7(strategy_state 맵+occupancy_seq additive, batched 조립) 구현·검증 완료 — `tests/application/test_slots_handler_strategy_state.py` + 기존 `test_slots_handler.py` 회귀 green. 기존 AC-1~6 불변. 479 passed, ruff clean. Implemented 복귀.
### CHG-20260615-01
- Date: 2026-06-15
- Author: Justin Ko
#### Change Summary
- (change-req, dcy-028/issue #26 C-1) `trex.slots.req` 응답의 각 슬롯 행에 **strategy_state 맵**(`{<strategy_id>: {version,data,updated_at}}`, REQ-079/074)과 **occupancy_seq**(int, REQ-081)를 additive 로 추가한다. 핸들러는 반환 slot_id 들로 `StrategyStateStore`(REQ-079) batched 조회 후 group by 해 행별 맵으로 조립한다(추가 왕복 없음). 미보유 시 omit/`{}`. 기존 envelope 키(`slots`/`available_slots`/`degraded`/`reason`/`message`)·filter·spy·degraded 동작은 불변. AC-3 의 "strategy 계열 키 없음"은 dcy-025 가 제외한 strategy_* **reasoning** 필드(strategy_id/params/active)를 가리키며, 본 변경의 `strategy_state`(opaque 상태 맵)·`occupancy_seq`는 그와 구분되는 신규 additive 필드다.
#### Intent
- 전략 데몬이 슬롯과 함께 opaque strategy-state 를 추가 왕복 없이 read(C-1 piggyback). write 는 별도 RPC(REQ-080).
#### Acceptance Criteria Delta
- Added:
- AC-7(신규): 행에 `strategy_state` 맵(보유 시)과 `occupancy_seq` 가 포함되고, batched 조회로 조립되어 추가 RPC 왕복이 없다. strategy_* reasoning 필드 부재는 유지(AC-3 정합).
- Updated:
- AC-3: 응답 키 집합에서 제외되는 "strategy 계열"은 strategy_* reasoning 필드로 한정하고 `strategy_state`/`occupancy_seq` additive 필드는 허용함을 명확화.
- Removed: 없음
#### Impacted Area Delta
- Docs: docs/interface-contract.md(strategy_state·occupancy_seq 행 필드 — REQ-082)
- Modules: trex_core/application/messaging_handlers.py(slots 핸들러 strategy_state batched 조립), trex_core/application/portfolio.py(slot_to_dict)
- Tests: tests/application/(strategy_state 맵·occupancy_seq 행 조립, batched 조회)
#### Delivery Trace Delta
- Batches: BAT-035(dcy-025, 기존 Implemented 근거) 불변 — 신규 AC-7 은 dcy-028 batch 에서 구현·검증.
- Releases: REL-006(REQ-073 released) — 기존 계약 영향 없음(additive). 신규 필드는 REL-007 이후 dcy-028 batch.
#### Revalidation Impact
- Reverification Needed: yes (신규 AC-7 만)
- Existing Implementation Invalidated: no (기존 envelope/filter/spy 동작 보존)
- Status Recommendation: revert-to-approved (Implemented → Approved — 신규 additive AC 구현·검증 대기, 선례 REQ-002/006 CHG-20260612)
- Follow-up Action: confirm-req → dcy-028 batch 에서 REQ-079/080/081 과 함께 구현·검증 → confirm-req-implemented
#### Validation Plan
- slots 핸들러 테스트: 행에 strategy_state 맵(보유/미보유)·occupancy_seq 포함, batched 조회로 추가 왕복 없음, 기존 키 집합/filter/spy/degraded 회귀.
### CHG-20260612-02
- Date: 2026-06-12
- Author: Justin Ko
#### Change Summary
- (change-req, issue #25) slots RPC 핸들러(`make_slots_rpc_handler`)가 status 필터링을 `SlotRepository.list_slots(instance_key, status_filter=...)`(REQ-002/006) 에 위임해 per-request full scan + Python 필터를 제거한다. 추가로 watchdog 갱신용 holding 조회를, 응답 필터가 `all`/`holding` 이라 이미 holding 을 포함한 경우 fetch 결과를 재사용해 두 번째 커넥션을 생략한다(그 외 필터는 기존대로 `list_holding_slots`). **관찰 가능한 응답 계약(AC-1~6)은 불변** — filter 결과·키 집합·spy·degraded·available_slots 동일. AC delta 없음 → **Implemented 유지**(BAT-040 재검증).
#### Intent
- issue #25 (1) DB 레벨 status 필터 + (2) 두 쿼리 통합. orb-v1 이 매 cycle `{filter:"inactive"}` 로 요청할 때 200-slot 인스턴스에서 전 행 fetch 를 반복하던 비용 제거. 동작 보존 내부 최적화.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음 (AC-1~6 관찰 계약 불변, 핸들러 내부 위임만)
#### Impacted Area Delta
- Docs: 없음
- Modules: `trex_core/application/messaging_handlers.py`(`make_slots_rpc_handler` — `list_slots(status_filter)` 위임 + watchdog 조회 재사용)
- Tests: 기존 filter/spy/응답 키 집합 테스트 회귀 + status_filter 위임 확인
#### Delivery Trace Delta
- Batches: BAT-040 (예정, issue #25)
- Releases: none
#### Revalidation Impact
- Reverification Needed: yes (BAT-040 에서 filter/spy/degraded/available_slots 회귀)
- Existing Implementation Invalidated: no (관찰 응답 동일, 내부 위임만 — AC evidence 유효)
- Status Recommendation: **Implemented 유지**
- Follow-up Action: BAT-040 구현·검증으로 재확인(REQ-002/006 Implemented 복귀와 동일 배치)
#### Validation Plan
- BAT-040: 기존 `test_filter_*`/`test_spy_*`/`test_response_keys_*`/`test_available_slots_*` 회귀 green + status_filter 위임 경로(필터별 list_slots 인자) 확인.
### CHG-20260612-IMPL
- Date: 2026-06-12
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-037 (release-candidate) — AC-3 반전(available_slots 포함)·AC-6 신규(null/잔여/0 클램프) 16 tests passed, 423 전체 회귀 없음. Blocking Issues 없음.
### CHG-20260612-01
- Date: 2026-06-12
- Author: Justin Ko
#### Change Summary
- 응답 payload 에 `available_slots: int|null` 추가. orb-v1 이 매 cycle `{filter: "inactive"}` 로 슬롯을 요청할 때 capacity 가 차 있어도 intent 를 쏴야만 `capacity_full` 을 알 수 있던 문제 해소. `max_active_slots` 미설정 시 `null`(제한 없음), 설정 시 `max(0, M − active)` 정수.
#### Intent
- slots RPC 를 read 표면으로 유지하면서도 capacity 힌트를 제공해 불필요한 intent 왕복을 줄인다. admission gate(`capacity_full`)는 그대로 유지 — `available_slots` 는 hint 이며 orb-v1 이 skip 최적화에 사용한다.
#### Acceptance Criteria Delta
- Updated:
- AC-3: 응답 키 집합에서 `available_slots` 제외 → **포함**으로 반전. `assets`·`watchdog`·strategy 계열은 여전히 제외.
- Added:
- AC-6: `available_slots` 값 규칙 — `max_active_slots` 미설정 시 `null`, 설정 시 `max(0, M − count_active)`. 응답의 `available_slots` 는 hint 이며 admission gate 를 대체하지 않는다.
- Removed: 없음
#### Impacted Area Delta
- Modules:
- `trex_core/application/messaging_handlers.py` — `make_slots_rpc_handler` 응답에 `available_slots` 추가
- `trex_core/domain/slot/service.py` — `compute_slot_capacity` 호출 경로 확인
- Tests: `tests/application/test_slots_handler.py` — AC-3 키 집합 검사 및 AC-6 값 검증 갱신
- Docs: `docs/interface-contract.md` — 응답 스키마 반영 (REQ-075 소관)
#### Delivery Trace Delta
- Batches: BAT-035 (REQ-073 구현/확인) — AC-3 evidence 무효. 신규 batch 필요.
- Releases: REL-006 (배포 완료) — 운영 중 발견, 비파괴적 필드 추가(additive).
#### Revalidation Impact
- Reverification Needed: yes
- Existing Implementation Invalidated: yes (AC-3 — `available_slots` 부재 검증이 반전됨)
- Status Recommendation: Implemented → **Approved** (차기 batch 구현·검증 후 복귀)
- Follow-up Action: draft-batch → implementation → verification → confirm-req-implemented
#### Validation Plan
- 응답에 `available_slots` 키 존재 확인.
- `max_active_slots` 설정 인스턴스: active N 개일 때 `available_slots = M − N`, active ≥ M 이면 `0`.
- `max_active_slots` 미설정: `available_slots = null`.
- 기존 AC-1/2/4/5 회귀 없음 확인.
### CHG-20260611-01
- Date: 2026-06-11
- Author: Justin Ko
#### Change Summary
- dcy-025 FR-1/2/4/5/6 로부터 최초 생성(Proposed). `trex.slots.req` RPC 계약(filter=status 단일/spy 워치독 무터치/응답 slots+health 만/strategy 제외/즉시 교체).
#### Intent
- 전략 read 표면을 슬롯 단일 테이블로 재설계 — assets/available_slots/watchdog 병렬 구조와 파생 view 폐기.
#### Acceptance Criteria Delta
- Added:
- AC-1~5 신규
- Updated/Removed: none
#### Impacted Area Delta
- Docs: interface-contract/runtime-flows
- Modules: topology/messaging_handlers/portfolio(View 폐기)
- Tests: slots 핸들러/토폴로지
#### Delivery Trace Delta
- Batches: none(승인 후 draft-batch)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no(신규)
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current(Proposed)
- Follow-up Action: confirm-req
#### Validation Plan
- 신규 batch: 토폴로지 선언/제거 단위, filter·spy·응답 키 집합 단위, 워치독 터치/무터치, degraded 신호 회귀.
@@ -1,87 +0,0 @@
# req-080: `trex.slots.strategy_state.set` write RPC 계약 — occupancy_seq·version CAS
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 전략 데몬이 슬롯의 opaque strategy-state 를 write 하는 신규 RPC 계약을 정의한다. read 는 기존 `trex.slots.req`(REQ-073) 에 piggyback 하고(추가 왕복 없음), write 만 별도 RPC 로 분리해 `evaluate()` 순수성과 재시도 격리를 보존한다. (dcy-028 FR-2/OQ-2, issue #26 C-2)
## Requirement
- 신규 RPC `trex.slots.strategy_state.set` 를 기존 계약 패턴(direct reply-to + JSON + per-instance `queue_name({base}.{instance_key})`)으로 신설한다.
- 요청 payload: `{slot_id, strategy_id, expected_version:int, expected_occupancy_seq:int, data:str}`. `correlation_id = "{slot_id}:{strategy_id}:{expected_version}"`(멱등 키), delivery persistent.
- 성공 응답: `{ok:true, slot_id, strategy_id, version:<new>}`.
- 실패 응답 reason 전체 집합 = `{occupancy_changed, version_conflict, slot_inactive, state_too_large, bad_request}`:
- `occupancy_changed`: 슬롯 현재 occupancy_seq ≠ expected_occupancy_seq → `{ok:false, reason, occupancy_seq:<cur>}` (저장 안 함; 데몬 re-read 후 fresh restart).
- `version_conflict`: stored version ≠ expected_version → `{ok:false, reason, version:<cur>}`.
- `slot_inactive`: 슬롯 inactive/미존재 → `{ok:false, reason}` (저장 안 함).
- `state_too_large`: `data` 가 size cap(REQ-079/NFR) 초과 → `{ok:false, reason}` (저장 안 함).
- `bad_request:<detail>`: malformed payload(기존 intent 핸들러 패턴) → `{ok:false, reason}`.
- 핸들러는 REQ-079 `StrategyStateStore` 의 CAS 로 위임한다(저장 의미는 REQ-079 소유). `data` 는 opaque 로 전달하고 핸들러는 해석하지 않는다.
- 동일 `correlation_id` 재전송은 부작용 없음(멱등). 미인식 reason 에 대해 소비자 fail-closed 를 계약에 명시한다.
## Acceptance Criteria
1. Given 기동된 데몬, When 토폴로지 선언, Then `trex.slots.strategy_state.set`(per-instance) 큐가 존재하고 direct reply-to 로 응답한다.
2. Given 유효 요청(occupancy_seq·version 일치), When set, Then `{ok:true, version:<+1>}` 를 반환하고 저장된다.
3. Given occupancy_seq 불일치, Then `{ok:false, reason:"occupancy_changed", occupancy_seq:<cur>}`. Given version 불일치, Then `{ok:false, reason:"version_conflict", version:<cur>}`. 둘 다 저장되지 않는다.
4. Given inactive 슬롯, Then `{ok:false, reason:"slot_inactive"}`. Given size cap 초과, Then `{ok:false, reason:"state_too_large"}`. Given malformed payload, Then `{ok:false, reason:"bad_request:<detail>"}`.
5. Given 동일 `correlation_id` 재전송, When 처리, Then 부작용 없이 동일 결과가 반환된다.
6. Given 응답 reason, When 집합 검사, Then `{occupancy_changed, version_conflict, slot_inactive, state_too_large, bad_request}` 외 값이 없다.
## Impacted Area
- Docs: docs/interface-contract.md(strategy_state.set 계약 — REQ-082), docs/runtime-flows.md(write 흐름 — REQ-082)
- Modules: trex_core/adapters/messaging/topology.py(큐명), trex_core/application/messaging_handlers.py(신규 set 핸들러 — REQ-079 store 위임), trex_core/runtime/daemon.py(핸들러 와이어링)
- Tests: tests/application/(set 핸들러 6 reason 케이스 + 멱등), tests/adapters/messaging/(토폴로지)
## Notes
- 저장·CAS 의미는 REQ-079 가 소유한다 — 본 REQ 는 RPC 계약(요청/응답 shape, reason 운반, 멱등, 큐). 핸들러는 store 로 위임만 한다.
- read piggyback(REQ-073/074)과의 비대칭(read 무료/write 분리)은 dcy-028 OQ-2 의도. 사이클당 다중 슬롯 write 시 N개 set RPC — optional batch 변형은 v1 범위 밖 후속.
- 출처: dcy-028 FR-2(C-2), OQ-2(별도 RPC), reject reason 집합(trex-tsl #4705990067 답변 정합).
## Change Log
### CHG-20260615-03
- Date: 2026-06-15
- Author: Justin Ko
- Type: status
- Summary: Approved → Implemented (confirm-req-implemented). 근거: BAT-042 verification — `trex.slots.strategy_state.set` 큐(topology/rabbitmq declare) + `make_strategy_state_set_handler`(store 위임) + daemon consumer 스레드. AC-1~6 evidence: `tests/application/test_strategy_state_set_handler.py`(성공+5 reason+bad_request 2종+멱등+reason 집합). 479 passed, ruff clean. Blocking Issues 없음.
### CHG-20260615-02
- Date: 2026-06-15
- Author: Justin Ko
- Type: status
- Summary: Proposed → Approved (confirm-req). 필수 필드·구체 AC(6개) 충족, source dcy-028(OQ-2 정합) 일치, reject reason 집합 trex-tsl #4705990067 답변과 정합. blocker 없음.
### CHG-20260615-01
- Date: 2026-06-15
- Author: Justin Ko
#### Change Summary
- dcy-028 FR-2/OQ-2 로부터 최초 생성(Proposed). strategy_state.set write RPC 계약 + occupancy_seq·version CAS + reject reason 전체 집합.
#### Intent
- write 를 별도 RPC 로 분리해 evaluate 순수성·재시도 격리 보존, read 는 slots.req piggyback.
#### Acceptance Criteria Delta
- Added: 큐/성공/occupancy·version reject/inactive·size·bad_request/멱등/reason 집합 6개 기준
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: interface-contract.md, runtime-flows.md(REQ-082)
- Modules: topology.py, messaging_handlers.py, daemon.py
- Tests: set 핸들러 reason 케이스, 토폴로지
#### Delivery Trace Delta
- Batches: none (편성 예정)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch 편성(REQ-079/081/082 + REQ-073/074 CHG 동일 batch)
#### Validation Plan
- set 핸들러 단위 테스트(6 reason 케이스 + 멱등) + 토폴로지 선언 테스트로 RPC 계약 검증.
@@ -1,53 +0,0 @@
# req-086: 청산 reason+actor 동반 노출 — 안전망/전략 구분 가시화
- Status: Implemented
- Type: Interface
- Priority: Medium
- Owner: project maintainers
## Intent
- watchdog 소유 안전망 청산이 `reason=stop_loss`로만 보여 "전략의 진짜 손절"로 오해됐다(2026-06-15 064400). 신규 필드 없이, 기존 `reason`(조건축)과 기존 `actor`(주체축)를 **함께** 노출해 "안전망 자율청산(actor=safety_sell)"과 "전략 손절(actor=strategy)"을 운영자가 구분하게 한다. (dcy-029 FR-3, OQ-4=Option A)
## Requirement
- 기존 `reason` 어휘 `{stop_loss, take_profit, forced_close_at, market_close_liquidation}`(safety_sell 발화)와 전략 SellIntent의 reason을 계약으로 고정한다(신규 reason 값·신규 분류 필드 없음).
- 슬롯 전이 로그/이벤트/조회 뷰에 `reason`과 `actor`(`safety_sell`/`strategy`/`execution_loop`)를 **함께** 노출한다. 특히 주문 결과 로깅(REQ-085)·조회 CLI(REQ-088)·청산 로그에 actor가 reason과 같이 보이도록 한다.
- `docs/interface-contract.md`에 reason+actor 어휘와 "안전망 자율청산 family vs 전략 매도" 구분을 명문화한다.
- 기존 `slots.req`/이벤트/전이 기록의 기존 동작은 깨지 않는다(additive 노출).
## Acceptance Criteria
1. Given safety_sell이 stop_loss로 발화, When 전이/로그, Then `reason=stop_loss` + `actor=safety_sell`이 함께 기록된다.
2. Given 전략 SellIntent 매도, When 전이/로그, Then `actor`가 전략 주체로 기록되어 안전망과 구분된다.
3. Given 청산 로그 라인, When 운영자가 확인, Then reason만으로 오해되지 않도록 actor가 동반 노출된다.
4. Given safety_sell 4경로(stop_loss/take_profit/forced_close_at/market_close_liquidation), When 발화, Then 각 reason이 actor=safety_sell과 함께 정확히 기록된다.
5. Given 기존 reason 소비처(`_SELL_REJECT_RETRYABLE` 등), When 변경 적용, Then 기존 동작 회귀 없음(reason 값 불변).
6. Given interface-contract.md, When 갱신 후, Then reason+actor 어휘와 구분 규칙이 문서화돼 있다.
## Impacted Area
- Docs: docs/interface-contract.md(reason+actor 어휘), docs/runtime-flows.md(청산 분류 노출)
- Modules: trex_core/application/safety_sell.py·execution.py(로그에 actor 동반), 조회 뷰(REQ-088)·주문결과 로깅(REQ-085)과 협조. `slot_transition_log`는 이미 actor 기록.
- Tests: safety_sell 각 경로 reason·actor 단위, 노출 형식 단위
## Notes
- 코드 확인: `slot_transition_log`는 이미 `actor`를 기록하고, safety_sell은 이미 구분된 reason으로 발화한다. 본 REQ는 둘을 **함께 노출**(로그/뷰/계약 문서)하는 가시화가 핵심이며 신규 필드·신규 reason 값은 만들지 않는다(dcy-029 OQ-4 Option A).
- 출처: dcy-029 FR-3, OQ-4.
## Change Log
### CHG-20260616-01
- Date: 2026-06-16
- Author: Justin Ko
#### Change Summary
- dcy-029 FR-3로부터 최초 생성(Proposed).
### CHG-20260616-02
- Date: 2026-06-16
- Author: Justin Ko
- Type: status
- Summary: Proposed → **Approved** (confirm-req). 필수 필드·구체 AC 충족, source dcy-029(confirmed, Open OQ 0) 정합. dcy-029 P0/P1 batch 편성 예정.
### CHG-20260616-IMPL
- Date: 2026-06-16
- Author: Justin Ko
- Type: status
- Summary: Approved → **Implemented** (confirm-req-implemented, BAT-046 release-candidate, dcy-029 P1). 근거: 단위/문서 AC 매핑(REQ-086 reason+actor 로그·interface-contract; REQ-088 operator_report 집계·net PnL·KST 경계·CLI report; REQ-089 docs/operations.md 4영역; REQ-090 runtime-flows·project-structure 정합). 14 passed(report+safety_sell), 전체 537 passed/47 skipped 회귀 0, ruff clean. report direct-DB·Loki 실 적재는 release 운영 검증 위임. Blocking Issues 없음.
@@ -1,57 +0,0 @@
# req-088: 운영 조회 CLI — 보유·오늘 체결·실현 PnL·대기 주문
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: project maintainers
## Intent
- 일일 실현 PnL을 `ledger_outbox`에서 수기 계산해야 했다. 운영자가 단일 CLI 명령으로 현재 보유·오늘 체결·오늘 실현 PnL(수수료·세금 반영)·대기 주문을 조회해 일일 리포트 자동화의 기반을 만든다. (dcy-029 FR-5, OQ-1=CLI, RPC 없음)
## Requirement
- 운영자 CLI(`trex_core/runtime/cli.py`)에 신규 서브커맨드(예: `report` 또는 `pnl`)를 추가해 다음을 출력한다:
- **현재 보유**: holding 슬롯의 symbol/portfolio_id/qty/avg_price.
- **오늘 체결**: 당일(trading_date, KST 경계) 체결 건수/내역.
- **오늘 실현 PnL**: 수수료·세금 반영(BAT-038 정책과 동일 계산), `ledger_outbox`/체결 기록을 단일 권위 출처로 집계.
- **대기 주문**: pending_* 슬롯.
- 조회는 **DB-backed 시점 집계**다. 신규 RabbitMQ RPC는 추가하지 않는다(dcy-029 OQ-1). 데몬 미경유로 DB를 직접 읽거나 기존 read 경로를 재사용한다.
- 청산/체결 항목에 reason+actor(REQ-086)를 함께 보여 안전망/전략 구분이 되게 한다.
- 출력은 사람용 표/요약 + 가능하면 머신 파싱용(예: `--json`) 형태를 고려한다(자동화 기반).
## Acceptance Criteria
1. Given holding 슬롯 존재, When `report` 실행, Then 보유 symbol/qty/avg_price가 출력된다.
2. Given 당일 체결 N건, When 실행, Then 오늘 체결 건수/내역이 출력된다.
3. Given 당일 매도 체결, When 실행, Then 실현 PnL이 수수료·세금 반영 값으로 출력되고 `ledger_outbox` 직접 집계와 일치한다.
4. Given pending_* 슬롯, When 실행, Then 대기 주문이 출력된다.
5. Given "오늘" 경계, When trading_date(KST) 기준, Then 전일 체결은 오늘 집계에서 제외된다.
6. Given 신규 표면, When 실행, Then 신규 RabbitMQ RPC 없이 동작한다(CLI/DB-backed, OQ-1).
## Impacted Area
- Docs: docs/runtime-flows.md(운영자 CLI 조회 흐름), docs/operations.md(사용법 — REQ-089)
- Modules: trex_core/runtime/cli.py(신규 서브커맨드), PnL 집계 read(신규 헬퍼 — `ledger_outbox`/체결 집계), 기존 slot read 재사용
- Tests: 집계 함수 단위(수수료·세금·trading_date 경계), CLI 서브커맨드 단위
## Notes
- PnL 계산은 BAT-038(매도 증권거래세+수수료) 정책을 단일 출처로 재사용(dcy-029 NFR-3/A-3). 부분 정산·재시도 중 outbox 상태는 집계 시점 기준으로 명시.
- 출처: dcy-029 FR-5, OQ-1.
## Change Log
### CHG-20260616-01
- Date: 2026-06-16
- Author: Justin Ko
#### Change Summary
- dcy-029 FR-5로부터 최초 생성(Proposed).
### CHG-20260616-02
- Date: 2026-06-16
- Author: Justin Ko
- Type: status
- Summary: Proposed → **Approved** (confirm-req). 필수 필드·구체 AC 충족, source dcy-029(confirmed, Open OQ 0) 정합. dcy-029 P0/P1 batch 편성 예정.
### CHG-20260616-IMPL
- Date: 2026-06-16
- Author: Justin Ko
- Type: status
- Summary: Approved → **Implemented** (confirm-req-implemented, BAT-046 release-candidate, dcy-029 P1). 근거: 단위/문서 AC 매핑(REQ-086 reason+actor 로그·interface-contract; REQ-088 operator_report 집계·net PnL·KST 경계·CLI report; REQ-089 docs/operations.md 4영역; REQ-090 runtime-flows·project-structure 정합). 14 passed(report+safety_sell), 전체 537 passed/47 skipped 회귀 0, ruff clean. report direct-DB·Loki 실 적재는 release 운영 검증 위임. Blocking Issues 없음.
@@ -1,99 +0,0 @@
# req-098: 알람 envelope wire 계약 정의
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: trex-core-dev
## Intent
- 제품군 모든 모듈(core/orb/tsl/kdh)이 알람을 발신할 때 사용할 표준 메시지 envelope 스키마를 trex-core가 wire 계약으로 정의하고 `docs/interface-contract.md`에 명시한다.
- 이 계약은 trex-notifier가 알람을 수집·분류할 때의 파싱 기준이 되며, 다른 모듈 repo(orb/tsl/kdh)와 trex-notifier가 이 문서를 단일 출처(source of truth)로 참조한다.
- 기존 wire 계약(slots RPC/trex.events/trex.control.req)은 일절 변경하지 않는다.
## Requirement
- trex-core는 알람 envelope의 표준 JSON 스키마를 아래 필드로 정의하고, `docs/interface-contract.md`에 신규 섹션 `Interface: trex.alerts (알람 채널, dcy-033)`으로 버전드 명시해야 한다.
- `source` :: str — 알람 발신 모듈 식별자 (예: `"trex-core"`, `"trex-orb-v1"`, `"trex-tsl-v1"`, `"kis-data-hub"`)
- `severity` :: `"critical"` | `"warn"` | `"info"` — 등급 (소문자 리터럴)
- `code` :: str — 알람 식별 코드 (예: `"kill_switch_fired"`, `"fill_price_unresolvable"`)
- `title` :: str — 사람이 읽는 1행 요약
- `fields` :: dict[str, any] — 선택 구조화 컨텍스트 (예: `{"slot_id": "...", "symbol": "..."}`)
- `occurred_at` :: ISO-8601 datetime string (UTC 또는 KST+09:00 offset 포함)
- `schema_version` :: str — 현재 값 `"1"` (semver 주 버전 문자열; 소비자는 미인식 버전 무시·경고)
- 계약 섹션에 routing key 규약(`alarm.{severity}.{source}`)과 exchange 이름(`trex.alerts`)을 함께 기술한다.
- 이 스키마를 변경(필드 추가 포함)하면 `schema_version`을 올리거나 additive 변경 여부를 명시하도록 Update Trigger를 문서에 포함한다.
## Acceptance Criteria
1. Given `docs/interface-contract.md`에 `Interface: trex.alerts (알람 채널, dcy-033)` 섹션이 존재하지 않을 때, When REQ-098 구현을 완료하면, Then 해당 섹션이 위 7개 필드(source/severity/code/title/fields/occurred_at/schema_version)의 JSON 스키마 명세를 포함해야 한다.
2. Given 섹션이 추가됐을 때, When 명세를 검토하면, Then `severity` 값이 `"critical"` | `"warn"` | `"info"` 세 리터럴로 제한되고, `schema_version="1"`이 현재 버전으로 명시되어야 한다.
3. Given 명세가 추가됐을 때, When 기존 interface-contract.md의 다른 섹션(slots RPC/trex.events/trex.control.req/strategy_state)을 검토하면, Then 기존 섹션의 내용이 변경되지 않아야 한다(가산·격리 불변 — diff는 신규 섹션 추가뿐).
4. Given envelope 스키마 명세가 완성됐을 때, When routing key 규약을 확인하면, Then `alarm.{severity}.{source}` 형식이 명시되어야 한다.
5. Given 명세가 추가됐을 때, When Update Trigger를 확인하면, Then 알람 envelope 스키마 변경(breaking/additive 모두) 시 이 문서를 갱신해야 한다는 트리거가 포함되어야 한다.
6. Given 다른 모듈 repo(orb/tsl/kdh) 개발자가 알람 emitter를 구현할 때, When `docs/interface-contract.md`의 알람 계약 섹션을 읽으면, Then 자체 `trex_core` import 없이 envelope 구성에 필요한 모든 정보(필드·타입·필수 여부·schema_version·routing key)를 얻을 수 있어야 한다.
## Impacted Area
- Docs: `docs/interface-contract.md` — 알람 채널 신규 섹션 추가(기존 섹션 불변)
- Modules: 코드 변경 없음(이 REQ는 문서 계약만; emitter 구현은 REQ-100)
- Tests: `docs/interface-contract.md` diff가 기존 섹션 변경 0임을 확인하는 검증(batch verification 단계에서 수동 검토 또는 diff assertion)
## Notes
- 이 REQ는 **계약 문서화**만 담당한다. envelope을 실제로 직렬화·발행하는 Python 코드(알람 emitter)는 REQ-100이 담당한다.
- `fields` 값은 opaque dict — core/notifier 모두 내용을 강제 파싱하지 않는다. 각 code별 권장 fields는 ALARM-INVENTORY.md를 참조한다.
- `occurred_at` 형식: 권장은 KST+09:00 offset-aware ISO-8601(기존 코어 로깅 관례와 통일). UTC도 수용.
- 다른 모듈(orb/tsl/kdh)은 `trex_core`를 import하지 않는다. 이 계약은 **문서 규약**이며 런타임 공유 코드가 아니다(Discovery 제약 A-1).
- trex-notifier가 `schema_version`이 미인식인 envelope을 수신하면 경고 로그 후 무시한다(소비자 책임 — notifier REQ 범위).
- dcy-033 성공기준 S-1(CRITICAL 알람 텔레그램 도달)·S-3(wire 계약 무회귀)의 선행 계약.
## Change Log
### CHG-20260621-02
- Date: 2026-06-21
- Author: trex-core-dev
#### Change Summary
- Status: Approved → Implemented. BAT-049 confirm-batch-verification 팀장 승인(QC PASS-WITH-NOTES blocker 0 + 팀장 실인프라 e2e 통과).
#### Delivery Trace Delta
- Batches: BAT-049 (release-candidate)
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no
### CHG-20260621-01
- Date: 2026-06-21
- Author: trex-core-dev
#### Change Summary
- REQ-098 신규 생성(Proposed). dcy-033 FR-1 대응: 알람 envelope wire 계약 문서화.
#### Intent
- dcy-033(제품군 알람 전달 체계) confirmed Discovery에서 요구하는 표준 알람 envelope 스키마를 trex-core wire 계약으로 정식화한다.
#### Acceptance Criteria Delta
- Added: AC-1~6 (신규 생성)
- Updated: (없음)
- Removed: (없음)
#### Impacted Area Delta
- Docs:
- `docs/interface-contract.md` 신규 섹션 추가
- Modules:
- 코드 변경 없음
- Tests:
- interface-contract diff 검증(기존 섹션 불변 확인)
#### Delivery Trace Delta
- Batches: (미정, M2 이후 큐잉)
- Releases: (미정)
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch 편성 시 REQ-099/100/101과 묶어 단일 batch로 처리 예정
#### Validation Plan
- `docs/interface-contract.md`에 알람 채널 섹션이 추가됐는지 수동 확인
- 기존 섹션 diff=0 확인(grep 또는 수동 비교)
- 7개 필드·severity 리터럴·schema_version·routing key 규약이 모두 명시됐는지 체크리스트 검토
@@ -1,143 +0,0 @@
# req-104: 전략 차단 게이트 — pause ∨ reconcile-warning 중 하나라도 걸리면 차단
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: trex-core-dev
## Intent
- 현재 전략 차단은 pause(수동 durable) 채널에만 의존한다. reconcile-warning(자동 durable) 채널을 추가해, **pause ∨ reconcile-warning 중 하나라도 존재하면 해당 슬롯/포트폴리오의 전략 수행(intent 수용 + slots read 차단 표면)을 차단**한다.
- dcy-034 FR-2 대응: 두 채널이 독립적으로 작동하며 OR 논리로 게이트를 확장한다.
- slots RPC wire 계약(`trex.slots.req` 응답 스키마)에서 `reconcile_warned` 플래그를 additive 필드로 노출해 운영자가 차단 원인을 식별할 수 있게 한다(NFR-4 최소 침습).
- **차단 범위(OQ-B 확정)**: reconcile-warning 차단은 **외부 전략 intent/read 전용**이다. **내부 안전망(safety-sell · watchdog · kill-switch)은 차단 예외**다. 근거: 집행 수량 정본은 브로커 잔고(execution.py)이므로 안전망은 수량 오류에 안전하며, 차단 시 포지션이 무보호로 방치된다.
## Requirement
- 시스템은 `IntentService._admit_buy` 및 `_admit_sell` 수행 시 대상 슬롯의 `pause_store` 또는 `ReconcileWarningStore` 중 하나라도 차단 기록이 있으면 intent를 `rejected`(reason: `reconcile_warned` 또는 `paused`)로 반환해야 한다.
- **내부 안전망 경로(safety-sell / kill-switch / watchdog)는 reconcile-warning 차단을 우회해야 한다.** 이 경로들은 `IntentService._admit_*` 게이트를 거치지 않는 별도 내부 경로를 사용하며, reconcile-warning이 걸린 슬롯에 대해서도 안전망 매도를 실행할 수 있어야 한다(OQ-B 확정, 차단 대상은 외부 전략 intent만).
- 시스템은 slots RPC 핸들러(`make_slots_rpc_handler`)에서 각 슬롯 행에 `reconcile_warned: bool` 필드를 추가해 reconcile-warning 차단 여부를 노출해야 한다.
- `slot_to_dict` 함수는 `ReconcileWarningStore`를 선택적으로 주입받고, `reconcile_warned` 필드를 산출해야 한다(pause_store의 `paused` 필드 처리 방식과 동형).
- 기존 `paused` 필드 및 `warned` 필드는 변경 없이 유지해야 한다(additive only, NFR-4).
- reconcile-warning 차단으로 rejected된 buy intent는 `reason="reconcile_warned"` 를 반환해야 한다.
## Acceptance Criteria
1. Given 슬롯의 portfolio_id가 ReconcileWarningStore에 warned 상태일 때, When buy intent가 제출되면, Then status=`rejected`, reason=`reconcile_warned`가 반환된다(전략 진입 차단).
2. Given 슬롯의 portfolio_id가 ReconcileWarningStore에 warned 상태일 때, When sell intent가 제출되면(외부 전략 경로), Then status=`rejected`, reason=`reconcile_warned`가 반환된다(전략 매도 차단). **단, safety-sell / kill-switch / watchdog의 내부 안전망 매도 경로는 이 차단을 받지 않으며 정상 실행되어야 한다(OQ-B 확정, 차단 예외).**
3. Given pause도 reconcile-warning도 없는 정상 슬롯에서, When buy/sell intent가 제출되면, Then 기존 admission 로직이 그대로 동작한다(오발동 없음).
4. Given pause만 있는 슬롯에서, When slots RPC가 호출되면, Then `paused=True`, `reconcile_warned=False` 필드가 반환된다(기존 paused 동작 불변).
5. Given reconcile-warning만 있는 슬롯에서, When slots RPC가 호출되면, Then `paused=False`, `reconcile_warned=True` 필드가 반환된다.
6. Given pause와 reconcile-warning이 모두 있는 슬롯에서, When slots RPC가 호출되면, Then `paused=True`, `reconcile_warned=True`가 모두 반환된다.
7. Given ReconcileWarningStore가 주입되지 않은 구성에서, When slots RPC가 호출되면, Then `reconcile_warned=False`(또는 필드 부재 시 기본값)로 반환되어 기존 클라이언트가 깨지지 않는다(하위 호환).
8. Given 기존 `warned` 필드(슬롯 qty ≠ hub asset_quantity 로컬 계산), When 신규 필드가 추가돼도, Then `warned` 필드 정의와 동작이 변경되지 않는다.
## Impacted Area
- Docs: `docs/interface-contract.md` (slots RPC 응답 스키마 `reconcile_warned` 필드 추가 명시)
- Modules:
- `trex_core/application/portfolio.py` (`slot_to_dict` — `reconcile_warned` 필드 추가)
- `trex_core/application/intents.py` (`IntentService._admit_buy`, `_admit_sell` — reconcile-warning 게이트 추가)
- `trex_core/application/messaging_handlers.py` (`make_slots_rpc_handler` — ReconcileWarningStore 주입 파라미터 추가)
- `trex_core/runtime/daemon.py` (ReconcileWarningStore 주입 배선)
- Tests:
- `tests/application/test_intents.py` (reconcile_warned 차단 시나리오, 정상 슬롯 오발동 없음)
- `tests/application/test_messaging_handlers.py` (slots RPC reconcile_warned 필드 노출)
- `tests/application/test_portfolio.py` (`slot_to_dict` reconcile_warned 필드 검증)
## Notes
- **safety-sell / kill-switch / watchdog 차단 예외(OQ-B 확정)**: 내부 안전망(safety-sell REQ-037~039, kill-switch REQ-045, watchdog REQ-034) 경로는 reconcile-warning 차단 예외다. 집행 수량 정본은 브로커 잔고(`execution.py`)이므로 안전망은 수량 오류에 안전하며, 차단하면 포지션이 무보호로 방치된다. 이 경로들은 `IntentService._admit_*` 게이트를 거치지 않는 별도 내부 호출 경로를 사용하므로 구조적으로 차단을 우회한다. batch design에서 경로 분리 구조를 명시적으로 확인한다.
- `reconcile_warned` 필드는 `slot_to_dict` 단에서 `ReconcileWarningStore.is_warned(slot_id)` 또는 `slot_id in list_warned()` 조회로 산출한다. batch design에서 성능(N+1) 고려해 bulk 조회 방식 선택.
- AMQP wire 계약 변경 사항: `trex.slots.req` 응답 행에 `reconcile_warned: bool` 필드 additive 추가. trex-orb-v1·trex-tsl-v1이 이 필드를 무시해도 하위 호환이 유지되는지 batch design에서 확인 필요.
- dcy-034 FR-2, NFR-4 대응.
## Change Log
### CHG-20260626-01
- Date: 2026-06-26
- Author: trex-core-dev
- Status: Approved → Implemented
- Summary: BAT-050(PR #31, ced7eda) origin/main 머지 완료. QC(opus) PASS + 팀장 confirm-batch-verification. pause∨reconcile-warning OR 게이트, 안전망 우회(OQ-B), slots RPC reconcile_warned 필드, 전 AC 검증 완료.
#### Acceptance Criteria Delta
- 없음
#### Impacted Area Delta
- 없음
#### Delivery Trace Delta
- Batches: BAT-050 (core-A)
- Releases: M3 (배포 대기)
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: 없음.
#### Validation Plan
- BAT-050 verification.md AC 매핑 전항목 PASS 확인됨.
### CHG-20260625-02
- Date: 2026-06-25
- Author: trex-core-dev
#### Change Summary
- REQ-104 **Proposed → Approved** (confirm-req, 팀장 2026-06-25).
- OQ-B 결정 반영: reconcile-warning 차단 범위 = 외부 전략 intent/read 전용. 내부 안전망(safety-sell/watchdog/kill-switch)은 차단 예외로 확정. AC-2에 예외 명시.
- Intent, Requirement, Notes에 OQ-B 결정 근거(집행 수량 정본=브로커, 차단 시 포지션 무보호) 추가.
#### Intent
- 팀장 confirm-req 결정(OQ-B 차단 예외 확정)을 REQ에 반영.
#### Acceptance Criteria Delta
- Added: 없음.
- Updated: AC-2(safety-sell/kill-switch/watchdog 차단 예외 명시).
- Removed: 없음.
#### Impacted Area Delta
- Notes: 안전망 경로 차단 예외 설계 원칙 구체화.
- Modules: `intents.py` — 차단 게이트가 외부 전략 intent 경로에만 적용됨을 구현 시 명시.
- Tests: safety-sell/kill-switch가 reconcile-warning 슬롯에서도 실행됨을 확인하는 테스트 추가 필요.
#### Delivery Trace Delta
- Batches: 미정 (suggest-batch-reqs 이후)
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Approved
- Follow-up Action: batch design에서 안전망 경로 분리 구조 명시 확인.
#### Validation Plan
- 외부 intent reconcile_warned 차단 테스트 pass / safety-sell 차단 우회 테스트 pass / slots RPC reconcile_warned 필드 반환 테스트 pass / 기존 paused/warned 동작 회귀 pass.
### CHG-20260625-01
- Date: 2026-06-25
- Author: trex-core-dev
#### Change Summary
- REQ-104 신규 생성 (Proposed) — dcy-034 FR-2 대응, draft-req 단계.
#### Intent
- pause 단독 게이트를 pause ∨ reconcile-warning OR 게이트로 확장해 자동 차단 채널을 활성화.
#### Acceptance Criteria Delta
- Added: AC-1~8 전부 신규.
- Updated: 없음.
- Removed: 없음.
#### Impacted Area Delta
- Docs: interface-contract.md 갱신 예정.
- Modules: portfolio.py, intents.py, messaging_handlers.py.
- Tests: 신규 게이트 테스트.
#### Delivery Trace Delta
- Batches: 미정
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no (신규 REQ)
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 wire 계약 영향 확인 포함 batch design.
#### Validation Plan
- reconcile_warned 차단 및 정상 슬롯 오발동 없음 테스트 pass / slots RPC reconcile_warned 필드 반환 테스트 pass / 기존 paused/warned 동작 회귀 pass.
@@ -1,148 +0,0 @@
# req-105: trex-core sync 명령 — 슬롯 수량을 브로커에 맞춰 갱신 + warning 해제
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: trex-core-dev
## Intent
- 운영자가 `trex-core sync` 명령으로 **브로커 잔고(정본)를 기준으로 대상 슬롯의 보유 수량을 갱신**(INACTIVE→HOLDING 전이 포함)하고, 갱신 후 브로커와 일치하면 해당 슬롯의 reconcile-warning을 자동 해제한다.
- cold-start 시 실계좌에 이미 보유 중인 종목(B 케이스)의 슬롯 onboarding 경로이기도 하다.
- dcy-034 FR-3, OQ-2/OQ-3 확정 반영: **브로커 잔고 정본 유지, 슬롯 qty ← 브로커**. 브로커에만 있고 portfolio-hub에 없는 종목(슬롯 부재)은 sync 대상 아님(자동 슬롯 생성 금지).
- portfolio-hub WAC(보유 평단) read 엔드포인트(FR-7, portfolio-hub **dcy-008 / REQ-043** `GET /v1/portfolios/{id}/holdings/cost-basis`) 가용 시 슬롯 avg_price를 seed한다. 포트 미가용 또는 조회 실패 시 수량만 갱신하고 WARN 로그를 남긴다(graceful degrade).
- **INACTIVE→HOLDING 전이 엣지 추가 승인(OQ-A)**: `ALLOWED_TRANSITIONS`에 `(INACTIVE, HOLDING)` 전이를 추가한다. 이 전이는 **actor=sync 또는 reconcile/reconcile_sync로 제한**되며, 일반 전략 경로(INACTIVE→PENDING_BUY→HOLDING)는 유지된다. transition_log reason은 `onboarding` 또는 `reconcile_sync`류로 식별 가능하게 기록한다. **wire 계약 무영향**: SlotState enum 상태값 5개(INACTIVE/PENDING_BUY/HOLDING/PENDING_SELL/ERROR) 불변, 전이 엣지만 추가이므로 slots RPC 스키마·상태값 변화 없음.
## Requirement
- 시스템은 `trex-core sync [--portfolio-id <pid> | --all]` 서브커맨드를 제공해야 한다.
- sync는 portfolio-hub 유니버스에 있어 슬롯이 생성된 종목만 대상으로 한다. 브로커에만 있고 슬롯이 없는 종목은 sync가 건드리지 않고 unmanaged 경고를 로그에 남긴다(자동 슬롯 생성 금지).
- sync 실행 시 대상 슬롯마다 브로커 잔고(`BrokerPort.get_balance()`)를 조회하여 슬롯 qty를 브로커 수량으로 갱신해야 한다. 브로커 수량 > 0이고 슬롯이 INACTIVE이면 **INACTIVE→HOLDING 전이(actor=sync, reason=onboarding/reconcile_sync)**를 수행해야 한다. 이 전이는 OQ-A 승인으로 `ALLOWED_TRANSITIONS`에 추가되는 새 엣지를 사용하며 일반 전략 진입 경로와 구분된다.
- portfolio-hub WAC read 포트(FR-7: **portfolio-hub dcy-008 / REQ-043**, `GET /v1/portfolios/{id}/holdings/cost-basis`)가 연결되어 있으면, sync 시 보유 평단(WAC)을 읽어 슬롯 avg_price에 seed해야 한다. 포트가 없거나 조회 실패 시 avg_price seed를 건너뛰고 WARN 로그를 남긴다(graceful degrade).
- sync 후 슬롯 qty == 브로커 수량이면 `ReconcileWarningStore.clear_warned(slot_id)`로 reconcile-warning을 해제해야 한다.
- sync 실행 전 before 상태, 실행 후 after 상태(슬롯 qty, 브로커 qty, warning 해제 여부)를 출력해야 한다.
- sync는 confirmation 프롬프트(`--yes` 스킵 가능)와 `--dry-run` 모드를 지원해야 한다. live 계좌에서는 `--yes --live` 이중 확인을 요구해야 한다.
- sync는 직접-DB 경로(pause/resume 방식)로 구현하며, 데몬 RPC를 거치지 않는다.
## Acceptance Criteria
1. Given cold-start 상태(슬롯 INACTIVE, 브로커 보유 qty > 0)에서 `trex-core sync --portfolio-id <pid>` 실행 시, When sync가 완료되면, Then 슬롯 qty = 브로커 qty이고 슬롯 상태가 HOLDING으로 전이되며 reconcile-warning이 해제된다(S-2, OQ-A 승인 전이).
2. Given 슬롯 qty ≠ 브로커 qty인 B 케이스에서 sync 실행 시, When sync가 완료되면, Then 슬롯 qty = 브로커 qty로 갱신되고 reconcile-warning이 해제된다.
3. Given 브로커에만 있고 슬롯이 없는 종목(슬롯 부재)에서 sync 실행 시, When sync가 실행되면, Then 슬롯이 자동 생성되지 않고 unmanaged 경고가 로그에 남는다.
4. Given portfolio-hub WAC read 포트(portfolio-hub dcy-008 / REQ-043 `GET /v1/portfolios/{id}/holdings/cost-basis`)가 연결되어 있을 때, When sync를 실행하면, Then 슬롯 avg_price에 WAC 값이 seed된다.
5. Given portfolio-hub WAC read 포트가 없거나 조회 실패 시, When sync를 실행하면, Then avg_price seed 없이 수량 갱신만 수행하고 WARN 로그를 남긴다(graceful degrade).
6. Given `--dry-run` 플래그로 sync 실행 시, When 명령이 실행되면, Then 슬롯 qty 변경 없이 before/after 예상치만 출력된다.
7. Given live 계좌에서 `--yes` 없이 sync 실행 시, When 명령이 실행되면, Then 오류 메시지와 함께 실행을 거부한다(live double-ack 게이트).
8. Given sync 실행 후 슬롯 qty가 여전히 브로커 수량과 다를 경우(갱신 실패 등), When sync가 완료되면, Then reconcile-warning이 해제되지 않는다.
9. Given `--all` 플래그로 sync 실행 시, When 명령이 실행되면, Then 인스턴스의 모든 B-warned 슬롯에 대해 sync가 실행된다.
10. Given INACTIVE→HOLDING 전이 시, When transition_log 또는 로그를 확인하면, Then actor 및 reason 필드에 sync/onboarding(또는 reconcile_sync)이 기록되어 일반 전략 진입 경로(INACTIVE→PENDING_BUY)와 구분된다(OQ-A actor 식별).
## Impacted Area
- Docs: `docs/operations.md` (cold-start onboarding 절차 신설), `docs/runtime-flows.md` (sync 흐름 추가)
- Modules:
- `trex_core/runtime/cli.py` (`sync` 서브커맨드 추가, `_build_parser`, `_cmd_sync`)
- `trex_core/application/reconciliation.py` (sync 로직 또는 별도 `sync_slot_to_broker` 함수 — batch design에서 결정)
- `trex_core/application/ports.py` 또는 `application/portfolio.py` (WAC read 포트 의존 명시)
- `trex_core/adapters/portfolio/` (WAC read 어댑터 — portfolio-hub FR-7 REQ 선행 의존)
- Tests:
- `tests/application/test_sync.py` 또는 `tests/integration/test_sync.py` (cold-start onboarding, warning 해제, unmanaged 슬롯 처리, dry-run, WAC seed 유무)
- `tests/runtime/test_cli.py` (sync 서브커맨드 인수 파싱, 확인 프롬프트, live double-ack)
## Notes
- **FR-7 의존 구체화(OQ-A 팀장 결정)**: portfolio-hub WAC read 엔드포인트는 **portfolio-hub dcy-008 / REQ-043**, `GET /v1/portfolios/{id}/holdings/cost-basis`. 2026-06-25 confirm-discovery 완료. 가용 시 avg_price seed, 미가용/실패 시 수량만 갱신 + WARN(graceful degrade). 구현 시 portfolio-hub REQ-043 완료 여부 확인 필요.
- **INACTIVE→HOLDING 전이 엣지 추가(OQ-A 팀장 승인)**: `state.py:ALLOWED_TRANSITIONS`에 `(INACTIVE, HOLDING)` 엣지 추가가 승인되었다. 이 전이는 **actor=sync 또는 reconcile로 제한**되며 일반 전략 경로(INACTIVE→PENDING_BUY→HOLDING)는 유지된다. transition_log reason은 `onboarding` 또는 `reconcile_sync`류로 식별. **wire 무영향**: SlotState enum 5개(inactive/pending_buy/holding/pending_sell/error) 불변, 엣지만 추가이므로 slots RPC 스키마·상태값 변화 없음. batch design에서 `_BASE_TRANSITIONS` 확장 또는 별도 `_SYNC_TRANSITIONS` 집합 구성을 결정한다.
- sync 대상 슬롯 결정 방법(portfolio_id 명시 vs all warned 슬롯 vs all INACTIVE 슬롯)은 batch design에서 구체화.
- dcy-034 FR-3, OQ-2/3, OQ-A(팀장 2026-06-25 confirm), R-1 대응.
## Change Log
### CHG-20260626-01
- Date: 2026-06-26
- Author: trex-core-dev
- Status: Approved → Implemented
- Summary: BAT-051(PR #32, 07b393d) origin/main 머지 완료. QC(opus) PASS + 팀장 confirm-batch-verification. sync CLI(--portfolio-id/--all/--dry-run/--live), INACTIVE→HOLDING 전이, WAC seed, warning 해제, 전 AC 검증 완료.
#### Acceptance Criteria Delta
- 없음
#### Impacted Area Delta
- 없음
#### Delivery Trace Delta
- Batches: BAT-051 (core-B)
- Releases: M3 (배포 대기)
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: M3 배포 시 cold-start 운영 검증.
#### Validation Plan
- BAT-051 verification.md AC 매핑 전항목 PASS 확인됨.
### CHG-20260625-02
- Date: 2026-06-25
- Author: trex-core-dev
#### Change Summary
- REQ-105 **Proposed → Approved** (confirm-req, 팀장 2026-06-25).
- OQ-A 결정 반영: INACTIVE→HOLDING 전이 엣지 추가 승인(actor=sync/reconcile 제한, wire 무영향 명시).
- FR-7 의존 구체화: portfolio-hub dcy-008 / REQ-043 (`GET /v1/portfolios/{id}/holdings/cost-basis`) 로 참조 갱신.
- AC-10 신규 추가(전이 actor 식별).
#### Intent
- 팀장 confirm-req 결정(OQ-A 승인 + FR-7 참조 구체화)을 REQ에 반영.
#### Acceptance Criteria Delta
- Added: AC-10 신규(INACTIVE→HOLDING 전이 actor/reason 식별).
- Updated: AC-1(OQ-A 전이 명시), AC-4(FR-7 참조 구체화), AC-5(graceful degrade 명시).
- Removed: 없음.
#### Impacted Area Delta
- Notes: FR-7 참조 및 전이 엣지 추가 내용 구체화.
- Modules: `trex_core/domain/slot/state.py` — `ALLOWED_TRANSITIONS`에 `(INACTIVE, HOLDING)` 엣지 추가 필요(batch implementation 단계).
- Tests: AC-10 actor 식별 테스트 신규.
#### Delivery Trace Delta
- Batches: 미정 (suggest-batch-reqs 이후)
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Approved
- Follow-up Action: batch design에서 state.py 전이 집합 확장 방식 결정 및 actor 제한 구현 방안 확정.
#### Validation Plan
- cold-start onboarding 시나리오 테스트 pass / INACTIVE→HOLDING 전이 actor 식별 테스트 pass / warning 해제 확인 / unmanaged 슬롯 자동 생성 없음 테스트 pass / FR-7 graceful degrade 테스트 pass.
### CHG-20260625-01
- Date: 2026-06-25
- Author: trex-core-dev
#### Change Summary
- REQ-105 신규 생성 (Proposed) — dcy-034 FR-3 대응, draft-req 단계.
#### Intent
- cold-start 시 운영자가 안전하게 슬롯을 브로커에 맞춰 onboarding하는 표준 CLI 경로 신설.
#### Acceptance Criteria Delta
- Added: AC-1~9 전부 신규.
- Updated: 없음.
- Removed: 없음.
#### Impacted Area Delta
- Docs: operations.md 신설, runtime-flows.md 갱신.
- Modules: cli.py, reconciliation.py.
- Tests: sync 통합 테스트 신규.
#### Delivery Trace Delta
- Batches: 미정
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no (신규 REQ)
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: INACTIVE→HOLDING 전이표 추가 여부 팀장 확인 후 batch design 진행.
#### Validation Plan
- cold-start onboarding 시나리오 테스트 pass / warning 해제 확인 / unmanaged 슬롯 자동 생성 없음 테스트 pass.
@@ -1,167 +0,0 @@
# req-106: trex-core verify 명령 — C 불일치 슬롯 재대조 + warning 해제
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: trex-core-dev
## Intent
- 운영자가 portfolio-hub CLI로 원장을 정정한 뒤 `trex-core verify [--portfolio-id <pid>]` 명령으로 **C 불일치(원장↔슬롯) 차단 슬롯을 재대조**하여, 일치 시 warning을 해제하고 불일치 시 사유와 함께 해제를 거부한다.
- dcy-034 FR-4, OQ-2/5, **OQ-C 확정** 반영: read-중심 명령(슬롯 수량 변경 없음), 강제 해제(force-clear) 없음.
- 재대조 로직은 현행 `reconcile_positions`(브로커 경유 2-대조)를 재사용한다(OQ-5).
- **verify는 C 케이스(원장↔슬롯 수량 불일치) 전용**이다. B 케이스(슬롯↔브로커 수량 불일치)는 sync 명령(REQ-105)이 해소 경로이며 verify 범위에 포함되지 않는다(OQ-C 확정).
## Requirement
- 시스템은 `trex-core verify [--portfolio-id <pid>]` 서브커맨드를 제공해야 한다.
- verify는 대상 슬롯(portfolio_id 기반)에 대해 `reconcile_positions`를 다시 실행해(브로커=정본, 원장↔브로커 대조) 일치 여부를 판정해야 한다.
- 대조 결과 일치(원장 수량 == 브로커 수량)이면 `ReconcileWarningStore.clear_warned(slot_id)` 로 reconcile-warning을 해제하고 "해제됨" 메시지를 출력해야 한다.
- 대조 결과 불일치이면 warning을 해제하지 않고 불일치 사유(원장 수량, 브로커 수량, 차이)를 출력하고 비-0 종료코드를 반환해야 한다(강제 해제 경로 없음).
- verify는 슬롯 qty를 변경하지 않는다(read-중심 — 슬롯 수량 변경 없음).
- verify는 C 케이스(case_code='C')로 warned된 슬롯만을 대상으로 한다. **B 케이스(슬롯↔브로커 수량 불일치)에 대한 해소는 sync 명령(REQ-105) 책임이며, verify는 B 케이스에 적용하지 않는다(OQ-C 확정, C 전용).**
## Acceptance Criteria
1. Given C 불일치로 차단된 슬롯에서 운영자가 portfolio-hub CLI로 원장을 정정하고 `trex-core verify --portfolio-id <pid>` 실행 시, When 원장 수량 == 브로커 수량이면, Then reconcile-warning이 해제되고 "해제됨" 메시지가 출력된다(S-3 1차).
2. Given C 불일치로 차단된 슬롯에서 `trex-core verify` 실행 시, When 원장 수량 ≠ 브로커 수량이면, Then reconcile-warning이 해제되지 않고 불일치 사유(원장qty, 브로커qty, 차이)가 출력되며 비-0 종료코드를 반환한다(S-3 2차, 강제 해제 없음).
3. Given verify 실행 시, When 어떤 경우에도, Then 슬롯 qty가 변경되지 않는다(read-중심 불변식).
4. Given reconcile-warning이 없는 슬롯에 대해 verify 실행 시, When 명령이 실행되면, Then 이미 해제 상태임을 알리는 메시지 출력 후 0 종료코드로 반환한다(idempotent).
5. Given `--json` 플래그로 verify 실행 시, When 명령이 실행되면, Then `{portfolio_id, slot_id, result: "cleared"|"rejected", hub_qty, broker_qty, reason?}` JSON이 stdout에 출력된다.
6. Given `trex-core verify` (--portfolio-id 없이) 실행 시, When 명령이 실행되면, Then 인스턴스의 모든 C-warned 슬롯에 대해 재대조를 수행하고 결과를 슬롯별로 출력한다.
## Impacted Area
- Docs: `docs/operations.md` (원장 정정 후 verify 절차 추가), `docs/runtime-flows.md` (verify 흐름 추가)
- Modules:
- `trex_core/runtime/cli.py` (`verify` 서브커맨드 추가)
- `trex_core/application/reconciliation.py` (`reconcile_positions` 재사용 또는 호출 래퍼 — batch design에서 결정)
- Tests:
- `tests/runtime/test_cli.py` (verify 서브커맨드 인수 파싱)
- `tests/application/test_verify.py` 또는 `tests/integration/test_verify.py` (일치→해제, 불일치→거부, read-중심 불변식, idempotent)
## Notes
- OQ-5 확정: verify의 재대조는 `reconcile_positions`(원장↔브로커 2-대조, 브로커=정본)를 재사용한다. 별도 대조 로직을 만들지 않는다.
- verify는 read-중심이므로 pause/resume의 live double-ack 게이트는 불필요하다. --yes, --live 옵션이 필요 없다.
- **OQ-C 확정: verify는 C 전용**. B 케이스(슬롯↔브로커 수량 불일치)는 sync(REQ-105)로 해소한다. verify가 B-warned 슬롯 ID로 호출되면 "C 케이스 대상 아님" 안내 후 0 종료코드를 반환한다(batch design에서 메시지 확정).
- dcy-034 FR-4, OQ-2/5, OQ-C(팀장 2026-06-25 confirm), S-3 대응.
## Change Log
### CHG-20260630-01
- Date: 2026-06-30
- Author: 팀장(Claude) — change-req (라이브 릴리즈 핫픽스 + postmortem)
#### Change Summary
- **REL-010 STEP2 배포 스모크서 `trex-core verify` ImportError 핫픽스.** Status `Implemented` 유지(구현 결함 수정, AC 불변).
#### Intent / 증상·근본원인 (핫픽스 예외 경로)
- **증상**: 운영 배포(`ababf80`) 후 `trex-core verify --config ... --portfolio-id ...` 실행 시 `ImportError: cannot import name 'make_broker' from 'trex_core.adapters.broker'`.
- **근본원인**: `runtime/cli.py` `_cmd_verify()`가 **코드베이스에 존재하지 않는** `trex_core.adapters.broker.make_broker`를 import(정의 0건, 참조는 verify 한 곳뿐). 형제 명령 `_cmd_sync()`는 올바르게 `trex_core.runtime.daemon._build_broker`를 사용. → verify 경로에만 잘못된 import가 박혀 있었음.
- **수정**: `_cmd_verify`를 `from trex_core.runtime.daemon import _build_broker` / `_build_broker(cfg)`로 교체(sync와 동일, 검증된 경로). 커밋 `51cc3cc`.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음 (기존 AC 동일 — 깨진 구현을 정정)
#### Delivery Trace Delta
- 핫픽스 커밋 `51cc3cc`(main 직접, fast-path). 회귀 테스트 2종 추가(`tests/runtime/test_cli_operator.py`): `test_verify_cmd_broker_import_does_not_raise`(paper config+DB stub로 verify 경로 import 통과 검증), `test_verify_cmd_uses_build_broker_not_make_broker`(make_broker 심볼 부재 구조검증).
#### Verification
- 전체 스위트 747 passed / 47 skipped / 0 failed(회귀 0). **운영 재검증(2026-06-30, `51cc3cc`)**: verify OK(slot already cleared) · sync --dry-run OK(broker_qty_zero guard SKIP) · report OK.
#### Postmortem (테스트 갭)
- **왜 미검출**: BAT-051 verification이 verify의 **broker import 경로를 런타임 실행하지 않음**(import가 함수 내부라 호출 시에만 트리거). 단위 테스트가 verify 명령을 끝까지 돌리지 않아 phantom import가 통과됨.
- **재발 방지**: 위 회귀 테스트 2종으로 import 경로를 실제 실행/구조검증. 후속 권고 — operator CLI 명령들의 lazy import를 스모크 수준으로 한 번씩 실행하는 테스트 추가 검토.
#### Revalidation Impact
- Reverification Needed: no (회귀테스트+운영 재검증 완료) / Existing Implementation Invalidated: no
- Status Recommendation: implemented
- Rollback: `git revert 51cc3cc` (CLI 전용, trading/wire/daemon 무관 — 실행 중 데몬 무영향).
- ⚠️ 거버넌스 노트: 라이브 블로커 해소를 위해 **main 직접 푸시**(사전 결재 게이트 절차 생략) — 사장님 사후 추인.
### CHG-20260626-01
- Date: 2026-06-26
- Author: trex-core-dev
- Status: Approved → Implemented
- Summary: BAT-051(PR #32, 07b393d) origin/main 머지 완료. QC(opus) PASS + 팀장 confirm-batch-verification. verify CLI(--portfolio-id/--json), C케이스 재대조+warning 해제, B케이스 거부+sync 안내, 전 AC 검증 완료.
#### Acceptance Criteria Delta
- 없음
#### Impacted Area Delta
- 없음
#### Delivery Trace Delta
- Batches: BAT-051 (core-B)
- Releases: M3 (배포 대기)
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: 없음.
#### Validation Plan
- BAT-051 verification.md AC 매핑 전항목 PASS 확인됨.
### CHG-20260625-02
- Date: 2026-06-25
- Author: trex-core-dev
#### Change Summary
- REQ-106 **Proposed → Approved** (confirm-req, 팀장 2026-06-25).
- OQ-C 결정 반영: verify = C 케이스(원장↔슬롯) 전용 확정. B 케이스는 sync(REQ-105) 책임. Intent, Requirement, Notes에 "C 전용, B는 sync 책임" 명시.
#### Intent
- 팀장 confirm-req 결정(OQ-C 확정: verify는 C 전용)을 REQ에 반영.
#### Acceptance Criteria Delta
- Added: 없음.
- Updated: 없음(기존 AC는 이미 C 케이스 중심으로 작성됨).
- Removed: 없음.
#### Impacted Area Delta
- Notes: OQ-C 확정 및 B-warned 슬롯 호출 시 처리 방침 추가.
- Modules: cli.py verify 서브커맨드 — B-warned 슬롯 필터링 로직 추가 필요.
#### Delivery Trace Delta
- Batches: 미정 (suggest-batch-reqs 이후)
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Approved
- Follow-up Action: batch design에서 B-warned 슬롯 필터링 메시지 확정.
#### Validation Plan
- 일치→해제, 불일치→거부 시나리오(C 케이스) 테스트 pass / B-warned 슬롯에 verify 적용 시 "대상 아님" 처리 테스트 pass / 슬롯 qty 불변 검증 / 기존 reconcile_positions 회귀 pass.
### CHG-20260625-01
- Date: 2026-06-25
- Author: trex-core-dev
#### Change Summary
- REQ-106 신규 생성 (Proposed) — dcy-034 FR-4 대응, draft-req 단계.
#### Intent
- C 불일치 차단 해소를 위한 운영자 read-중심 재대조 경로 신설. 강제 해제 없이 재대조 일치 시에만 차단 해제.
#### Acceptance Criteria Delta
- Added: AC-1~6 전부 신규.
- Updated: 없음.
- Removed: 없음.
#### Impacted Area Delta
- Docs: operations.md, runtime-flows.md 갱신.
- Modules: cli.py, reconciliation.py.
- Tests: verify 시나리오 테스트 신규.
#### Delivery Trace Delta
- Batches: 미정
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no (신규 REQ)
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch design.
#### Validation Plan
- 일치→해제, 불일치→거부 시나리오 테스트 pass / 슬롯 qty 불변 검증 / 기존 reconcile_positions 회귀 pass.
@@ -1,150 +0,0 @@
# req-110: 운영 리포트 WAC 실현손익 통합 — 전 인스턴스 공통
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: trex-core-dev
- Approved By: 팀장 (Claude), 2026-06-26 (confirm-req)
## Intent
- 현재 `operator_report.py`(REQ-088)의 `realized_pnl(trades)`은 당일 net 현금흐름(`Σ매도대금 − Σ매수대금 − 수수료 − 세금`)을 사용한다. 중장기 인스턴스에서 전일 매수→당일 매도 시 cost basis가 반영되지 않아 실현손익이 왜곡된다. portfolio-hub WAC API(`/pnl/realized`)를 소비해 전 인스턴스 공통으로 정확한 실현손익을 산출하고 리포트에 표시한다. (dcy-035 FR-2, FR-3, FR-4, OQ-1=전 인스턴스 WAC 통일, NFR-2)
## Requirement
- `operator_report.py`의 `OperatorReport`에 WAC 실현손익 관련 필드를 추가한다: `realized_pnl_wac: float`, `realized_pnl_wac_by_asset: dict[str, float]`, `data_completeness_warning: bool`. (CHG-20260626-02: `buy_fee_only_assets` 필드 제거 — 아래 매수 fee 편입 결정 반영.)
- 운영 리포트(`trex-core report` CLI)는 당일 net 대신 portfolio-hub WAC 실현손익(`/pnl/realized`)을 **전 인스턴스 공통**으로 사용해 실현손익을 표시한다.
- 매도가 있는 자산: WAC 기준 실현손익(`(매도가 − WAC) × qty − fee − tax`)을 자산별로 분해해 출력한다. portfolio-hub WAC는 **매수 수수료를 cost basis에 편입**(REQ-041 CHG-20260626-01)하므로 이 실현손익은 매수·매도 fee를 모두 정확히 반영한다.
- 매수만 한 기간(해당 자산의 매도 0): 실현손익 0으로 표시한다. **매수 수수료는 cost basis(WAC)에 편입되어 매도 시 실현**되므로, 별도 "수수료 비용" 라인은 두지 않는다(CHG-20260626-02 — 별도 라인은 매도 시 실현분과 이중계상되어 제거).
- portfolio-hub 응답의 `data_completeness_warning: true` 시 리포트 출력에 경고를 표면화한다(텍스트/JSON 모두 포함).
- `render_text` / `render_json`을 WAC 모드에 맞게 갱신한다.
- CLI `report` 서브커맨드에서 portfolio-hub 설정(`cfg.portfolio_hub.base_url`)이 있을 때 WAC 경로를 사용하고, 미설정이면 REQ-111 degrade 경로로 위임한다.
## Acceptance Criteria
1. Given 전일 매수 + 당일 매도 시나리오(portfolio-hub `/pnl/realized` 모킹 응답), When `report` 실행, Then 실현손익이 WAC 기준 정확값(`(매도가 − WAC) × qty − fee − tax`)으로 표시되고 당일 net 왜곡값과 다르다.
2. Given 동일 날 **닫힌** 매수+매도(일중, buy_qty==sell_qty) 시나리오, When `report` 실행, Then WAC 실현손익이 기존 당일 net과 **정확히 일치**한다(`==`, NFR-2 회귀 보장). (CHG-20260626-02: 매수 fee 편입(REQ-041)으로 일중 닫힌 거래는 WAC==net이 엄격 성립 — `≈`가 아니라 `==`로 단언.)
3. Given 매수만 한 기간(매도 0), When `report` 실행, Then 실현손익 0으로 표시되고 별도 수수료 비용 라인은 없다(매수 fee는 cost basis 편입, 매도 시 실현). (CHG-20260626-02: 기존 `buy_fee_only_assets` 별도 라인 제거.)
4. Given portfolio-hub 응답에 `data_completeness_warning: true`, When `report` 실행, Then 텍스트 출력과 `--json` 출력 모두에 completeness 경고가 표시된다.
5. Given 자산별 실현손익 분해, When `report` 실행, Then `realized_pnl_wac_by_asset`에 자산(symbol)별 WAC 실현손익이 분해된다.
6. Given `--json` 플래그, When `report` 실행, Then `render_json` 출력에 `realized_pnl_wac`, `realized_pnl_wac_by_asset`, `data_completeness_warning` 필드가 포함된다. (CHG-20260626-02: `buy_fee_only_assets` 제거.)
7. Given portfolio-hub `base_url` 미설정(cfg.portfolio_hub None 또는 base_url 미정의), When `report` 실행, Then REQ-111 degrade 경로로 처리된다(에러 표시).
## Impacted Area
- Docs:
- `docs/operations.md` — 리포트 실현손익 정의 갱신(당일 net → WAC 기준, 매수일 수수료 표시 명시)
- `docs/runtime-flows.md` — operator report 흐름에 portfolio-hub WAC 호출 경로 추가
- Modules:
- `trex_core/application/operator_report.py` — `OperatorReport` 필드 확장, 기존 `realized_pnl(trades)` 함수는 legacy/테스트 목적 유지(NFR-2 회귀 비교용), WAC 모드 신규 함수/빌더, `render_text`/`render_json` 갱신
- `trex_core/runtime/cli.py` — `_cmd_report` 내 portfolio-hub WAC 호출 분기, `from_dt`/`to_dt` 파라미터 전달 (OQ-2 deferred: 기본값=오늘 KST 경계로 구현)
- Tests:
- 신규: 멀티데이 픽스처(전일 매수+당일 매도) 통합 테스트, 매수만 기간 테스트, data_completeness_warning 테스트, NFR-2 일중 회귀 단위 테스트
- 기존 `test_operator_report.py` 회귀 (당일 net 함수 동작 보존)
## Notes
- OQ-2(기간 모델): from_dt/to_dt는 오늘(KST 경계) 기본값으로 구현. 기간 범위 확장(지정 기간)은 design/팀장 결정 대기 → 기본 구현은 "당일 KST 매도 기준" 유지, `--from`/`--to` CLI 옵션 추가는 OQ-2 확정 후 별도 change-req 또는 design 인계.
- OQ-3(수수료 출처): 매수만 한 날의 수수료는 `ledger_outbox` 당일 거래에서 집계(기존 경로 재사용). portfolio-hub 거래내역(REQ-039) 사용 여부는 design 인계.
- OQ-4(N콜 vs 집계): 슬롯↔portfolio 1:1이므로 portfolio_id별 N콜이 기본 구현. 집계 최적화는 design 인계.
- 기존 `realized_pnl(trades)` 함수는 삭제하지 않고 유지한다(NFR-2 회귀 비교, 기존 테스트 보존).
- NFR-1(wire 계약 불변): report는 read-only 운영 표면 — slots RPC/AMQP 계약 무관. REQ 명시 불필요.
- NFR-3(데몬 본업 격리): `_cmd_report`는 CLI 직접 실행 경로이며 데몬 루프와 무관 — 격리는 구조적으로 보장됨.
## Change Log
### CHG-20260626-03
- Date: 2026-06-26
- Author: trex-core-dev
#### Change Summary
- BAT-052 구현·검증 완료(PR #33, 머지 커밋 81d06d9). confirm-batch-verification + confirm-req-implemented. Approved → Implemented.
#### Intent
- dcy-035 FR-2/FR-3/FR-4 delivery 완료 확인 및 상태 전환.
#### Acceptance Criteria Delta
- Updated:
- none (모든 AC-1~7 검증 완료, 상태 전환만)
- Added:
- none
- Removed:
- none
#### Impacted Area Delta
- Docs: 없음
- Modules: 변경 없음 (구현 완료 상태 유지)
- Tests: 717 passed / 47 skipped / 0 fail (BAT-052 verification)
#### Delivery Trace Delta
- Batches:
- BAT-052 (verified, PR #33, 머지 커밋 81d06d9, 2026-06-26)
- Releases:
- none (M3 배포 대기)
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: Implemented
- Follow-up Action: none
### CHG-20260626-02
- Date: 2026-06-26
- Author: 팀장 (Claude)
#### Change Summary
- 사장님 결정(2026-06-26): portfolio-hub WAC에 매수 수수료 편입(REQ-041 CHG-20260626-01). 그 결과 (1) 일중 닫힌 거래에서 WAC 실현손익 == 당일 net이 **엄격히** 성립 → AC-2를 `≈`에서 `==`로 강화. (2) 매수 fee가 cost basis에 편입되므로 매수전용일의 별도 "수수료 비용" 라인(`buy_fee_only_assets`)은 매도 시 실현분과 **이중계상** → 제거.
#### Intent
- 매수 fee 편입 결정과 정합: 단일 정확 실현손익 숫자, NFR-2 엄격 성립, 이중계상 제거.
#### Acceptance Criteria Delta
- Updated:
- AC-2: 일중 닫힌 거래 WAC==net **엄격 일치**(`==`)로 강화.
- AC-3: 매수전용일 별도 수수료 비용 라인 제거(매수 fee는 cost basis 편입·매도 시 실현).
- AC-6: `--json` 필드에서 `buy_fee_only_assets` 제거.
- Removed:
- `OperatorReport.buy_fee_only_assets` 필드 및 관련 산출/렌더.
#### Impacted Area Delta
- Modules: operator_report.py(buy_fee_only_assets 제거, NFR-2 테스트 강화), cli.py(해당 표시 제거)
- Tests: NFR-2 일중 회귀 테스트를 `==` 단언으로 강화, buy_fee_only_assets 테스트 제거/대체
#### Revalidation Impact
- Reverification Needed: yes (BAT-052 보정 후 재검증)
- Existing Implementation Invalidated: partial (BAT-052 구현 중 buy_fee_only_assets 부분)
- Status Recommendation: keep-current (Approved)
- Follow-up Action: BAT-052 보정 → 재QC → confirm-batch-verification
### CHG-20260626-01
- Date: 2026-06-26
- Author: trex-core-dev
#### Change Summary
- dcy-035 FR-2/FR-3/FR-4, OQ-1(전 인스턴스 WAC 통일), NFR-2(일중 회귀)로부터 최초 생성(Proposed).
#### Intent
- 중장기 인스턴스 실현손익 왜곡 해소 + 단기 회귀 보장 + 매수일 수수료 표시 + completeness 경고 표면화.
#### Acceptance Criteria Delta
- Added:
- AC-1~7 신규
- Updated:
- none
- Removed:
- none
#### Impacted Area Delta
- Docs:
- docs/operations.md, docs/runtime-flows.md
- Modules:
- operator_report.py 확장, cli.py _cmd_report 분기
- Tests:
- 신규 멀티데이/매수전용/completeness/NFR-2 테스트, 기존 회귀
#### Delivery Trace Delta
- Batches:
- none (미배치)
- Releases:
- none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 승인 게이트 후 suggest-batch-reqs
@@ -1,144 +0,0 @@
# req-116: `trex.slots.req` 전략 필드 노출 + `strategy` 요청 필터 (additive)
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: trex-core-dev
## Intent
- 신규 전략 데몬 trex-tvr-v1(TVR — Target-Value Rebalancing)이 `trex.slots.req` 응답 행에서 `strategy_name`·`strategy_params`·`markets` 를 읽어 자기 슬롯을 식별하고 리밸런싱 목표 비중(`target_weight` 등)을 파라미터로 수신해야 한다. 또한 `strategy="tvr_v1"` 요청 필터로 자기 전략 슬롯만 수신하려 한다.
- REQ-074 AC-5 는 dcy-025 OQ-4 당시 결정을 유보한 것이었고, 본 REQ 는 그 additive 재도입(dcy-025 OQ-4 후속)이다. **기존 소비자(orb·tsl)에게 byte-동일 기본 동작을 보장**하면서 필드를 추가한다.
- 근거: trex-tvr-v1 Discovery(dcy-001/dcy-002 v3 FR-8, confirmed) — portfolio-hub 측 `strategy_name`/`markets`/`strategy_params` 노출 REQ(①)가 선행 배포된 뒤 본 REQ(②)를 배포한다.
## Requirement
### 행 필드 추가 (additive — 기존 필드 불변)
- `slot_to_dict()`(application/portfolio.py)가 `SnapshotStore` 의 `PortfolioItem` 에서 아래 세 필드를 읽어 슬롯 행에 추가한다:
- `strategy_name: str | null` — portfolio-hub `strategy_name`. PortfolioItem 에 없거나 빈 값이면 `null`.
- `strategy_params: dict` — portfolio-hub `strategy_params` opaque dict. PortfolioItem 에 없으면 `{}`.
- `markets: list[str]` — portfolio-hub `markets` 배열. PortfolioItem 에 없으면 `[]`.
- 이 세 필드의 정본 출처는 portfolio-hub(SnapshotStore 경유)이다. hub 응답에 없으면 safe default(null/`{}`/`[]`)를 사용하고 데몬을 중단하지 않는다.
- hub_read.py(`get_portfolios`) 가 portfolio-hub 응답에서 `strategy_name` 과 `markets` 를 파싱해 `PortfolioItem` 에 담는다. 구버전 hub 응답(미존재 키)에서는 각각 `None`/`[]` 로 safe-default 한다.
- `PortfolioItem` 도메인 객체에 `strategy_name: Optional[str]` 과 `markets: list[str]` 필드를 추가한다.
### 요청 `strategy` 필터 추가 (additive — 기존 필터 불변)
- `trex.slots.req` 요청 payload 에 선택적 파라미터 `strategy: str` 을 추가한다.
- 지정 시: `strategy_name == strategy` 인 슬롯 행만 반환한다. 대소문자 exact-match.
- 미지정 시: 기존과 완전 동일(전체 반환).
- `strategy` 필터는 기존 `filter`(status 필터) 와 **AND 조합**된다. 두 필터를 동시에 지정하면 status 조건과 strategy 조건 모두 만족하는 행만 반환한다.
- `available_slots` 힌트는 `strategy` 필터 적용 여부와 **무관하게 인스턴스 전체 활성 슬롯 기준**으로 계산한다(capacity 의미 불변 — REQ-073 AC-6).
### interface-contract.md 갱신
- `trex.slots.req` 요청 payload 에 `strategy: str (optional)` 파라미터를 추가한다.
- 응답 슬롯 행 스키마에 `strategy_name`·`strategy_params`·`markets` 필드와 정본 소스 테이블을 추가한다.
- REQ-074 AC-5 주석("strategy 필드 없음")을 본 REQ 에 의한 additive 재도입으로 갱신한다.
## Acceptance Criteria
1. **행 필드 노출**: Given portfolio-hub 가 `strategy_name="tvr_v1"`, `strategy_params={"target_weight": 0.05}`, `markets=["KRX"]` 를 반환하는 환경에서, When `trex.slots.req` 조회, Then 해당 슬롯 행에 `strategy_name="tvr_v1"`, `strategy_params={"target_weight": 0.05}`, `markets=["KRX"]` 가 포함된다.
2. **hub 미제공 safe-default**: Given portfolio-hub 응답에 `strategy_name`·`markets` 키가 없는 구버전 응답 환경에서, When `trex.slots.req` 조회, Then 행의 `strategy_name=null`, `strategy_params={}`, `markets=[]` 이고 데몬이 중단되지 않는다.
3. **strategy 필터 — 매칭**: Given `strategy_name="tvr_v1"` 인 슬롯과 `strategy_name="orb_v1"` 인 슬롯이 공존하는 인스턴스에서, When `{strategy:"tvr_v1"}` 요청, Then `strategy_name="tvr_v1"` 인 슬롯 행만 반환된다.
4. **strategy 필터 — 미지정**: Given 동일 인스턴스에서, When `strategy` 없이 요청(기존 포맷), Then 모든 슬롯 행이 반환되고 응답 내용이 `strategy` 도입 전과 동일하다(기존 필드 불변 — 신규 필드만 추가).
5. **AND 조합**: Given `strategy_name="tvr_v1"` 인 holding 슬롯과 `strategy_name="tvr_v1"` 인 inactive 슬롯이 있는 환경에서, When `{filter:"holding", strategy:"tvr_v1"}` 요청, Then `strategy_name="tvr_v1"` + status `holding` 인 슬롯만 반환된다.
6. **available_slots 불변**: Given `max_active_slots=10`, 현재 active 3개인 인스턴스에서, When `{strategy:"tvr_v1"}` 요청(tvr_v1 슬롯이 1개뿐이라도), Then `available_slots=7`(인스턴스 전체 기준). strategy 필터가 available_slots 계산에 영향을 미치지 않는다.
7. **orb·tsl 회귀 없음**: Given 기존 orb-v1 또는 tsl-v1 소비자가 `strategy` 파라미터 없이 기존 요청 포맷을 전송하는 경우, When 처리, Then 응답 키 집합 및 기존 필드 값이 변경 전과 동일하다(신규 `strategy_name`·`strategy_params`·`markets` 필드 추가는 backward compatible — unknown 필드 무시 계약).
8. **계약 테스트 갱신**: Given 슬롯 계약 테스트(`EXPECTED_SLOT_FIELDS` 등)가 존재하는 경우, When 본 REQ 구현, Then 계약 테스트가 신규 필드를 포함하도록 갱신되고 통과한다.
## Impacted Area
- Docs:
- `docs/interface-contract.md` — 요청 파라미터(`strategy` 추가) + 행 스키마(`strategy_name`·`strategy_params`·`markets` 추가) + 정본 소스 테이블 + REQ-074 AC-5 주석 갱신
- Modules:
- `trex_core/application/portfolio.py` — `PortfolioItem` 에 `strategy_name: Optional[str]`·`markets: list[str]` 필드 추가; `slot_to_dict()` 에서 SnapshotStore 의 `PortfolioItem` strategy 필드 읽기
- `trex_core/adapters/portfolio/hub_read.py` — `get_portfolios()` 에서 `strategy_name`·`markets` 파싱 추가
- `trex_core/application/messaging_handlers.py` — `make_slots_rpc_handler()` 에서 `strategy` 파라미터 파싱 + strategy 필터 적용(행 후처리 or slot_to_dict 이후 Python 필터)
- Tests:
- `tests/application/test_slots_handler.py` (또는 신규) — strategy 필터 AC-3/4/5, available_slots 불변 AC-6, 회귀 AC-7
- `tests/application/test_slot_to_dict.py` (또는 기존 행 스키마 테스트) — strategy 필드 노출 AC-1/2
- 슬롯 계약 테스트(`EXPECTED_SLOT_FIELDS` 등) — AC-8 갱신
## Notes
- **REQ-074 AC-5 와의 관계**: REQ-074 AC-5 는 dcy-025 OQ-4 당시 "전략↔자산 할당 모델 미확정" 사유로 strategy 필드 전체를 제외했다. 본 REQ 는 그 유보 결정을 additive 로 개정(OQ-4 후속 확정)하며, REQ-074 의 기존 AC(1~6) 는 불변이다. REQ-074 에 change-req 를 별도로 기록하지 않고 본 REQ Notes 에 관계를 명기하는 것으로 충분하다 — 이유: REQ-074 는 Implemented 상태이고 AC-5 의 "strategy 계열 제외" 불변식 자체를 파괴하지 않으며, 본 REQ 가 additive 재도입이라는 별도 REQ 근거를 남기는 것이 추적성 측면에서 더 명확하다. 단, 구현 batch 에서 REQ-074 CHG 항목으로도 참조를 남긴다.
- **라이브 wire 계약 변경 — 고위험**: orb-v1·tsl-v1 이 현재 `trex.slots.req` 를 소비 중이다. 신규 필드는 additive(unknown 필드 무시)이므로 orb·tsl 파손 없음이 예상되나, 계약 테스트(AC-8)·회귀 테스트(AC-7) 필수. 구현은 worktree+PR+QC 정식 플로로 진행한다.
- **배포 선행 조건**: portfolio-hub 측 `strategy_name`/`markets`/`strategy_params` 노출 REQ(①)가 배포된 뒤 본 REQ(②)를 배포한다. 선행 배포 전에는 safe-default(AC-2) 로 동작한다.
- **`strategy` 필터 적용 위치**: `strategy_name` 은 SnapshotStore(in-memory) 에 있으므로 DB 레벨 필터가 아닌 Python 레벨 후처리 필터로 구현한다. status 필터(`list_slots(status_filter=...)`)가 먼저 DB 에서 실행되고, 그 결과에 strategy 필터를 Python 으로 적용한다. available_slots 는 필터 이전에 계산한다(AC-6).
- **`strategy` 값 오타/미존재**: `strategy` 로 지정한 값에 매칭되는 슬롯이 없으면 빈 `slots=[]` 를 반환한다(에러 없음 — REQ-073 AC-2 의 unrecognized filter 처리 선례).
- **`PortfolioItem.markets` 타입**: portfolio-hub 가 `markets: list[str]` 를 반환하지 않는 경우(None 또는 키 부재) `[]` 로 처리. `PortfolioItem.markets` 기본값 `field(default_factory=list)`.
- **Open Question**: portfolio-hub 가 `strategy_name` 필드를 `active_strategy_id` 와 별도로 반환하는지, 아니면 `active_strategy_id` 를 `strategy_name` 의미로 사용하는지 portfolio-hub REQ(①) 확정 후 확인 필요. 구현 전에 portfolio-hub 응답 스키마를 검증한다. (현재 hub_read.py 는 `active_strategy_id` 를 파싱하지만 `strategy_name` 은 별도 필드일 수 있다.)
## Change Log
### CHG-20260704-03
- Date: 2026-07-04
- Author: 팀장(Claude) — confirm-req-implemented
#### Change Summary
- Approved → **Implemented**: bat-055 구현 완료. 독립 QC **opus 승격** PASS-WITH-NOTES(blocker 0) — 777 passed 일치, AC 8/8, ★watchdog 굶김 없음 실증 프로브 확인(필터는 응답에만 적용), 미지정 요청 byte-동일 검증. PR #37 사장님 결재·머지(dc6d7a9) = confirm-batch-verification 완료.
- **배포 게이트**: portfolio-hub REQ-055(PR #20) 선행 배포 후 본 변경 배포(선행 전엔 safe-default 무해).
#### Delivery Trace Delta
- Batches: bat-055_20260704_slots-strategy-field-filter (merged, PR #37)
#### Revalidation Impact
- Reverification Needed: no / Existing Implementation Invalidated: no
- Status Recommendation: Implemented
### CHG-20260704-02
- Date: 2026-07-04
- Author: 팀장(Claude) — confirm-req
#### Change Summary
- Proposed → Approved: 팀장 검토·승인. tvr e2e 배관 ②(흘려주기). Notes의 오픈질문(strategy_name 별도 필드 여부)은 portfolio-hub REQ-055(Approved)가 `active_strategy_id`와 **별도 필드 `strategy_name`으로 확정** — 필드명 4종(active_strategy_id/strategy_name/strategy_params/markets) 상호 잠금. 라이브 wire 계약 변경이므로 구현은 worktree+PR+QC 정식 플로, 배포는 REQ-055 후.
#### Acceptance Criteria Delta
- Added/Updated/Removed: 없음
#### Revalidation Impact
- Reverification Needed: no / Existing Implementation Invalidated: no
- Status Recommendation: Approved
### CHG-20260704-01
- Date: 2026-07-04
- Author: trex-core-dev
#### Change Summary
- trex-tvr-v1 Discovery(dcy-001/dcy-002 v3 FR-8, confirmed)로부터 최초 생성(Proposed). `trex.slots.req` additive 확장 — 행 `strategy_name`·`strategy_params`·`markets` 필드 추가 + 요청 `strategy` 필터 추가. REQ-074 AC-5 additive 재도입(dcy-025 OQ-4 후속).
#### Intent
- trex-tvr-v1 이 `strategy="tvr_v1"` 필터로 자기 슬롯만 수신하고 행의 `strategy_params.target_weight` 로 리밸런싱할 수 있도록 wire 계약을 확장.
#### Acceptance Criteria Delta
- Added:
- AC-1~8 신규
- Updated: none
- Removed: none
#### Impacted Area Delta
- Docs: docs/interface-contract.md (요청·응답 스키마 갱신)
- Modules: portfolio.py / hub_read.py / messaging_handlers.py
- Tests: slots 핸들러·행 스키마·계약 테스트
#### Delivery Trace Delta
- Batches: none (승인 후 draft-batch)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no (신규)
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Proposed)
- Follow-up Action: confirm-req → suggest-batch-reqs → draft-batch
#### Validation Plan
- 신규 batch: 행 필드 단언(AC-1/2), strategy 필터 단위(AC-3/4/5), available_slots 불변(AC-6), orb·tsl 회귀(AC-7), 계약 테스트 갱신(AC-8).