diff --git a/docs/discovery/dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve.md b/docs/discovery/dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve.md new file mode 100644 index 0000000..cd76f55 --- /dev/null +++ b/docs/discovery/dcy-011_20260608_buy-intent-portfolio-id-required-symbol-resolve.md @@ -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 diff --git a/docs/discovery/index.md b/docs/discovery/index.md index f01b7d1..8f82079 100644 --- a/docs/discovery/index.md +++ b/docs/discovery/index.md @@ -15,4 +15,5 @@ | dcy-007_20260606_core-autonomous-safety-sell | 20260606 | core 자율 안전 매도 — stop-loss·시간 만기 자동 트리거 | [Discovery](./dcy-007_20260606_core-autonomous-safety-sell.md) | confirmed | | 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 | \ No newline at end of file +| 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 | \ No newline at end of file