docs: add discovery dcy-011

This commit is contained in:
2026-06-08 12:28:17 +09:00
parent 565af6792c
commit a24ebb242e
2 changed files with 239 additions and 1 deletions
@@ -0,0 +1,237 @@
# 0. 문서 상태
이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다.
- 상태: confirmed
- 문서 ID: dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve
- 이슈명: buy intent — portfolio_id를 필수 키로, symbol은 universe(SnapshotStore)에서 resolve (+ portfolio_id 누락 체결의 ledger silent skip 가시화)
- 작성 시각(KST): 2026-06-08 11:08 KST
- 마지막 갱신 시각(KST): 2026-06-08 12:23 KST
- 대체됨: 없음
- 후속 Discovery 참조: 없음
- 생성된 REQ 참조: 없음
# 1. 계획 상태 요약
현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다.
- 연계 문서 현황:
- 관련 점수 파일: 미생성
- 관련 TODO/메모: GitHub issue #6, issue #11 (fourblocks2020/trex-core)
- 해석:
- 매수(buy) intent 계약이 `symbol` 필수 / `portfolio_id` optional 로 되어 있어, 정식 식별자(asset_id=portfolio_id) 기반 원장 귀속·safety 보호 범위와 정합이 깨지는 문제를 정식 SDLC 주기로 착수한다.
- 이번 Discovery에서는 buy intent payload 계약을 `portfolio_id` 필수 + 서버측 `symbol` resolve 로 전환하는 범위/리스크/하위호환 경계를 판정한다. 더불어 issue #11 에서 관측된 동일 근본 원인(portfolio_id 없는 슬롯 체결이 ledger 에 silent skip 되어 데이터 누락·운영 가시성 부재)을 함께 흡수해, 예방(admission 거부)과 탐지/가시화(skip 영구 기록·경고)를 한 주기로 다룬다. 이미 Implemented·released(REL-003) 된 계약 변경이므로 거버넌스는 OQ-3 결정에 따라 기존 REQ(REQ-007/021/018) `change-req` 를 우선하고, 기존 REQ 가 다루지 않는 신규 기능(운영 점검 쿼리 등)만 신규 REQ 로 생성한다.
# 2. 요구사항 판정 결과
이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다.
- 판정: 신규
- 근거
- 기존 Discovery(dcy-001~dcy-010) 중 buy intent 식별자 계약(portfolio_id 필수화 / symbol resolve)을 다룬 문서는 없다. dcy-004(원장 연동)·dcy-005(snapshot read)·dcy-007/dcy-008(safety)은 portfolio_id 를 전제하지만 buy 제출 계약 자체를 재정의하지 않았다.
- 변경이 이미 Implemented·released 된 buy intent 인터페이스 계약(REQ-007 제출, REQ-021/022 메시지 계약, REL-003 동작)에 닿아 핵심 식별자 의미를 바꾸므로, 기존 Discovery 미세 조정이 아니라 독립 주기로 추적하는 것이 명확하다.
# 3. 문제점의 요약
문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다.
- 현재 상태
- `trex_core/application/intents.py` 의 `BuyIntent` dataclass 는 `symbol: str`(필수, intents.py:50)이고 `portfolio_id: Optional[str] = None`(optional, intents.py:56) 이다. `_admit_buy`(intents.py:141~)는 `find_idle_slot` 으로 idle 슬롯을 자동 배정한 뒤 `symbol`/`portfolio_id` 를 슬롯에 그대로 기록한다 — symbol 은 필수로 들어오고 portfolio_id 는 없을 수 있다.
- `trex_core/application/messaging_handlers.py` buy 핸들러(73~88행)는 `symbol=str(body.get("symbol") or "")`, `portfolio_id=_opt_str(body.get("portfolio_id"))` 로 파싱해 현 계약(symbol 필수 추정, portfolio_id optional)을 그대로 반영한다.
- universe→symbol resolve 의 기반은 이미 존재한다: `trex_core/application/portfolio.py` 의 `SnapshotStore.get(portfolio_id)`(portfolio.py:130)가 `SnapshotAsset{portfolio_id, symbol, ...}` 를 반환한다. 즉 portfolio_id→symbol 조회 경로는 구현돼 있으나 admission 에서 사용하지 않는다.
- `docs/interface-contract.md` 의 buy payload 계약(79~86행)은 `"symbol": str` 을 기본 필드로, `"portfolio_id": str?` 를 optional 로 명시한다. 즉 문서 계약도 현 코드와 일치한다.
- (issue #11) `trex_core/application/execution.py` 의 `_record_ledger`(execution.py:153~164)는 `slot.portfolio_id` 가 falsy 면 `r.ledger_skipped += 1` 후 즉시 반환한다. 슬롯은 holding/closed 로 정상 전이되지만 `ledger_outbox` 에 행이 생기지 않아 portfolio-hub 에 거래가 전혀 기록되지 않는다. 스킵은 `ExecutionResult` 의 메모리 카운터로만 남고 로그·DB 어디에도 영구화되지 않아 운영자가 누락을 인지하기 어렵다(무성 실패). 실관측: 슬롯 `6e75f3ec-...`(symbol 316140)는 buy/sell 모두 체결돼 closed 됐으나 portfolio_id=None 으로 outbox 0건.
- baseline 문서(`docs/project-structure.md`, `docs/runtime-flows.md`)는 존재하며 최신이다. buy admission 은 기존 runtime flow 에 포함돼 있고, 이번 변경은 그 흐름에 symbol resolve 단계를 추가한다.
- 기대 상태
- buy intent 는 `portfolio_id`(=asset_id, 정식 식별자) 를 필수로 요구하고, `symbol` 은 admission 시 서버가 `SnapshotStore` universe 에서 resolve 해 슬롯에 기록한다.
- portfolio_id 가 universe 에 없으면 명확한 reject(`unknown_portfolio`)로 처리되어, 원장 귀속 불가·safety 보호 누락 슬롯이 생기지 않는다.
- (issue #11) 만에 하나 portfolio_id/execution_id 누락으로 ledger skip 이 발생하더라도 무성으로 사라지지 않고 WARN/ERROR 로그·메트릭으로 노출되며, closed 슬롯 vs outbox 대조 점검 쿼리로 운영자가 누락을 탐지·집계할 수 있다.
- 이해관계자
- 문서 작성자(AI agent) — Discovery/REQ/Batch 산출물 작성
- 리뷰어/승인자 — 계약 변경 및 하위호환 영향 승인
- 운영 담당자 — released(REL-003) buy 계약 변경에 따른 전략 모듈/배포 영향 관리
- 전략 모듈 개발자 — buy intent 제출 호출부(payload) 변경 대상
- 제약사항
- 이미 released(REL-003) 된 인터페이스 계약 변경이므로 ad-hoc 수정이 아니라 정식 SDLC(change-req 또는 신규 Discovery) 경유가 필요하다.
- 매수 시점 universe(`SnapshotStore`)에 해당 portfolio_id 가 존재한다는 보장이 거래일/refresh 주기에 의존한다 — resolve 실패 처리 정책이 필요하다.
## 주요 사용자 시나리오
사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다.
- 전략 모듈이 universe snapshot(`PortfolioItem{portfolio_id, symbol, ...}`)에서 매수 대상을 고른 뒤, buy intent 에 `portfolio_id` 만 실어 제출하면 core 가 symbol 을 universe 에서 resolve 해 슬롯·KIS 주문에 사용한다.
- 운영자가 특정 portfolio 를 pause/kill-switch 로 보호한 상태에서, portfolio_id 필수화 덕분에 모든 buy 슬롯이 보호 범위에 정확히 귀속된다.
- portfolio_id 가 당일 universe 에 없을 때(상장폐지·종목 제외 등) core 가 `unknown_portfolio` 로 매수를 거부해, 귀속 불가능한 체결이 원장에 들어가지 않는다.
# 4. 이번에 정의할 변경
이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다. 기능, 구조, 규칙 변경을 함께 포함해도 된다.
- buy intent payload 계약을 `portfolio_id` 필수로 전환하고, `symbol` 은 클라이언트 payload 에서 제거해 서버가 universe 에서 resolve 하는 값으로만 사용한다(OQ-1·OQ-2 결정 — override/fallback·레거시 호환 없음).
- admission(`_admit_buy`) 시 `SnapshotStore` 에서 `portfolio_id → symbol` 을 resolve 해 슬롯에 기록하고, universe 에 portfolio_id 부재 시 reject(`unknown_portfolio`) 처리한다.
- (issue #11 제안 ②) `_record_ledger` 의 ledger skip 을 무성에서 가시화로 전환한다 — skip 발생 시 WARN/ERROR 로그·메트릭 노출(OQ-4 결정 — outbox 마커 행은 도입하지 않음; defense-in-depth: portfolio_id 필수화 이후에도 잔존할 수 있는 누락을 탐지 가능하게).
- (issue #11 제안 ③) closed 슬롯 vs `ledger_outbox` 대조 운영 점검 쿼리/알람을 추가해 ledger 누락 슬롯을 주기·온디맨드로 탐지한다.
- 인터페이스 계약 문서(`docs/interface-contract.md`)와 buy admission runtime flow 기술을 새 계약에 맞춰 갱신한다.
## 영향 범위
변경이 미칠 코드/문서/운영 범위를 명시해 REQ 정제와 batch planning에서 추정 누락을 줄인다.
- 코드 영향:
- `trex_core/application/intents.py` — `BuyIntent`(portfolio_id 필수화, symbol 은 클라이언트 입력에서 제거하고 서버 resolve 로 채움), `_admit_buy`(symbol resolve + unknown_portfolio reject)
- `trex_core/application/messaging_handlers.py` — buy 핸들러 payload 파싱/검증(portfolio_id 필수 검사)
- `trex_core/application/portfolio.py` — `SnapshotStore` portfolio_id→symbol 조회 활용(기존 `get` 재사용, 신규 메서드 필요 시 추가)
- (issue #11) `trex_core/application/execution.py` — `_record_ledger` skip 지점 가시화(로그/메트릭). OQ-4 결정으로 `ledger_outbox` 스키마/`LedgerWriter` 변경은 없음(마커 행 미도입)
- (issue #11) 운영 점검 쿼리(FR-5) — `trex_core/adapters/persistence/sql/` 의 slots↔`ledger_outbox` anti-join 점검 SQL 추가(읽기 전용, 스키마 변경 없음)
- 문서 영향:
- `docs/interface-contract.md` — buy payload 계약(portfolio_id 필수, symbol 필드 제거·서버 resolve) 갱신
- `docs/runtime-flows.md` — buy admission 흐름에 symbol resolve 단계 + ledger skip 가시화 반영
- 운영 영향:
- released(REL-003) buy 계약 변경 → 전략 모듈 호출부 마이그레이션 안내 필요
- 거래일 universe refresh 와 매수 시점 정합 운영 점검 필요
- (issue #11) ledger skip 가시화 + 운영 점검 쿼리로 누락을 운영자가 탐지·집계 가능 → 회계 정합(P&L/포지션) 리스크 완화
# 5. 요구사항 목록
실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다.
## 기능 요구사항
- FR-1: buy intent payload 는 `portfolio_id` 를 필수 키로 요구하고, 누락 시 admission 단계에서 `portfolio_id_required` 로 거부한다. (issue #11 제안 ① — 근본 원인 제거)
- FR-2: admission 시 `SnapshotStore` universe 에서 `portfolio_id → symbol` 을 resolve 해 슬롯(및 후속 KIS 주문)에 사용할 symbol 로 기록한다. buy payload 는 클라이언트 symbol 을 받지 않는다(OQ-1·OQ-2 결정 — 완전 서버 resolve).
- FR-3: universe 에 해당 `portfolio_id` 가 없으면 `unknown_portfolio` 로 매수를 거부한다. (OQ-1 결정: 단일 reject 정책 — 클라이언트 symbol 로의 override fallback 은 두지 않는다.)
- FR-4: (issue #11 제안 ②) `_record_ledger` 의 ledger skip 발생 시 무성으로 반환하지 않고 WARN/ERROR 로그 + 메트릭으로 노출한다(OQ-4 결정 — `ledger_outbox` 마커 행은 도입하지 않고 영구 탐지는 FR-5 점검 쿼리에 위임). portfolio_id 누락·execution_id 누락 두 skip 경로 모두 포함한다.
- FR-5: (issue #11 제안 ③) closed 슬롯 중 대응 `ledger_outbox` 행이 없는 케이스를 anti-join 으로 식별하는 운영 점검 쿼리/알람을 제공한다(slots 테이블이 durable 하므로 outbox 마커 없이도 영구 탐지 성립 — OQ-4 영구성 위임). 주기 실행 또는 온디맨드 점검으로 누락을 운영자가 탐지·집계할 수 있어야 한다.
- FR-6: `docs/interface-contract.md` 와 `docs/runtime-flows.md` 를 새 buy 계약(portfolio_id 필수 + symbol resolve) 및 ledger skip 가시화/운영 점검에 맞춰 갱신한다.
## 비기능 요구사항
성능, 운영성, 일관성, 자동화 안정성 등 기능 외 요구사항을 적는다.
- NFR-1: 원장 정합성 — 모든 매수 슬롯이 `portfolio_id`(asset_id)에 귀속되어 outbox correlation_id(`asset_id:order_id:execution_id`) 및 portfolio-hub ledger 기록이 누락 없이 성립해야 한다.
- NFR-2: safety 일관성 — pause(REQ-032)·kill-switch(dcy-008)·포지션 정합(REQ-031)·snapshot masking 의 portfolio_id 기준 보호 범위에서 누락되는 buy 슬롯이 없어야 한다.
- NFR-3: 즉시 cutover 정합 — 하위호환을 두지 않으므로(OQ-2 결정), 기존 symbol 기반 호출부(전략 모듈/테스트)를 모두 식별해 portfolio_id 기반으로 동시 전환하고, 전환 누락 시 명확히 실패(거부)하도록 보장한다.
- NFR-4: (issue #11) 운영 가시성 — ledger skip 같은 회계 누락 이벤트는 메모리 카운터에만 남지 않고 로그/메트릭/DB 중 최소 하나로 영구 관측 가능해야 한다(무성 실패 금지).
## 범위 경계
이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다.
- In Scope
- buy intent 계약의 portfolio_id 필수화 및 admission 시 symbol resolve
- universe 부재 시 reject 처리 및 인터페이스/런타임 문서 갱신
- (issue #11 제안 ②) ledger skip 의 가시화(로그/메트릭) — defense-in-depth
- (issue #11 제안 ③) closed 슬롯 vs ledger_outbox 대조 운영 점검 쿼리/알람 (OQ-5 결정: 포함)
- Out of Scope
- sell intent 계약 변경(이미 portfolio_id/slot 기반으로 동작)
- universe refresh 주기/스케줄 자체의 재설계
- symbol-only 레거시 호출 한시 허용(호환 창구) — OQ-2 결정으로 미지원(즉시 hard cutover)
# 6. 리스크/가정 목록
불확실성과 전제 조건을 분리해서 적는다. 리스크는 영향과 완화 방안을, 가정은 현재 판단의 전제를 기록한다.
## 리스크
- R-1 (High): released(REL-003) buy 계약을 깨는 변경이라 기존 symbol 기반 전략 모듈/테스트 호출이 즉시 실패할 수 있다.
- 완화 방안: (OQ-2 결정 — 즉시 cutover) 호환 창구는 두지 않으므로, 전략 모듈·테스트 등 모든 호출부를 사전 식별해 동시에 portfolio_id 기반으로 전환하고, change-req 로 REQ-007/021(및 #11 관련 REQ-018) 변경 이력을 남긴다.
- R-2 (Medium): 매수 시점 universe(`SnapshotStore`)에 portfolio_id 가 없으면(refresh 타이밍·종목 제외) 정상 매수가 `unknown_portfolio` 로 거부될 수 있다.
- 완화 방안: resolve 실패 시 `unknown_portfolio` 단일 reject 정책(OQ-1)을 적용하고, 거부 시 진단 가능한 reason/로그를 남긴다. 거래일 universe refresh 와 매수 시점 정합은 운영 점검 대상으로 둔다.
- R-3 (Low, OQ-1·OQ-2 결정으로 해소): symbol override/fallback·레거시 호환을 모두 두지 않으므로, override 값과 resolve 값의 불일치 모호성이 발생하지 않는다.
- 완화 방안: symbol 은 클라이언트 입력 없이 항상 서버가 universe 에서 resolve 한 값만 사용한다.
- R-4 (Medium, issue #11): portfolio_id 필수화 이전(또는 마이그레이션 창구 중)에 발생한 누락 체결은 이미 ledger_outbox 에 행이 없어 탐지/대응이 늦어질 수 있다.
- 완화 방안: skip 가시화(FR-4)와 운영 점검 쿼리(FR-5)로 신규/잔존 누락을 탐지·집계한다. (과거 누락분의 데이터 복구는 #11 의 명시 요구가 아니므로 본 주기 범위 밖이며, 필요 시 별도 운영 이슈로 다룬다.)
## 가정
아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다.
- A-1: `SnapshotStore` 가 admission 시점에 당일 universe 를 보유하며 `get(portfolio_id)` 로 symbol 을 신뢰성 있게 조회할 수 있다.
- A-2: 전략 모듈은 이미 universe snapshot 에서 portfolio_id 를 받아 매수 결정을 내리므로, payload 에서 symbol 을 빼고 portfolio_id 를 싣는 변경이 전략 측 로직에 큰 부담이 아니다.
- A-3: 이번 변경은 buy 경로에 한정되며 sell/kill-switch/pause 등 portfolio_id 기반 기능은 그대로 호환된다.
- A-4: (issue #11) `_record_ledger` 의 execution_id 누락 skip 경로도 동일한 가시화 처리 대상이며, ledger skip 가시화는 슬롯 전이 동작 자체를 바꾸지 않고 관측만 추가한다.
## 오픈 질문
답을 아직 모르는 항목을 적는다. 추정으로 덮지 말고 REQ 초안 작성 이전에 확인할 질문으로 남긴다.
- OQ-1: universe 에 portfolio_id 가 없을 때 처리 정책 — `reject(unknown_portfolio)` 단일 정책인가, symbol override fallback 을 허용하는가?
- 상태: Answered (2026-06-08, 사용자 결정 — `reject(unknown_portfolio)` 단일 정책)
- 결정: universe 부재 시 항상 `unknown_portfolio` 로 거부한다. 클라이언트가 보낸 symbol 로의 fallback 은 두지 않는다(원장 정합·식별자 유일성 우선).
- 반영 위치: FR-3, R-3(override fallback 경로 제거로 불일치 위험 해소)
- OQ-2: 하위호환 — 기존 symbol 기반 호출(전략 모듈/테스트)을 한시 허용하는 마이그레이션 창구를 둘지, 즉시 hard cutover 할지?
- 상태: Answered (2026-06-08, 사용자 결정 — 하위호환 없음 / 즉시 hard cutover)
- 결정: 호환 창구를 두지 않는다. symbol 은 payload 에서 제거하고, 모든 호출부를 portfolio_id 기반으로 동시 전환한다. 전환 안 된 호출은 `portfolio_id_required` 등으로 명확히 거부된다.
- 반영 위치: FR-1/FR-2, NFR-3, 범위 경계 Out of Scope, R-1
- OQ-3: 거버넌스 경로 — 본 변경을 신규 REQ(이 Discovery 기반)로 추적할지, 기존 REQ-007/021/022 의 change-req 로 처리할지?
- 상태: Answered (2026-06-08, 사용자 결정 — 가능하면 기존 REQ change-req, 필요 시에만 신규 REQ)
- 결정: 기존 Implemented REQ 본문 수정으로 다룰 수 있는 변경은 `change-req` 로 처리한다. change-req 우선 대상 — REQ-007(intent 제출 API: portfolio_id 필수화), REQ-021(메시지 계약 매핑: buy payload 에서 symbol 제거), REQ-018(체결→원장 기록 fill hook: ledger skip 로그/메트릭 가시화). 기존 REQ 가 다루지 않는 신규 기능(closed 슬롯 vs ledger 대조 운영 점검 쿼리/알람, FR-5)은 신규 REQ 로 생성한다. (OQ-4 로 outbox 마커 행을 두지 않으므로 REQ-019 outbox durability 본문 변경은 원칙적으로 불필요 — REQ 정제에서 영향 확인 후 필요 시에만 포함.)
- 반영 위치: 4. 거버넌스 해석, R-1 완화 방안, 8. 확인 체크
- OQ-4: (issue #11) ledger skip 영구 가시화 방식 — WARN/ERROR 로그+메트릭만으로 충분한가, `ledger_outbox` 에 `skipped` 상태 행까지 남겨 사후 대조 가능하게 할 것인가?
- 상태: Answered (2026-06-08, 사용자 결정 — 로그+메트릭만)
- 결정: skip 시 WARN/ERROR 로그 + 메트릭만 노출하고 `ledger_outbox` 마커 행은 도입하지 않는다. 근거 — skip 마커는 정작 outbox 행 식별자(portfolio_id/execution_id)가 비어 있는 기형 행이 되어 전송 큐 의미를 오염시키고 dispatcher 필터링·스키마 마이그레이션을 요구한다. 영구 탐지는 slots↔outbox anti-join(FR-5)으로 충족된다. 또한 OQ-1·OQ-2 로 portfolio_id 누락 skip 주원인이 admission 에서 제거되어 잔여 skip(execution_id None)은 드문 방어 케이스다.
- 반영 위치: FR-4, FR-5
- OQ-5: (issue #11 제안 ③) closed 슬롯 vs ledger_outbox 대조 운영 점검 쿼리/알람을 이번 주기에 포함할지, 후속으로 분리할지?
- 상태: Answered (2026-06-08, 사용자 결정 — 포함)
- 결정: 운영 점검 쿼리/알람을 이번 주기 In Scope 로 포함한다(FR-5 반영).
- 반영 위치: FR-5, 범위 경계 In Scope, R-4 완화 방안
# 7. 초기 성공 기준
이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. 가능하면 데이터 출처까지 연결한다.
- S-1: portfolio_id 누락 buy intent 가 100% `portfolio_id_required` 로 거부되고, portfolio_id 만으로 제출한 buy 가 symbol resolve 를 거쳐 정상 admit 된다.
- S-2: admit 된 모든 매수 슬롯이 portfolio_id(asset_id)에 귀속되어 outbox correlation_id 와 ledger 기록이 누락 없이 생성된다.
- S-3: (issue #11) ledger skip 이 발생하는 테스트 시나리오에서 무성 반환이 아니라 WARN/ERROR 로그·메트릭이 100% 남는다.
- S-4: (issue #11 제안 ③) 운영 점검 쿼리가 ledger 누락 closed 슬롯을 정확히 식별한다(누락 슬롯 주입 시 검출, 정상 케이스 시 0건).
- S-5: 변경된 buy 계약이 `docs/interface-contract.md` 와 `docs/runtime-flows.md` 에 반영되고, 코드(intents.py / messaging_handlers.py / execution.py)와 문서가 일치한다.
## 측정 방식 및 데이터 출처
각 성공 기준을 어떻게 측정할지와 어떤 데이터나 문서를 근거로 쓸지 적는다.
- S-1 측정 방식: 단위/통합 테스트(portfolio_id 누락·정상·unknown_portfolio 케이스) 통과 / 데이터 출처: `_admit_buy`, buy 핸들러 테스트 결과
- S-2 측정 방식: 매수 시나리오 후 슬롯·outbox·ledger 귀속 검증 / 데이터 출처: 슬롯 스냅샷, outbox correlation_id, portfolio-hub ledger 레코드
- S-3 측정 방식: portfolio_id/execution_id 누락 강제 주입 테스트에서 로그·메트릭 발생 확인 / 데이터 출처: `_record_ledger` 테스트, 데몬 로그, 메트릭
- S-4 측정 방식: 누락 슬롯 주입 후 운영 점검 쿼리 실행 결과 대조 / 데이터 출처: 점검 쿼리 결과, 슬롯·`ledger_outbox` 테이블
- S-5 측정 방식: 코드-문서 정합 리뷰(diff 대조) / 데이터 출처: `docs/interface-contract.md`, `docs/runtime-flows.md`, 변경 코드 diff
# 8. REQ로 넘기기 전 확인 체크
REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다.
- [x] 범위(In Scope/Out of Scope) 확정
- 기준: 하위호환 정책이 확정됨 (OQ-2 — 즉시 hard cutover, 호환 창구 없음). 호출부 전환 대상의 구체 식별·수정은 REQ/batch 단계 작업으로 넘김(비차단).
- [x] 성공 지표의 측정 방식/데이터 출처 확정
- 기준: S-1~S-5 의 테스트/검증 출처가 실제 실행 가능한 형태로 지정됨
- [x] High 영향 리스크 우선순위 및 해소 책임자 지정
- 기준: R-1 의 change-req 대상(REQ-007/021/018, REQ-019 는 조건부) 추적 방식이 OQ-3 으로 확정됨. 해소 실무 책임자 배정은 REQ/batch planning 단계 담당자 할당 문제로 넘김(비차단).
- [x] 모든 오픈 질문(OQ) `Open` 상태 없음 확인
- 기준: OQ-1~OQ-5 모두 `Answered`, `Open` 상태 0개
- [x] Freeze 확정 담당자(CONFIRMED_BY) 지정
- 기준: Confirmed By = Justin (사람 승인자 지정 완료)
# 9. 파일 처리 결과
이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다. 이후 추적과 리뷰 시 근거로 사용한다.
- 처리 결과: 생성
- 생성 경로: docs/discovery/dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve.md
- 참조 문서:
- GitHub issue #6 (fourblocks2020/trex-core) — buy intent portfolio_id 필수화 제안
- GitHub issue #11 (fourblocks2020/trex-core) — portfolio_id 없는 거래의 ledger silent skip 버그(동일 근본 원인, 가시화 범위 흡수)
- docs/interface-contract.md — 현행 buy payload 계약(symbol 필수 / portfolio_id optional)
- docs/discovery/dcy-004_20260604_portfolio-hub-ledger-integration.md — asset_id=portfolio_id 원장 귀속 근거
- trex_core/application/execution.py:153-178 — `_record_ledger` ledger skip 지점(issue #11)
# 10. 사용자 결정 필요 항목 요약
사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. 결정, 확인, 데이터 요청을 구분해서 적는다.
## DECIDE
- (없음 — 모든 결정 항목이 OQ-1~OQ-5 확정으로 해소됨)
> 결정 완료(2026-06-08): OQ-1 universe 부재 처리 = `reject(unknown_portfolio)` 단일 정책 / OQ-2 하위호환 = 없음(즉시 hard cutover) / OQ-3 거버넌스 = 기존 REQ change-req 우선·필요 시 신규 REQ / OQ-4 skip 가시화 = 로그+메트릭만(outbox 마커 없음) / OQ-5 운영 점검 쿼리·알람 = `포함`(FR-5). 모두 결정 항목에서 제외됨.
## CONFIRM
- 없음 — 거버넌스 경로는 OQ-3 으로 확정됨(기존 REQ-007/021/018/019 change-req 우선, 신규 기능만 신규 REQ).
## DATA
- 없음(차단 항목 기준) — 매수 시점 universe(SnapshotStore)에 대상 portfolio_id 존재 보장 여부는 운영 런타임 데이터로, REQ/delivery 단계에서 계측·확정한다. 부재 케이스는 FR-3 의 `unknown_portfolio` reject 와 R-2 로 이미 처리되므로 Discovery confirm 을 막지 않는다.
# 11. Discovery Freeze
REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다. 내용 재작성 없이 원본 섹션을 링크로 대신한다.
## 섹션 참조
- 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록)
- 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록)
- 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준)
- 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크)
- 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약)
## Freeze 플래그
- Handoff Decision: 승인
- Handoff Rationale: confirm-discovery 완료. 오픈 질문 OQ-1~OQ-5 모두 Answered (universe 부재=reject 단일 정책 / 하위호환=없음·즉시 cutover / 거버넌스=기존 REQ change-req 우선·필요 시 신규 REQ / skip 가시화=로그+메트릭만 / 운영 점검 쿼리=포함). C 유형 플레이스홀더 0개, 저장소 사실관계 일치 확인. universe portfolio_id 존재 보장(DATA)은 REQ/delivery 단계 계측 항목으로 비차단 분류. REQ 초안 작성 인계 가능.
- Ready for REQ Drafting: true
- Confirmed By: Justin
- Confirmed At (KST): 2026-06-08 12:23 KST
+1
View File
@@ -16,3 +16,4 @@
| dcy-008_20260607_emergency-stop-kill-switch | 20260607 | 비상 정지/강제 청산(kill-switch) — portfolio/전역 슬롯 청산 + 당일 전략 제외 | [Discovery](./dcy-008_20260607_emergency-stop-kill-switch.md) | confirmed |
| dcy-009_20260607_multi-instance-rabbitmq-topology | 20260607 | 인스턴스별 독립 RabbitMQ 채널 토폴로지 — trex-core 다중 인스턴스 운영을 위한 Topic Exchange + Fanout Exchange per-instance 큐 분리 | [Discovery](./dcy-009_20260607_multi-instance-rabbitmq-topology.md) | confirmed |
| dcy-010_20260607_safety-sell-persistent-rejection-backoff | 20260607 | safety-sell 영속 거부 재시도 백오프 — 장 휴장·잔고 부족·규제 등 지속 거부 상황에서 KIS 주문 spam 방지를 위한 슬롯별 재시도 backoff/cooldown 정책 | [Discovery](./dcy-010_20260607_safety-sell-persistent-rejection-backoff.md) | confirmed |
| dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve | 20260608 | buy intent — portfolio_id를 필수 키로, symbol은 universe(SnapshotStore)에서 resolve (+ issue #11 portfolio_id 누락 체결 ledger silent skip 가시화 흡수) | [Discovery](./dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve.md) | confirmed |