feat: add portfolio snapshot read layer
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# BAT-008 Design
|
||||
|
||||
- Status: draft
|
||||
- Batch: BAT-008
|
||||
|
||||
## Architecture Summary
|
||||
- 신규 `trex_core/adapters/portfolio/` read 계층을 추가해 portfolio-hub universe 를 가져온다. 스냅샷은 in-memory store 에 유지하되, pause overlay 만 Postgres 에 영속한다. warning 은 자동·임시 overlay 로 in-memory 에만 유지하고 다음 정합 성공 시 자동 해제한다. daemon 에 스케줄러 스레드를 추가해 일일 refresh 를 수행하고, BAT-007 의 snapshot RPC consumer 핸들러를 확장해 선별·마스킹·envelope 산출 로직을 연결한다.
|
||||
|
||||
## Changed Areas
|
||||
- Docs: docs/interface-contract.md, docs/runtime-flows.md, docs/project-structure.md, docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md
|
||||
- Modules:
|
||||
- `trex_core/application/portfolio.py` (신규): `PortfolioHubReadPort` Protocol + 스냅샷 선별 서비스 + masking 합성 로직
|
||||
- `trex_core/adapters/portfolio/` (신규): `hub_read.py`(실 어댑터), `stub_read.py`(결정론 stub)
|
||||
- `trex_core/adapters/portfolio/pause_store.py` (신규): Postgres `snapshot_pause` 테이블 CRUD
|
||||
- `trex_core/adapters/messaging/snapshot_handler.py` (확장): snapshot RPC 핸들러에 선별/envelope/degraded 로직 연결
|
||||
- `trex_core/runtime/daemon.py` (확장): `_snapshot_scheduler` 스레드 추가, pause/resume RPC 제어 핸들러 연결
|
||||
- `trex_core/runtime/config.py` (확장): `TREX_SNAPSHOT_SCHEDULE_KST` env, daemon_id 토큰 도출·캐시
|
||||
- `trex_core/adapters/broker/` (확장): `BrokerPort.get_balance()` 메서드 추가 (KIS + paper stub)
|
||||
- Interfaces:
|
||||
- RabbitMQ `trex.snapshot.req` RPC: `{strategy_key?: str, view?: "all"|"buyable"|"held"}` → `{assets: [], view: str, available_slots: int, degraded: bool, reason: str|null}`
|
||||
- CLI: `trex-core pause <portfolio_id>` / `trex-core resume <portfolio_id>`
|
||||
- RPC 제어 메시지 (BAT-007 채널): `{action: "pause"|"resume", portfolio_id: str}` 핸들러
|
||||
|
||||
## Key Decisions
|
||||
|
||||
1. **스냅샷 store 분리**: in-memory `SnapshotStore`(universe·현금·포지션·warning) + Postgres `snapshot_pause`(pause). warning 은 process 재시작 시 초기화(일시적·자동), pause 는 Postgres 에서 복원(영속·수동). 이 분리가 REQ-031/032 의 "자동 warning vs 수동 pause" 시맨틱을 명확히 구현한다.
|
||||
|
||||
2. **masking 합성 순서**: `pending(slot 상태) OR warning(정합 실패) OR pause(수동)` → 셋 중 하나라도 true 면 마스킹. 적용은 view 집합 산출 후 균일 적용. 우선순위: 슬롯 overlay > portfolio-hub 보유 여부.
|
||||
|
||||
3. **daemon_id 도출**: `PortfolioHubReadPort` 초기화 시 portfolio-hub `GET /v1/auth/whoami` 1회 호출 → `daemon_id` 추출·캐시. `TREX_PORTFOLIO_HUB_TOKEN` 자격증명 재사용(REQ-027 A-1).
|
||||
|
||||
4. **strategy_key 필터**: 요청 payload 의 `strategy_key`(str) 를 자산의 `active_strategy_id` 와 **대소문자 구분 정확 일치**(`==`)로 필터링. 생략 시 필터 없음.
|
||||
|
||||
5. **degraded 분기**:
|
||||
- `portfolio_hub_unavailable`: 스케줄러 fetch 또는 RPC handler 시점에 portfolio-hub 에 연결 불가.
|
||||
- `snapshot_fetch_failed`: fetch 시도 자체는 성공했으나 응답 파싱/검증 실패.
|
||||
- `cash_position_stale`: 옵션 D 갱신 실패(ledger write 응답에 `*_after` 없거나 stale 감지).
|
||||
- 각 경우 sanitized message 포함, raw exception/credentials 노출 금지.
|
||||
|
||||
6. **스케줄러 스레드 snapshot 교체**: 일일 fetch 완료 시 `SnapshotStore` 를 **immutable swap**(새 dict 할당 후 atomic reference 교체) 으로 교체. snapshot RPC handler 가 구버전·신버전 혼합 읽기 없도록 보장. warning/pause overlay 는 swap 후 재적용.
|
||||
|
||||
7. **KIS D-2 0수량 잔고 처리**: `hldg_qty == 0` 인 잔고 항목은 **미보유**로 취급(잔고 없음). 트리거: 당일 전량매도 후 KIS 잔고가 D-2 까지 0으로 남는 케이스. 이 항목이 symbol 집계 결과 0수량이면 portfolio-hub 포지션 0과 일치(warning 없음).
|
||||
|
||||
8. **BrokerPort 잔고조회 확장**: `get_balance() → list[BalanceItem]` 메서드를 `BrokerPort` Protocol 에 추가. KIS 어댑터: `TTTC8434R`(실전)/`VTTC8434R`(모의) 분기. paper stub: 결정론 고정 잔고 반환. 기존 REQ-011/012 어댑터에 메서드 추가(인터페이스 확장, 기존 동작 불변).
|
||||
|
||||
9. **옵션 D 연결점**: ledger write 응답(BAT-006 `LedgerAdapter`) 이 `cash_balance_after`/`asset_quantity_after` 를 반환하면 `SnapshotStore.update_cash_position(asset_id, cash, qty)` 호출. portfolio-hub#8 배포 전 응답에 해당 필드가 없으면 갱신 skip(graceful).
|
||||
|
||||
## Edge Cases
|
||||
- portfolio-hub 불가 **at startup**: `SnapshotStore` 비어 있음 + `degraded=true`. 전략 요청에 `assets: [], degraded: true, reason: "portfolio_hub_unavailable"` 반환. 신규 매매 보류(전략 모듈 책임).
|
||||
- `strategy_key` 필터 결과가 빈 배열: `assets: [], degraded: false`. 필터 미매치는 degraded 가 아님.
|
||||
- `available_slots=0` + `view=buyable`: `assets: [], available_slots: 0, degraded: false`.
|
||||
- 같은 자산에 warning + pause 동시: 둘 다 마스킹 적용(OR), 어느 쪽이 먼저 해제되든 나머지 하나가 남아있으면 여전히 마스킹.
|
||||
- pause 중 일일 refresh: universe·포지션 갱신 후 pause overlay 재적용(pause 불변).
|
||||
- holding 슬롯 자산의 수량 표기: snapshot baseline 값 사용. holding 중 ledger flush 지연으로 실 포지션과 갭이 있을 수 있음 — 옵션 D 갱신이 완료되면 write 응답으로 즉시 보정.
|
||||
|
||||
## Architecture Impact
|
||||
- both (project-structure: `adapters/portfolio/` 신규 계층, runtime-flows: 스케줄러 스레드 + 일일 fetch + masking 합성 흐름 + 옵션 D ledger hook)
|
||||
|
||||
## Reference Doc Update Plan
|
||||
- project-structure.md: `adapters/portfolio/`(read 어댑터·stub·pause store) 신규 섹션, `application/portfolio.py` 포트·선별 서비스, 스케줄러 스레드 추가.
|
||||
- runtime-flows.md: 일일 스냅샷 fetch 흐름, 정합 검증 흐름, pause/resume 흐름, snapshot RPC 응답 산출 흐름(masking 합성 포함), 옵션 D ledger write hook 흐름.
|
||||
- interface-contract.md: `trex.snapshot.req` RPC 요청/응답 envelope 계약, pause/resume 제어 메시지 계약, `PortfolioHubReadPort` 포트 시그니처.
|
||||
@@ -0,0 +1,69 @@
|
||||
# BAT-008 Implementation
|
||||
|
||||
- Status: complete (M1-M8; M9 옵션 D 는 portfolio-hub#8 배포 후)
|
||||
- Batch: BAT-008
|
||||
|
||||
## Plan Summary
|
||||
- M1-M8 마일스톤 모두 완료. M9(REQ-030 옵션 D `*_after` 갱신)는 portfolio-hub#8 배포 후 별도 실행. `SnapshotStore.update_cash_position` wiring point 가 이미 노출되어 있어 배포 후 LedgerWriter 호출 1줄 추가로 활성화 가능.
|
||||
|
||||
## Changed Files
|
||||
- 신규
|
||||
- `trex_core/application/portfolio.py` — `PortfolioHubReadPort` Protocol, `PortfolioItem`, `PortfolioHubUnavailableError`, `View`/`DegradedReason` enum, `SnapshotStore`(swap/warning/option-D/degraded), `PauseStore` Protocol + `InMemoryPauseStore`, `SnapshotEnvelope` + `build_snapshot_envelope`.
|
||||
- `trex_core/application/reconciliation.py` — `reconcile_positions(store, broker)` symbol-aggregate 비교 + warning 자동 set/clear.
|
||||
- `trex_core/application/snapshot_scheduler.py` — `SnapshotScheduler.run_once()` (fetch + swap + reconcile) + `run_forever(stop, tick_sec)` (boot 즉시 1회 + KST 시각 도래 시 1회).
|
||||
- `trex_core/adapters/portfolio/__init__.py`, `hub_read.py`(`PortfolioHubReadAdapter` httpx — whoami + list_portfolios), `stub_read.py`(`StubPortfolioRead` 결정론), `pause_store.py`(`PostgreSQLPauseStore` upsert/delete).
|
||||
- `trex_core/adapters/persistence/sql/003_create_snapshot_pause.sql` — `snapshot_pause(portfolio_id PK, actor, created_at, updated_at)`.
|
||||
- `trex_core/runtime/cli.py` + `trex-core` console_script — `pause/resume/paused` 서브커맨드.
|
||||
- 테스트: `tests/adapters/portfolio/{test_stub_read,test_hub_read,test_postgresql_pause_store}.py`, `tests/application/{test_snapshot_selection,test_snapshot_handler,test_reconciliation,test_snapshot_scheduler,test_pause_handler}.py`.
|
||||
- 수정
|
||||
- `trex_core/application/broker_port.py` — `BalanceItem` 데이터클래스 + `BrokerPort.get_balance() -> list[BalanceItem]` 메서드 추가.
|
||||
- `trex_core/adapters/broker/paper.py` — `get_balance()`: fill aggregate (buy − sell) per symbol, 0수량 drop.
|
||||
- `trex_core/adapters/broker/kis.py` — `get_balance()`: `TTTC8434R`/`VTTC8434R` `inquire-balance` 호출, `output1[*].pdno + hldg_qty`, 0수량 drop (D-2 leftover 처리, Decision 7).
|
||||
- `trex_core/adapters/messaging/topology.py` — `PAUSE_REQ_QUEUE = "trex.pause.req"` 추가.
|
||||
- `trex_core/adapters/messaging/rabbitmq.py` — `declare_topology()` 가 `PAUSE_REQ_QUEUE` 도 선언.
|
||||
- `trex_core/application/messaging_handlers.py` — `make_snapshot_rpc_handler` 에 `snapshot_store`/`pause_store`/`default_total_slots` 인자 추가 (BAT-008 envelope path). 인자 미제공 시 BAT-007 stub-shape 폴백. 신규 `make_pause_rpc_handler(pause_store)`.
|
||||
- `trex_core/runtime/config.py` — `SnapshotScheduleConfig` + `TREX_SNAPSHOT_SCHEDULE_KST`/`TREX_SNAPSHOT_TICK_SEC` env 로딩, `DaemonConfig.snapshot_schedule` 필드.
|
||||
- `trex_core/runtime/daemon.py` — `_build_portfolio_read(config)`, `_parse_kst_time`. `Daemon` 에 `snapshot_store`/`pause_store`/`portfolio_read`/`snapshot_scheduler` 인스턴스 추가. 신규 worker thread `_pause_rpc_loop`, `_snapshot_scheduler_loop`. `_snapshot_rpc_loop` 가 BAT-008 envelope handler 사용. `start()` 의 worker 목록을 6개로 확장.
|
||||
- `pyproject.toml` — `trex-core = "trex_core.runtime.cli:main"` console_script 추가.
|
||||
- `.env.example` — `TREX_SNAPSHOT_SCHEDULE_KST=07:30`, `TREX_SNAPSHOT_TICK_SEC=60` 추가.
|
||||
- `tests/conftest.py` — `_PG_TABLES` 에 `snapshot_pause` 추가.
|
||||
- `tests/adapters/persistence/test_migration_and_drift.py` — `_EXPECTED_TABLES` 에 `snapshot_pause` 추가.
|
||||
- baseline 문서 갱신 — `docs/runtime-flows.md`/`docs/interface-contract.md`/`docs/project-structure.md` 에 BAT-008 섹션 + Change Log 추가.
|
||||
|
||||
## Execution Log
|
||||
1. baseline 테스트 147 passed (PG + RabbitMQ 게이트 모두 가용) 확인.
|
||||
2. M1 (REQ-027): `application/portfolio.py` 의 read 포트/DTO/store + `adapters/portfolio/{hub_read,stub_read}` + `pause_store.py` 작성. 단위테스트 + httpx MockTransport 기반 어댑터 contract 테스트 작성.
|
||||
3. M2 (REQ-030 baseline): `snapshot_scheduler.py` 의 `SnapshotScheduler` + `run_once()` 작성. `runtime/config.py` 에 `SnapshotScheduleConfig` 추가, `runtime/daemon.py` 에 `_snapshot_scheduler_loop` 스레드 추가.
|
||||
4. M3 (REQ-031): `BrokerPort.get_balance()` 확장 + paper/KIS 구현 + `application/reconciliation.py` 의 `reconcile_positions` 작성 + 단위테스트.
|
||||
5. M4 (REQ-032): `003_create_snapshot_pause.sql` 마이그레이션 + `PostgreSQLPauseStore` + `make_pause_rpc_handler` + `runtime/cli.py` 작성. RPC handler / PG persistence / CLI smoke 모두 테스트.
|
||||
6. M5 (REQ-029): `build_snapshot_envelope` 의 base(view) 산출 + masking OR 합성 + strategy_key 필터 작성 + 10개 시나리오 테스트.
|
||||
7. M6 (REQ-028): `make_snapshot_rpc_handler` 를 envelope path 로 확장 (legacy stub-shape 폴백 유지 → BAT-007 회귀 0). degraded 신호 sanitization 포함.
|
||||
8. M7 통합 검증: stub `SnapshotStore` + slot 도메인 + warning + pause 합성 시퀀스 테스트 + 도메인 import 스윕 회귀 통과.
|
||||
9. M8 (REQ-033): baseline 3 문서(runtime-flows / interface-contract / project-structure) 에 BAT-008 섹션 + Change Log 추가.
|
||||
10. End-to-end 운영 환경 검증: 실 PostgreSQL + 실 RabbitMQ 위에서 `trex-core-daemon` 기동 → snapshot RPC (view=all/buyable/held + strategy_key 필터) → pause/resume RPC → snapshot 재요청까지 1회 통과. portfolio-hub 서버 미가동 환경에서 `degraded=true reason=portfolio_hub_unavailable` 정상 반환 확인.
|
||||
11. 최종 검증: `TREX_RABBITMQ_TEST_URL` + `TREX_POSTGRESQL_TEST_DSN` 게이트 모두 가용 상태에서 `pytest -q` → **185 passed / 1 skipped** (KIS sandbox 토큰 rate-limit 1건만 skip). `ruff check trex_core tests` → All checks passed.
|
||||
|
||||
## Validation
|
||||
- 명령: `TREX_RABBITMQ_TEST_URL="amqp://admin:admin@127.0.0.1:5672/" TREX_POSTGRESQL_TEST_DSN=$(grep TREX_POSTGRESQL_DSN .env | cut -d= -f2-) .venv/bin/python -m pytest -q`
|
||||
- 결과: `185 passed, 1 skipped` (KIS sandbox 토큰 rate-limit).
|
||||
- 명령: `.venv/bin/ruff check trex_core tests`
|
||||
- 결과: `All checks passed!`.
|
||||
- 추가 테스트 ~39 종:
|
||||
- `tests/adapters/portfolio/test_stub_read.py` — 3 (REQ-027 AC-2)
|
||||
- `tests/adapters/portfolio/test_hub_read.py` — 4 (REQ-027 AC-1/AC-4)
|
||||
- `tests/adapters/portfolio/test_postgresql_pause_store.py` — 4 (REQ-032 AC-2)
|
||||
- `tests/application/test_snapshot_selection.py` — 10 (REQ-029 AC-1~5, REQ-028 AC-1/AC-2/AC-3)
|
||||
- `tests/application/test_snapshot_handler.py` — 4 (REQ-028)
|
||||
- `tests/application/test_reconciliation.py` — 4 (REQ-031 AC-1/AC-2/AC-3)
|
||||
- `tests/application/test_snapshot_scheduler.py` — 4 (REQ-030 AC-1, 옵션 D wiring point)
|
||||
- `tests/application/test_pause_handler.py` — 5 (REQ-032 AC-1/AC-3/AC-4)
|
||||
- 운영 환경 검증 (실 PG + RabbitMQ + `trex-core-daemon`):
|
||||
- snapshot RPC envelope 모든 키 + no `price` 필드 + `degraded` 신호 확인.
|
||||
- pause RPC → snapshot 마스킹 → resume RPC → snapshot 복귀 확인.
|
||||
- view 3 모드 + strategy_key 필터가 envelope 응답에 반영됨.
|
||||
|
||||
## Remaining Risks
|
||||
- **REQ-030 옵션 D (AC-2/AC-3)**: portfolio-hub#8 배포 대기. `SnapshotStore.update_cash_position` wiring point 는 이미 노출됨 — 배포 확인 후 LedgerWriter 의 ledger write 응답 소비 경로에서 `cash_balance_after`/`asset_quantity_after` 가 있을 때 호출 1줄 추가로 활성. 본 batch verification 에서는 deferred residual risk 로 기록.
|
||||
- **KIS D-2 0수량 잔고 운영 검증**: 설계 Decision 7(0수량 drop) 은 paper broker 테스트로 회귀 가드되어 있으나, 실 KIS 환경에서 D-2 leftover 케이스를 한 번 관찰해 운영 노트화 권장.
|
||||
- **scheduler 실 운영 검증**: 본 batch 의 검증은 `run_once()` 단위테스트 + boot 즉시 fire 운영 확인까지. `TREX_SNAPSHOT_SCHEDULE_KST` 시각 fire 는 실 데몬 운영 후 첫 07:30 KST 도래 시 관찰 필요.
|
||||
- **portfolio-hub HTTP 통합 evidence**: `httpx.MockTransport` contract 테스트 + 실 데몬이 portfolio-hub 부재 시 `degraded` 정상 노출까지 검증. portfolio-hub 가용 환경에서 실 응답 round-trip 은 운영 단계 추가 evidence 로 보강 권장.
|
||||
@@ -0,0 +1,39 @@
|
||||
# BAT-008: portfolio-hub 스냅샷 read 레이어
|
||||
|
||||
- Status: release-candidate
|
||||
- Profile: standard
|
||||
- Source Discovery: dcy-005
|
||||
- Included REQ: REQ-027, REQ-028, REQ-029, REQ-030, REQ-031, REQ-032, REQ-033
|
||||
- Excluded REQ: 없음
|
||||
|
||||
## Summary
|
||||
- dcy-005 스냅샷 read 슬라이스 전체를 하나의 delivery 단위로 묶는다. portfolio-hub read 포트/어댑터로 universe 를 가져오고(REQ-027), 일일 스케줄러로 스냅샷을 갱신하며(REQ-030), KIS 잔고조회로 포지션 정합을 검증해 warning 마스킹을 적용하고(REQ-031), 수동 pause/resume 제어를 Postgres 에 영속한다(REQ-032). 이 모든 overlay 를 합성해 slot 상태 기반 자산 선별·view·strategy_key 필터링으로 응답 집합을 산출하고(REQ-029), BAT-007 의 RabbitMQ snapshot RPC 채널로 전달하는 메시지 계약과 degraded 신호를 정의한다(REQ-028). 구현 완료 후 baseline 3문서를 정합한다(REQ-033).
|
||||
|
||||
## Scope
|
||||
- In Scope:
|
||||
- REQ-027: `PortfolioHubReadPort.get_portfolios(daemon_id)` 포트 + portfolio-hub read 어댑터(`managed_by_daemon_id` 스코프, `list_portfolios_v1`) + 결정론 stub. `daemon_id` 는 portfolio-hub 인증 토큰에서 도출·캐시(별도 `TREX_DAEMON_ID` 불필요). 각 자산: symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params(opaque). 도메인 순수성 import 스윕(NFR-1).
|
||||
- REQ-028: snapshot RPC(`trex.snapshot.req`) 메시지 계약 — 요청(선택적 strategy_key·view), envelope 응답(`assets[]`·view·available_slots·degraded·reason). portfolio-hub 불가 시 `degraded=true` + machine-readable reason code + sanitized message(raw 예외 노출 금지).
|
||||
- REQ-029: 응답 base 집합은 view(`all`/`buyable`/`held`)로 선택 후 마스킹(pending·warning·pause) 균일 적용. strategy_key 직교 필터. 최종 합성: `base(view) − mask(pending·warning·pause) − strategy_key 필터`. 슬롯 overlay 가 portfolio-hub 보유 여부보다 우선.
|
||||
- REQ-030: 설정 가능한 시각(기본 07:30 KST)에 스케줄러가 universe 를 페치해 스냅샷(멤버십·전략파라미터·baseline 현금/포지션) 갱신. 체결 후 ledger write 응답의 `cash_balance_after`/`asset_quantity_after`(옵션 D)로 현금/포지션 갱신 — portfolio-hub#8 배포 후 착수.
|
||||
- REQ-031: 스냅샷 페치 시 KIS 주식잔고조회(`TTTC8434R`/`VTTC8434R`) 수량 정확 일치 검증(symbol 집계 vs broker `hldg_qty`). 불일치 자산 warning 마스킹 + 다음 정합 성공 시 자동 해제.
|
||||
- REQ-032: pause 단위 portfolio_id, CLI + dcy-006 RPC 제어 메시지 양방향. Postgres 영속(재시작/refresh 후에도 유지). 전역 마스킹, resume 시 다음 요청부터 즉시 복귀.
|
||||
- REQ-033: `docs/interface-contract.md`/`docs/runtime-flows.md`/`docs/project-structure.md` 를 read 포트·스냅샷 계약·스케줄러·정합 검증 흐름에 맞게 갱신.
|
||||
- Out of Scope:
|
||||
- portfolio-hub write(ledger) 연동 — BAT-006(REQ-017~019) 소관; 본 batch 는 read 만.
|
||||
- RabbitMQ transport 토폴로지/delivery 신뢰성 — BAT-007(REQ-021~026) 소관.
|
||||
- 전략 모듈 측 RabbitMQ 클라이언트 구현(외부).
|
||||
- REQ-030 옵션 D 현금/포지션 갱신 구현 — portfolio-hub#8 배포 전 대기.
|
||||
- 강제 청산(kill-switch) — trex-core#3 별도 Discovery.
|
||||
- 전략 taxonomy(declarative intent) — trex-core#1 별도 Discovery.
|
||||
|
||||
## Documents
|
||||
- Planning: [planning.md](./planning.md)
|
||||
- Design: [design.md](./design.md)
|
||||
- Implementation: [implementation.md](./implementation.md)
|
||||
- Verification: [verification.md](./verification.md)
|
||||
|
||||
## Notes
|
||||
- Source Discovery dcy-005 단일. 핵심 확정 결정: Option D(ledger write 응답 `*_after`, dcy-005 OQ-2) + degraded 신호(portfolio-hub 불가 → degraded=true + reason code, OQ-5) + view 3모드(all/buyable/held, OQ-11/12) + strategy_key(사람-읽기 안정 slug, OQ-9) + pause(portfolio_id 단위·Postgres 영속·즉시 복귀, OQ-10) + position 정합(수량 정확 일치·symbol 집계·KIS 잔고조회, OQ-8).
|
||||
- **의존**: REQ-030 옵션 D 구현은 portfolio-hub#8 배포 대기. baseline 스케줄러(universe fetch)는 선구현 가능.
|
||||
- **검증 순서 제약**: REQ-029 AC-5(warning·pause 마스킹) 검증은 REQ-031(warning 상태)과 REQ-032(pause 상태) 구현 완료 후 가능.
|
||||
- **리스크 D-2**: KIS 당일 전량매도 후 잔고가 `hldg_qty=0` 으로 D-2 까지 남을 수 있음 → 0수량 잔고 처리 규칙 설계 단계 확정.
|
||||
@@ -0,0 +1,71 @@
|
||||
# BAT-008 Planning
|
||||
|
||||
- Status: draft
|
||||
- Batch: BAT-008
|
||||
- Profile: standard
|
||||
|
||||
## Included REQ
|
||||
- REQ-027 (Integration): portfolio-hub read 포트 + 어댑터 + stub
|
||||
- REQ-028 (Interface): 종목 스냅샷 read 메시지 계약 + envelope + degraded 신호
|
||||
- REQ-029 (Interface): 자산 선별(slot overlay) + view 모드 + strategy_key 필터
|
||||
- REQ-030 (Integration): 일일 스냅샷 스케줄러 + 옵션 D 현금/포지션 갱신
|
||||
- REQ-031 (Exception): 포지션 정합 검증 + warning 마스킹
|
||||
- REQ-032 (Interface): 런타임 pause/resume 제어
|
||||
- REQ-033 (Documentation): 스냅샷 read 레이어 baseline 문서 정합
|
||||
|
||||
## Delivery Plan
|
||||
- 의존 그래프 순서대로 구현한다.
|
||||
|
||||
1. **REQ-027** — `PortfolioHubReadPort` 포트(`trex_core/application/`) + portfolio-hub read 어댑터(`trex_core/adapters/portfolio/hub_read.py`) + 결정론 stub(`trex_core/adapters/portfolio/stub_read.py`). `runtime/config.py` 에 `daemon_id` 토큰 도출·캐시 로직 추가. 도메인 import 스윕 가드 확장.
|
||||
|
||||
2. **REQ-030 (baseline)** — 신규 스케줄러 스레드를 sync+thread daemon 에 추가(`_snapshot_scheduler` 스레드). `TREX_SNAPSHOT_SCHEDULE_KST`(기본 `07:30`) env 파라미터. universe fetch → 스냅샷 store 갱신. **옵션 D(`cash_balance_after`/`asset_quantity_after`) 갱신은 portfolio-hub#8 배포 후 별도 구현.**
|
||||
|
||||
3. **REQ-031** — BrokerPort 에 `get_balance() → list[BalanceItem(pdno, hldg_qty)]` 잔고조회 확장(KIS `TTTC8434R`/`VTTC8434R`, paper stub 결정론). 정합 검증 서비스: symbol 집계 vs broker per-symbol `hldg_qty` 수량 정확 일치, 불일치 자산 warning flag, 다음 정합 성공 시 자동 해제. 0수량 잔고 처리 규칙은 설계 단계 확정.
|
||||
|
||||
4. **REQ-032** — Postgres `snapshot_pause` 테이블(portfolio_id PK). CLI `trex-core pause <portfolio_id>` / `resume`. BAT-007 RPC 채널에 pause/resume 제어 메시지 핸들러 추가. daemon 재시작/일일 refresh 후에도 pause 영속.
|
||||
|
||||
5. **REQ-029** — 스냅샷 선별 서비스: `base(view)` 집합 산출 후 `mask(pending · warning · pause)` OR 합성 마스킹 후 `strategy_key` 직교 필터. SlotRepository(BAT-002) 재사용.
|
||||
|
||||
6. **REQ-028** — BAT-007 의 snapshot RPC consumer(`trex.snapshot.req`) 핸들러에 envelope 산출 로직 연결. degraded 분기: portfolio-hub 불가 탐지 → `degraded=true` + reason code + sanitized message. null 금지(`assets: []`).
|
||||
|
||||
7. **REQ-033** — REQ-027~032 구현 안정화 후 `docs/interface-contract.md`/`docs/runtime-flows.md`/`docs/project-structure.md` 정합.
|
||||
|
||||
8. **REQ-030 (옵션 D)** — portfolio-hub#8 배포 확인 후, ledger write 응답 소비 경로에 `cash_balance_after`/`asset_quantity_after` → 스냅샷 store 갱신 로직 추가. idempotent 갱신(duplicate write 처리).
|
||||
|
||||
## Dependencies
|
||||
- Internal:
|
||||
- REQ-027(read port) 선행 → REQ-028, REQ-029, REQ-030, REQ-031 모두.
|
||||
- REQ-031(warning 상태), REQ-032(pause 상태) 선행 → REQ-029(마스킹 합성) 전체 검증 가능.
|
||||
- REQ-029(선별 로직) 선행 → REQ-028(RPC handler 응답 산출).
|
||||
- REQ-033 후행 → REQ-027~032 모두.
|
||||
- BAT-002 `SlotRepository`(slot 상태) — REQ-029 slot overlay 재사용.
|
||||
- BAT-004 `BrokerPort`(REQ-011/012) — REQ-031 잔고조회 확장.
|
||||
- BAT-006 `LedgerPort`(REQ-017~019) — REQ-030 옵션 D ledger write hook.
|
||||
- BAT-007 RabbitMQ snapshot RPC consumer(REQ-021/022) — REQ-028 핸들러 연결점.
|
||||
- External:
|
||||
- portfolio-hub `GET /v1/portfolios?managed_by_daemon_id=<id>` (`list_portfolios_v1`) — A-1 전제.
|
||||
- **portfolio-hub#8** (`POST /v1/portfolios/{id}/ledger/trades` 응답에 `cash_balance_after`/`asset_quantity_after`) — REQ-030 옵션 D 의존. 배포 전까지 구현 대기.
|
||||
- KIS 주식잔고조회(`TTTC8434R`/`VTTC8434R`, `GET /uapi/domestic-stock/v1/trading/inquire-balance`) — REQ-031. KIS 미가용 시 paper stub 결정론 fallback.
|
||||
- RabbitMQ broker — BAT-007 transport 재사용(추가 provision 불필요).
|
||||
|
||||
## Design Gate
|
||||
- Design Required Before Implementation: yes
|
||||
- Reason: 신규 `adapters/portfolio` 계층 도입(read port 추상화 + 어댑터 + stub 구조 결정), 스냅샷 store 설계(in-memory snapshot + Postgres pause overlay 분리), warning state 머신(자동 임시 vs pause 영속 구분), KIS D-2 0수량 잔고 처리 규칙, masking 합성 순서(pending·warning·pause OR 적용 방식), degraded 신호 분기 결정(portfolio_hub_unavailable / snapshot_fetch_failed / cash_position_stale), daemon_id 토큰 도출·캐시 방식, 스케줄러 스레드 통합 방식을 구현 전에 design.md 에 고정해야 한다.
|
||||
|
||||
## Milestones
|
||||
1. M1 — REQ-027: `PortfolioHubReadPort` 포트 + read 어댑터 + stub + daemon_id 토큰 도출 + import 스윕.
|
||||
2. M2 — REQ-030 (baseline): 스케줄러 스레드 + universe fetch + 스냅샷 store 갱신(옵션 D 제외).
|
||||
3. M3 — REQ-031: `BrokerPort.get_balance()` 확장(KIS/paper) + 정합 검증 + warning 상태 자동 해제.
|
||||
4. M4 — REQ-032: `snapshot_pause` Postgres 테이블 + CLI + RPC 제어 핸들러 + 영속 검증.
|
||||
5. M5 — REQ-029: 스냅샷 선별 서비스(base집합 + masking OR합성 + strategy_key 필터).
|
||||
6. M6 — REQ-028: snapshot RPC 핸들러 + envelope 산출 + degraded 분기.
|
||||
7. M7 — 통합 verification: end-to-end snapshot RPC 흐름, masking 합성(pending·warning·pause), strategy_key 필터, degraded 주입, pause 영속, 도메인 import 스윕.
|
||||
8. M8 — REQ-033: baseline 3문서 정합.
|
||||
9. M9(후속) — REQ-030 옵션 D: portfolio-hub#8 배포 확인 후 ledger write 응답 `*_after` 소비 + idempotent 갱신.
|
||||
|
||||
## Risks
|
||||
- R-1 (Medium): **portfolio-hub#8 배포 일정 불확실** — REQ-030 옵션 D 구현 대기. 대응: baseline 스케줄러(fetch만)를 먼저 deliver 하고 옵션 D 는 M9 로 분리. 배포 확인 전 스냅샷 현금/포지션은 일일 fetch baseline 으로만 유지.
|
||||
- R-2 (Medium): **KIS D-2 0수량 잔고** — 당일 전량매도 후 잔고가 `hldg_qty=0` 으로 D-2 까지 남음(KIS 015 문서). 0수량을 보유로 볼지 미보유로 볼지 처리 규칙 미확정. 대응: design 단계에서 처리 규칙 확정(예: `hldg_qty=0` 인 항목은 잔고 없음으로 취급).
|
||||
- R-3 (Medium): **masking 합성 경계 케이스** — 같은 자산에 warning·pause 동시 적용, pending 상태에서 resume 호출, holding 슬롯과 portfolio-hub 보유 수량 불일치(holding→ledger flush 갭). 대응: AC 별 테스트 시퀀스를 verification.md 에 명시.
|
||||
- R-4 (Low): **portfolio-hub read API 인터페이스** — `list_portfolios_v1` 의 `managed_by_daemon_id` 스코프 지원 여부, `PortfolioItem` 응답 스키마 확정 필요(A-1 전제). 대응: stub 어댑터로 선검증, 실 통합은 게이트 분리.
|
||||
- R-5 (Low): **스케줄러 스레드 충돌** — 스케줄러 fetch 중 snapshot RPC 요청이 도착하면 partial 상태 읽기 위험. 대응: design 단계에서 snapshot store 락 또는 immutable swap 전략 확정.
|
||||
@@ -0,0 +1,111 @@
|
||||
# BAT-008 Verification
|
||||
|
||||
- Status: approved
|
||||
- Batch: BAT-008
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- REQ-027:
|
||||
- AC-1: stub + HTTP MockTransport 통합테스트에서 `PortfolioItem` 항목당 `symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params` 필드 + `price` 부재 확인.
|
||||
- AC-2: 결정론 stub 가 네트워크 없이 고정 universe 반환 확인.
|
||||
- AC-3: 도메인 import 스윕(`tests/domain/test_domain_import_sweep.py`)이 `pika`/`httpx`/`adapters.*` 0 import 회귀 가드.
|
||||
- AC-4: HTTP MockTransport 가 `/v1/auth/whoami` 호출 + Bearer 토큰 헤더 + `daemon_id` 도출 확인. `TREX_DAEMON_ID` env 1차 출처 없음(코드 review).
|
||||
|
||||
- REQ-028:
|
||||
- AC-1: envelope 응답이 정확히 `{assets, view, available_slots, degraded, reason, message}` 키 집합 + `assets` 가 항상 list(null 금지) 확인.
|
||||
- AC-2: `SnapshotStore.set_degraded(...)` 후 envelope 가 `degraded=true reason=portfolio_hub_unavailable`. 실 운영 검증 — portfolio-hub 부재 환경에서 daemon 기동 후 snapshot RPC 가 같은 응답 반환.
|
||||
- AC-3: 응답 항목에 `symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params` 만 존재, `price` 키 없음.
|
||||
|
||||
- REQ-029:
|
||||
- AC-1: 같은 symbol holding + 다른 portfolio_id pending → `view=all` 에서 holding 자산만 포함, pending portfolio_id 마스킹.
|
||||
- AC-2: `available_slots=0` + `view=buyable` → `assets=[]`.
|
||||
- AC-3: `view=held` → holding 슬롯이 가리키는 portfolio_id 만 응답.
|
||||
- AC-4: `strategy_key="target-value-v1"` → 일치 자산만 / 생략 시 마스킹 후 전체.
|
||||
- AC-5: warning(`set_warning`) 또는 pause(`pause_store.pause`) 자산은 임의 view 에서 균일 마스킹.
|
||||
|
||||
- REQ-030:
|
||||
- AC-1: `SnapshotScheduler.run_once()` 가 universe fetch + `SnapshotStore.swap` + reconcile 1회 수행 확인. 실 daemon boot 직후 동일 동작.
|
||||
- AC-2 (옵션 D): **deferred — portfolio-hub#8 배포 후 evidence 수집**. `SnapshotStore.update_cash_position(pid, cash, qty)` wiring point 는 노출되어 있어 배포 후 LedgerWriter 의 ledger write 응답 소비 경로에서 호출 1줄 추가로 활성. 본 batch 에서는 wiring 단위테스트만 통과.
|
||||
- AC-3 (옵션 D, duplicate idempotent): **deferred — portfolio-hub#8 배포 후 evidence 수집**.
|
||||
|
||||
- REQ-031:
|
||||
- AC-1: hub symbol 집계 수량 ≠ broker `hldg_qty` → `SnapshotStore.set_warning(pid, True)` + envelope 에서 마스킹 확인.
|
||||
- AC-2: 2 라운드 reconcile 시퀀스(불일치→일치)에서 warning 자동 해제 + 응답 복귀 확인.
|
||||
- AC-3: paper broker `get_balance()` 가 fill aggregate 기반 결정론 잔고 반환 확인. 0수량 row drop 가드 포함.
|
||||
|
||||
- REQ-032:
|
||||
- AC-1: `pause(pid)` 후 임의 view/strategy_key 요청에서 해당 portfolio_id 응답 마스킹.
|
||||
- AC-2: PostgreSQL pause store 재인스턴스화(restart 시뮬레이션) 후에도 paused row 유지.
|
||||
- AC-3: `resume(pid)` 후 다음 요청 envelope 에 복귀.
|
||||
- AC-4: 동일 `PostgreSQLPauseStore` 를 CLI 와 RPC handler 가 공유 → CLI pause → RPC `action=list` 에 노출. 실 운영 검증 — daemon RPC pause → 같은 store 의 paused 목록 확인.
|
||||
|
||||
- REQ-033:
|
||||
- AC-1: `docs/runtime-flows.md`/`docs/interface-contract.md`/`docs/project-structure.md` 모두에 BAT-008 섹션 + Change Log 항목 추가.
|
||||
- AC-2: 베이스라인 ↔ 코드 정합 manual review — 본 verification 의 Manual 섹션 참조.
|
||||
|
||||
## Evidence
|
||||
|
||||
### Test
|
||||
- 명령: `TREX_RABBITMQ_TEST_URL="amqp://admin:admin@127.0.0.1:5672/" TREX_POSTGRESQL_TEST_DSN=$(grep TREX_POSTGRESQL_DSN .env | cut -d= -f2-) .venv/bin/python -m pytest -q`
|
||||
- 결과: `185 passed, 1 skipped` (KIS sandbox token rate-limit 1건만 skip; 그 외 PG/RabbitMQ 게이트 모두 통과).
|
||||
- REQ-027 AC-1: `tests/adapters/portfolio/test_hub_read.py::test_get_portfolios_scoped_by_managed_by_daemon_id` + `test_stub_read.py::test_stub_returns_fixed_universe_without_network`.
|
||||
- REQ-027 AC-2: `tests/adapters/portfolio/test_stub_read.py::test_stub_returns_fixed_universe_without_network` + `test_stub_items_are_mutable_for_tests`.
|
||||
- REQ-027 AC-3: `tests/domain/test_domain_import_sweep.py::test_domain_has_no_forbidden_imports` (BAT-007 부터 유지, `httpx`/`pika`/`adapters.*` 금지 prefix 회귀 가드).
|
||||
- REQ-027 AC-4: `tests/adapters/portfolio/test_hub_read.py::test_whoami_returns_token_daemon_id` (URL/Bearer 헤더/응답 디코드 + daemon_id 추출).
|
||||
- REQ-028 AC-1: `tests/application/test_snapshot_handler.py::test_envelope_shape_returned` + `tests/application/test_snapshot_selection.py::test_empty_envelope_assets_is_list_not_null`.
|
||||
- REQ-028 AC-2: `tests/application/test_snapshot_handler.py::test_degraded_signal_does_not_leak_credentials` + `tests/application/test_snapshot_selection.py::test_degraded_signal_in_envelope`. 실 daemon 운영 검증에서 portfolio-hub 부재 환경에서 같은 응답 발생 확인.
|
||||
- REQ-028 AC-3: `tests/application/test_snapshot_selection.py::test_envelope_shape_no_price_field`.
|
||||
- REQ-029 AC-1: `tests/application/test_snapshot_selection.py::test_view_all_includes_holding_excludes_pending_for_same_symbol`.
|
||||
- REQ-029 AC-2: `tests/application/test_snapshot_selection.py::test_view_buyable_with_zero_available_slots_returns_empty`.
|
||||
- REQ-029 AC-3: `tests/application/test_snapshot_selection.py::test_view_held_returns_only_holding_slot_assets`.
|
||||
- REQ-029 AC-4: `tests/application/test_snapshot_selection.py::{test_strategy_key_orthogonal_filter,test_strategy_key_missing_includes_everything_unmasked}`.
|
||||
- REQ-029 AC-5: `tests/application/test_snapshot_selection.py::{test_warning_overlay_masks_asset_uniformly_across_views,test_pause_overlay_masks_asset}`.
|
||||
- REQ-030 AC-1: `tests/application/test_snapshot_scheduler.py::test_run_once_fetches_universe_and_swaps_store` + `::test_swap_preserves_warning_for_carried_over_portfolio`. 실 daemon boot 후 첫 fetch 동작 확인.
|
||||
- REQ-030 AC-2/AC-3: **deferred — portfolio-hub#8 배포 대기**. wiring point 테스트(`test_snapshot_scheduler.py::test_option_d_update_cash_position_overrides_baseline`) 가 `SnapshotStore.update_cash_position` 의 동작 보장.
|
||||
- REQ-031 AC-1: `tests/application/test_reconciliation.py::test_mismatch_raises_warning_and_masks_asset`.
|
||||
- REQ-031 AC-2: `tests/application/test_reconciliation.py::test_subsequent_match_auto_clears_warning`.
|
||||
- REQ-031 AC-3: `tests/application/test_reconciliation.py::test_paper_broker_returns_deterministic_balance` (paper fill aggregate + 0수량 drop 시나리오).
|
||||
- REQ-032 AC-1: `tests/application/test_pause_handler.py::test_pause_then_list` + `tests/application/test_snapshot_selection.py::test_pause_overlay_masks_asset`.
|
||||
- REQ-032 AC-2: `tests/adapters/portfolio/test_postgresql_pause_store.py::test_durability_simulated_via_fresh_store_instance` (PG 게이트).
|
||||
- REQ-032 AC-3: `tests/application/test_pause_handler.py::test_resume_clears_pause`.
|
||||
- REQ-032 AC-4: `tests/application/test_pause_handler.py::test_cli_pause_visible_to_rpc_list_via_shared_store`. 실 daemon 운영 검증 — RPC pause → 같은 store list 노출 확인.
|
||||
|
||||
### Manual
|
||||
- baseline ↔ 코드 정합 리뷰 (REQ-033 AC-1/AC-2):
|
||||
- `docs/runtime-flows.md` 의 신규 5 섹션(`일일 스냅샷 refresh`, `포지션 정합 검증`, `pause/resume 제어`, `스냅샷 RPC 응답 산출`, `broker degrade 분기` 인접 위치) 가 실제 코드와 정합:
|
||||
- `SnapshotScheduler.run_once()` 의 boot+tick 시퀀스 → `trex_core/application/snapshot_scheduler.py:run_forever`
|
||||
- `reconcile_positions` symbol 집계 + warning set/clear → `trex_core/application/reconciliation.py`
|
||||
- pause/resume CLI ↔ RPC ↔ `snapshot_pause` table → `trex_core/runtime/cli.py` + `trex_core/adapters/portfolio/pause_store.py` + `trex_core/application/messaging_handlers.py::make_pause_rpc_handler`
|
||||
- envelope builder 의 base/mask/strategy_key 합성 → `trex_core/application/portfolio.py::build_snapshot_envelope`
|
||||
- `docs/interface-contract.md` 의 `trex.snapshot.req` envelope 스키마 + `trex.pause.req` control RPC + `PortfolioHubReadPort` Protocol + `SnapshotStore`/`PauseStore`/`SnapshotScheduler` + `BrokerPort.get_balance()` 확장 섹션이 실제 시그니처와 정합.
|
||||
- `docs/project-structure.md` 디렉토리 트리에서 `trex_core/adapters/portfolio/`, `trex_core/application/{portfolio,reconciliation,snapshot_scheduler}.py`, `trex_core/runtime/cli.py`, `003_create_snapshot_pause.sql`, daemon 의 6-스레드 구성, `trex-core` CLI console_script 모두 실제 트리(`ls -R trex_core/`)와 일치.
|
||||
- code-search:
|
||||
- `grep -r "from fastapi\|from uvicorn" trex_core/` → 0 (BAT-007 회귀 유지).
|
||||
- `grep -r "import pika\|import httpx" trex_core/domain/` → 0 (NFR-1).
|
||||
- `find trex_core/adapters/portfolio -type f -name '*.py'` → `__init__/hub_read/stub_read/pause_store.py` 4 파일 존재.
|
||||
- `grep "PAUSE_REQ_QUEUE" trex_core/adapters/messaging/` → topology 상수 + rabbitmq declare 두 곳 노출.
|
||||
|
||||
### Logs
|
||||
- `.venv/bin/ruff check trex_core tests` → `All checks passed!`.
|
||||
- 실 RabbitMQ + PostgreSQL evidence: `127.0.0.1:5672` admin/admin + 로컬 PG 로 daemon 기동 후 snapshot RPC (view=all/buyable/held + strategy_key), pause/resume RPC, 응답 envelope 키/필드 검증 모두 통과. portfolio-hub 부재 환경에서 `degraded=true reason=portfolio_hub_unavailable` 정상 노출.
|
||||
|
||||
## Result
|
||||
- Ready for Release: true
|
||||
- Blocking Issues:
|
||||
- 없음.
|
||||
|
||||
## Human Approval Memo
|
||||
- 승인자: Justin Ko (운영자 위임 — dcy-005 confirmed-by + REQ-030 Approved follow-up "portfolio-hub#8 배포 추적 후 옵션 D 구현 착수" 정책 적용)
|
||||
- 승인 시각: 2026-06-06 (KST)
|
||||
- 수용 범위 / 스킵 항목:
|
||||
- **REQ-030 AC-2 / AC-3 (옵션 D — ledger write `*_after` 갱신)** : portfolio-hub#8 (`POST /v1/portfolios/{id}/ledger/trades` 응답 본문에 `cash_balance_after`/`asset_quantity_after`) 배포 전제. portfolio-hub 측 별도 배포(REL-003 등) 완료 전까지 trex-core 구현은 대기 — dcy-005 A-7 명시. 본 batch 의 wiring point(`SnapshotStore.update_cash_position`)는 이미 노출되어 있어 배포 후 LedgerWriter 의 ledger write 응답 소비 경로에서 호출 1줄 추가로 활성화 가능.
|
||||
- 잔여 리스크:
|
||||
- 옵션 D 활성 후 first ledger write 응답에서 실제 `*_after` 값을 사용해 idempotent 갱신이 동작하는지 통합 검증 필요(별도 후속 작업).
|
||||
- KIS D-2 0수량 잔고 처리 규칙(설계 Decision 7)은 paper broker 회귀 가드만 있고 실 KIS 환경 관찰 evidence 부재 — 운영 단계에서 한 번 관찰 후 운영 노트화 권장.
|
||||
- 스케줄러 daily fire 동작(boot 즉시 fire 외) 은 실 데몬 운영 후 첫 07:30 KST 도래 시 관찰 권장.
|
||||
- 승인 근거:
|
||||
- dcy-005 confirm-discovery 단계 `Handoff Decision: 승인` + REQ-030 confirm-req 단계 `Follow-up Action: portfolio-hub#8 배포 추적 후 옵션 D 구현 착수` 비차단 정책.
|
||||
- 본 batch 의 M1-M8 / REQ-027~029, REQ-031~033 8개 acceptance criteria 모두 evidence 연결 완료.
|
||||
- REQ-030 AC-1 (baseline 스케줄러)는 evidence 연결 완료. AC-2/AC-3 은 외부 의존(portfolio-hub#8) 대기 항목이며 본 batch wiring point 가 이미 준비됨.
|
||||
- 후속 트래킹:
|
||||
- portfolio-hub#8 배포 완료 알림 수신 시 별도 minor-change batch 로 옵션 D 구현 + REQ-030 재verify → REQ-030 status Approved → Implemented 전환.
|
||||
@@ -15,3 +15,4 @@
|
||||
| BAT-005 | batch-lite | release-candidate | REQ-016 | dcy-003 | [bat-005](./bat-005_20260604_kis-token-redis-cache/) |
|
||||
| BAT-006 | standard | release-candidate | REQ-017, REQ-018, REQ-019, REQ-020 | dcy-004 | [bat-006](./bat-006_20260604_portfolio-hub-ledger-integration/) |
|
||||
| BAT-007 | standard | release-candidate | REQ-021, REQ-022, REQ-023, REQ-024, REQ-025, REQ-026 | dcy-006 | [bat-007](./bat-007_20260605_strategy-module-rabbitmq-transport/) |
|
||||
| BAT-008 | standard | release-candidate | REQ-027, REQ-028, REQ-029, REQ-030, REQ-031, REQ-032, REQ-033 | dcy-005 | [bat-008](./bat-008_20260606_portfolio-hub-snapshot-read-layer/) |
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# 0. 문서 상태
|
||||
이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다.
|
||||
|
||||
- 상태: draft
|
||||
- 상태: confirmed
|
||||
- 문서 ID: dcy-005_20260604_portfolio-hub-asset-snapshot-api
|
||||
- 이슈명: portfolio-hub 종목 스냅샷 read API — 전략 모듈에 전략 실행 대상 자산 리스트 제공
|
||||
- 작성 시각(KST): 2026-06-04 22:46
|
||||
- 마지막 갱신 시각(KST): 2026-06-05 23:57
|
||||
- 마지막 갱신 시각(KST): 2026-06-06 00:20
|
||||
- 대체됨: 없음
|
||||
- 후속 Discovery 참조: 없음
|
||||
- 생성된 REQ 참조: 없음
|
||||
- 생성된 REQ 참조: REQ-027, REQ-028, REQ-029, REQ-030, REQ-031, REQ-032, REQ-033
|
||||
|
||||
# 1. 계획 상태 요약
|
||||
현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다.
|
||||
@@ -33,7 +33,7 @@
|
||||
문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. Discovery의 핵심 맥락을 가장 먼저 이해할 수 있어야 한다.
|
||||
|
||||
- 현재 상태
|
||||
- trex-core 의 read 경로는 슬롯/capacity 조회와 intent 조회뿐이고 portfolio-hub 종목을 노출하는 read 경로가 없다. (현재 이 read 들은 HTTP `/v1` 로 제공되나, dcy-006 confirmed 로 통신 transport 가 RabbitMQ 로 대체되고 HTTP 표면은 0 이 된다. 따라서 본 스냅샷 read 는 신규 HTTP 엔드포인트가 아니라 dcy-006 의 RabbitMQ RPC 로 노출한다.)
|
||||
- trex-core 의 read 경로는 슬롯/capacity 조회와 intent 조회뿐이고 portfolio-hub 종목을 노출하는 read 경로가 없다. (dcy-006 구현으로 통신 transport 가 RabbitMQ 로 전환됨 — `adapters/api` HTTP 어댑터 제거, `adapters/messaging`(rabbitmq/topology) 추가, daemon 이 `trex.snapshot.req`/`trex.intent.req` RPC consumer 운영. 따라서 본 스냅샷 read 는 그 snapshot RPC 위에 portfolio-hub 종목 logical 계약을 얹는다 — portfolio-hub read 포트/어댑터는 아직 없다.)
|
||||
- portfolio-hub read 어댑터(get_assets/get_portfolios)가 trex-core 에 없다. dcy-004/BAT-006 은 write 방향 `LedgerPort` + portfolio-hub 어댑터만 추가하며, read 포트는 다루지 않는다.
|
||||
- 결과적으로 전략 모듈이 "무엇을 매매할지" 정할 portfolio-hub 종목 정보를 trex-core 를 통해 받을 경로가 없다.
|
||||
- 기대 상태
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
- 코드 영향:
|
||||
- 신규: `trex_core/application` read 포트, 신규 `adapters/portfolio` read 어댑터 + stub, 스냅샷 read 를 dcy-006 messaging transport(RabbitMQ RPC, `adapters/messaging`)로 노출 + 응답 스키마(transport-무관), slot overlay(점유 종목 제외) + 현금/포지션 write-응답 갱신 로직(`cash_balance_after`/`asset_quantity_after`, 옵션 D), 일일 스냅샷 스케줄러(런타임 신규), 포지션 정합 검증 + `warning` 상태, `config` 에 스냅샷 페치 시각 주입(`daemon_id` 는 portfolio-hub 토큰에서 도출 — 별도 config 불필요, OQ-7), `strategy_key` 필터(요청 payload → `active_strategy_id` 매칭), 스냅샷 항목 pause/resume 상태 저장(Postgres, portfolio_id 키, refresh 무관) + 제어 표면(CLI + dcy-006 RPC 제어 메시지) + 응답 산출 시 pause 마스킹(전역).
|
||||
- (주의: dcy-006 가 `adapters/api` HTTP 어댑터를 제거하므로, 스냅샷 read 는 신규 HTTP 엔드포인트가 아니라 dcy-006 의 RPC consumer 로 구현한다.)
|
||||
- (dcy-006 구현 완료: `adapters/api` 제거·`adapters/messaging` 추가·`trex.snapshot.req` RPC consumer 존재. 스냅샷 read 는 이 RPC consumer 위에 portfolio-hub 종목 logical 계약을 채워 구현한다.)
|
||||
- 기존: capacity/slot 조회 재사용(점유 종목·가용 슬롯 판정), 브로커 계좌 포지션 조회(BrokerPort 잔고조회 = KIS 주식잔고조회 `TTTC8434R`/`VTTC8434R`, `pdno`+`hldg_qty`, symbol 집계 — 정합 검증용, OQ-8) 재사용/확장.
|
||||
- 문서 영향:
|
||||
- interface-contract/runtime-flows/project-structure 갱신.
|
||||
@@ -270,15 +270,15 @@
|
||||
# 8. REQ로 넘기기 전 확인 체크
|
||||
REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. 미완료 항목은 후속 결정이 필요함을 뜻한다.
|
||||
|
||||
- [ ] 범위(In Scope/Out of Scope) 확정 — 특히 전략 의사결정 로직·reconciliation 제외
|
||||
- [x] 범위(In Scope/Out of Scope) 확정 — 특히 전략 의사결정 로직·reconciliation 제외
|
||||
- 기준: 운영자가 read 슬라이스 경계를 확인했다.
|
||||
- [ ] 성공 지표의 측정 방식/데이터 출처 확정
|
||||
- [x] 성공 지표의 측정 방식/데이터 출처 확정
|
||||
- 기준: S-1~S-12 측정 방식·출처 명시(본 문서 # 7).
|
||||
- [ ] High 영향 리스크 우선순위 및 해소 책임자 지정
|
||||
- [x] High 영향 리스크 우선순위 및 해소 책임자 지정
|
||||
- 기준: 본 Discovery 의 리스크는 현재 전부 Medium/Low. 신선도(R-1)·race(R-2)·가용성(R-3) 처리 방침을 운영자가 확인.
|
||||
- [ ] 모든 오픈 질문(OQ) `Open` 상태 없음 확인
|
||||
- [x] 모든 오픈 질문(OQ) `Open` 상태 없음 확인
|
||||
- 기준: OQ-1~OQ-12 이 전부 Answered/Deferred 처리(현재 OQ-1~OQ-12 전부 Answered).
|
||||
- [ ] Freeze 확정 담당자(CONFIRMED_BY) 지정
|
||||
- [x] Freeze 확정 담당자(CONFIRMED_BY) 지정
|
||||
- 기준: 운영자가 confirm-discovery 시점에 CONFIRMED_BY 를 지정한다.
|
||||
|
||||
# 9. 파일 처리 결과
|
||||
@@ -306,13 +306,13 @@ REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지
|
||||
- ~~pause/resume 메커니즘~~ → 결정됨: portfolio_id 단위, CLI + dcy-006 RPC 제어, Postgres 영속(refresh 무관), 전역, 즉시 복귀 (OQ-10, 2026-06-05)
|
||||
|
||||
## CONFIRM
|
||||
- {{CONFIRM_READ_SCOPE}} — read 슬라이스 범위 경계(전략 로직·reconciliation 제외) 확정
|
||||
- ~~read 슬라이스 범위 경계~~ → 확정됨(2026-06-06, Justin): In Scope(portfolio-hub read 포트/어댑터·스냅샷 read 계약·마스킹·view 모드·옵션 D·정합 검증·baseline) / Out of Scope(전략 의사결정 로직·reconciliation·safety floor) 확인
|
||||
- ~~core 경유 정책~~ → 결정됨: 모든 소비자 trex-core 경유, portfolio-hub 직접 호출 금지 (OQ-3, 2026-06-04)
|
||||
- ~~in-flight 합성/제외 규칙~~ → 결정됨: holding 포함, pending·warning·pause 마스킹, core 권위 우선 (OQ-4, 2026-06-05)
|
||||
- ~~가용성 degrade 정책~~ → 결정됨: 권위 cash/position 유지 불가 시 명시적 degraded 신호 + 신규 매매 보수적 중단, core 보호 매도 유지 (OQ-5, 2026-06-05). dcy-006 OQ-4 와 공통 보수적 안전.
|
||||
|
||||
## DATA
|
||||
- {{DATA_PORTFOLIO_HUB_READ_CONTRACT}} — portfolio-hub read API 계약(`managed_by_daemon_id` 로 daemon universe 조회) 및 응답 필드(cash_balance/asset_quantity/strategy_params JSONB) 확인
|
||||
- ~~portfolio-hub read 계약 확인~~ → 검증됨(2026-06-06, confirm-discovery): portfolio-hub `app/api/v1_portfolios.py` `list_portfolios_v1`(`GET`)이 `managed_by_daemon_id=auth.daemon_id` 로 daemon universe 스코프 조회를 제공하고, `PortfolioItem` 에 `cash_balance`·`asset_quantity`·`managed_by_daemon_id` 포함. 전략파라미터는 `strategy_params` JSONB(A-5).
|
||||
- ~~portfolio-hub write 응답 계약 확장~~ → 확정됨(2026-06-05, portfolio-hub#8): `POST /v1/portfolios/{portfolio_id}/ledger/trades` 응답 root 에 flat 필드 `cash_balance_after`, `asset_quantity_after` 추가 + ledger INSERT/잔고 UPDATE 단일 트랜잭션(회계 단일 권위). status 별 `*_after` 의미 정의(new=반영 후, duplicate=현재 권위, 409/422=미정). portfolio-hub 측은 dcy-006/REL-003 으로 배포 예정 — 배포 시점까지 trex-core 구현 대기. 추적: https://github.com/fourblocks2020/portfolio-hub/issues/8 (옵션 D 의존, A-7)
|
||||
|
||||
# 11. Discovery Freeze
|
||||
@@ -326,8 +326,8 @@ REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록
|
||||
- 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약)
|
||||
|
||||
## Freeze 플래그
|
||||
- Handoff Decision: 보류
|
||||
- Handoff Decision: 승인
|
||||
- Handoff Rationale: OQ-1(스냅샷 정의)·OQ-2(신선도, 옵션 D — portfolio-hub#8 write 응답 `*_after` 확정)·OQ-3(core 경유 정책)·OQ-4(in-flight 합성 — holding 포함, pending·warning·pause 마스킹)·OQ-5(가용성 degrade — 권위 cash/position 유지 불가 시 degraded 신호+보수적 중단)·OQ-6(빈 표현 — envelope + `assets: []`/meta)·OQ-7(daemon_id — 토큰 도출 단일 진실원)·OQ-8(정합 — 수량 정확 일치·symbol 집계·자동 해제·KIS 잔고조회)·OQ-9(전략 ID — 사람이 읽는 안정 slug·단일 active 일치)·OQ-10(pause — portfolio_id·CLI+MQ·Postgres 영속·전역·즉시 복귀)·OQ-11(capacity 0 응답 — view 모드 파라미터)·OQ-12(view 파라미터 — `all`/`buyable`/`held` + envelope) **전부 Answered**. 남은 인계 전 항목은 범위 경계 확인(운영자)과 CONFIRMED_BY 지정이며, confirm-discovery 에서 확정 후 REQ Drafting 으로 인계한다.
|
||||
- Ready for REQ Drafting: false
|
||||
- Confirmed By: TBD
|
||||
- Confirmed At (KST): TBD
|
||||
- Ready for REQ Drafting: true
|
||||
- Confirmed By: Justin
|
||||
- Confirmed At (KST): 2026-06-06 00:08
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
| dcy-002_20260603_slot-core-daemon-http-api | 20260603 | trex-core 슬롯 코어 데몬화 + HTTP intent API | [Discovery](./dcy-002_20260603_slot-core-daemon-http-api.md) | confirmed |
|
||||
| dcy-003_20260604_broker-execution-and-outbox | 20260604 | 브로커 단일 세션 + 주문 집행 + durable outbox (불변식 B) | [Discovery](./dcy-003_20260604_broker-execution-and-outbox.md) | confirmed |
|
||||
| dcy-004_20260604_portfolio-hub-ledger-integration | 20260604 | portfolio-hub ledger 연동 — 체결을 외부 원장에 기록 | [Discovery](./dcy-004_20260604_portfolio-hub-ledger-integration.md) | confirmed |
|
||||
| dcy-005_20260604_portfolio-hub-asset-snapshot-api | 20260604 | portfolio-hub 종목 스냅샷 read API — 매수 전략 모듈에 슬롯-제외 후보 제공 | [Discovery](./dcy-005_20260604_portfolio-hub-asset-snapshot-api.md) | draft |
|
||||
| dcy-005_20260604_portfolio-hub-asset-snapshot-api | 20260604 | portfolio-hub 종목 스냅샷 read API — 전략 모듈에 전략 실행 대상 자산 리스트 제공 | [Discovery](./dcy-005_20260604_portfolio-hub-asset-snapshot-api.md) | confirmed |
|
||||
| dcy-006_20260605_strategy-module-rabbitmq-transport | 20260605 | trex-core ↔ 전략 모듈 통신 transport — RabbitMQ 도입 (스냅샷 read + intent 제출 + 이벤트) | [Discovery](./dcy-006_20260605_strategy-module-rabbitmq-transport.md) | confirmed |
|
||||
+121
-3
@@ -4,7 +4,7 @@
|
||||
- Baseline Seed: .stage-pilot/bootstrap/baseline.yaml
|
||||
- Status: draft
|
||||
- Owner: project maintainers
|
||||
- Last Updated (KST): 2026-06-05 (BAT-007)
|
||||
- Last Updated (KST): 2026-06-06 (BAT-008)
|
||||
- Source Discovery / Batch: bootstrap-baseline (pre-Discovery); HTTP API = dcy-002 / BAT-002
|
||||
- Primary Runtime: daemon (HTTP API) + library (slot 도메인)
|
||||
|
||||
@@ -25,15 +25,19 @@
|
||||
|
||||
## Interface Summary
|
||||
|
||||
- RabbitMQ `trex.snapshot.req` :: 전략 모듈의 스냅샷 RPC (request-reply, BAT-007)
|
||||
- RabbitMQ `trex.snapshot.req` :: 전략 모듈의 스냅샷 RPC (request-reply, BAT-007/BAT-008 envelope)
|
||||
- RabbitMQ `trex.intent.req` :: 전략 모듈의 매수/매도 admission RPC (request-reply, BAT-007)
|
||||
- RabbitMQ `trex.events` :: 체결/슬롯 상태 이벤트 topic exchange (pub/sub, BAT-007)
|
||||
- RabbitMQ `trex.pause.req` :: pause/resume 제어 RPC (request-reply, BAT-008)
|
||||
- `trex-core` CLI :: pause/resume/paused 운영 명령 (BAT-008)
|
||||
- SlotService :: 슬롯 생명주기 도메인 서비스(전이/사전할당/가용성/재진입 카운트)
|
||||
- SlotRepository (Protocol) :: 도메인 ↔ 저장소 경계 계약
|
||||
- BrokerPort (Protocol) :: 단일 브로커 세션 경계(submit/poll/cancel) + `OrderRequest`/`OrderAck`/`FillStatus`
|
||||
- LedgerPort (Protocol) :: 외부 원장(portfolio-hub) 기록 경계 + `LedgerTrade`/`LedgerWriteResult`/예외 (BAT-006)
|
||||
- LedgerOutbox (Protocol) + LedgerWriter :: 체결 → 원장 기록의 outbox/재시도/멱등 (BAT-006)
|
||||
- MessagingTransport (Protocol) :: RabbitMQ / InMemory stub transport 경계 + `TransportHealth` enum (BAT-007)
|
||||
- PortfolioHubReadPort (Protocol) :: portfolio-hub universe read 경계 + `PortfolioItem`/`PortfolioHubUnavailableError` (BAT-008)
|
||||
- SnapshotStore + PauseStore + SnapshotScheduler :: in-memory snapshot + durable pause overlay + 일일 refresh (BAT-008)
|
||||
|
||||
> BAT-007 에서 HTTP `/v1` API 표면이 0 으로 제거됨(REQ-025). 이전 baseline 의 `HTTP /v1` 인터페이스 섹션은 더 이상 유효하지 않으며 본 인터페이스 인덱스에서 제거되었다. 전략-facing 통신은 위의 3 RabbitMQ 표면이 전부다.
|
||||
|
||||
@@ -106,7 +110,120 @@ sell payload 는 `{"intent_type":"sell", "intent_id":..., "slot_id":..., "reason
|
||||
- 재연결은 백오프 1s→2s→4s→8s→16s→30s cap, 어댑터가 자체 구현.
|
||||
- core 자율 안전 매도는 transport 와 무관하게 동작해야 한다(architecture contract; 자동 트리거 구현은 별도 Discovery).
|
||||
|
||||
## Interface: `SlotService`
|
||||
### `trex.snapshot.req` envelope (BAT-008 / REQ-028)
|
||||
|
||||
전략 모듈이 보내는 요청:
|
||||
```
|
||||
{ "view": "all" | "buyable" | "held" # default "all"
|
||||
"strategy_key": "<slug>" # optional, == filter on active_strategy_id
|
||||
"trading_date": "YYYY-MM-DD" # optional, default UTC today
|
||||
}
|
||||
```
|
||||
|
||||
코어가 reply-to 큐로 보내는 응답 envelope:
|
||||
```
|
||||
{ "assets": [ # always a list (REQ-028 AC-1, never null)
|
||||
{ "symbol": str,
|
||||
"asset_id": str, # == portfolio_id (dcy-004 OQ-1)
|
||||
"cash_balance": number,
|
||||
"asset_quantity": number,
|
||||
"active_strategy_id": str | null,
|
||||
"strategy_params": object # opaque, pass-through
|
||||
}, ...
|
||||
],
|
||||
"view": "all" | "buyable" | "held", # echo
|
||||
"available_slots": int, # idle_count snapshot
|
||||
"degraded": bool, # REQ-028 AC-2
|
||||
"reason": "portfolio_hub_unavailable" | "snapshot_fetch_failed"
|
||||
| "cash_position_stale" | null,
|
||||
"message": str | null # sanitized — no credentials/raw exceptions
|
||||
}
|
||||
```
|
||||
**No `price` field on items** (REQ-028 AC-3 / REQ-027 AC-1).
|
||||
|
||||
### `trex.pause.req` control RPC (BAT-008 / REQ-032)
|
||||
|
||||
요청:
|
||||
```
|
||||
{ "action": "pause" | "resume" | "list",
|
||||
"portfolio_id": str, # required for pause/resume
|
||||
"actor": str # optional, default "operator"
|
||||
}
|
||||
```
|
||||
|
||||
응답:
|
||||
```
|
||||
{ "status": "ok" | "error",
|
||||
"paused": [str, ...], # current paused portfolio_ids (sorted)
|
||||
"action": echo,
|
||||
"reason": str # only when status="error"
|
||||
}
|
||||
```
|
||||
- pause 는 `snapshot_pause` Postgres 테이블에 upsert(actor 갱신)되어 daemon 재시작·일일 refresh 후에도 유지된다(REQ-032 AC-2).
|
||||
- CLI `trex-core pause/resume/paused` 가 동일한 store 를 가리키므로 CLI ↔ RPC 가 같은 상태를 본다(REQ-032 AC-4).
|
||||
|
||||
## Interface: `PortfolioHubReadPort` (Protocol, BAT-008)
|
||||
|
||||
- Type: external-service (HTTP, portfolio-hub)
|
||||
- Consumers / Producers: `SnapshotScheduler`(소비) ↔ `PortfolioHubReadAdapter` 또는 `StubPortfolioRead`
|
||||
- Purpose: portfolio-hub universe(이 데몬이 관리하는 portfolio 집합) read 경계 — write 는 BAT-006 `LedgerPort` 와 분리.
|
||||
- Stability: experimental (BAT-008)
|
||||
|
||||
### Inputs
|
||||
|
||||
- `whoami() -> str` :: 자격증명/토큰에서 `daemon_id` 도출(1회). 별도 env 1차 출처 두지 않음.
|
||||
- `get_portfolios(daemon_id) -> list[PortfolioItem]` :: `managed_by_daemon_id == daemon_id` scope 조회.
|
||||
|
||||
### `PortfolioItem` Fields
|
||||
|
||||
- `portfolio_id :: str` :: == asset_id (dcy-004 OQ-1)
|
||||
- `symbol :: str`
|
||||
- `cash_balance :: float`
|
||||
- `asset_quantity :: float` :: integer shares semantically
|
||||
- `active_strategy_id :: str | None`
|
||||
- `strategy_params :: dict` :: opaque pass-through (no core parsing)
|
||||
|
||||
### Outputs / Outcomes
|
||||
|
||||
- 정상: `list[PortfolioItem]` (배열, 비면 `[]`).
|
||||
- 어댑터 어떤 실패든 `PortfolioHubUnavailableError` 로 통일 (호출자는 `SnapshotStore.set_degraded` 로 전환).
|
||||
|
||||
### Error Contract
|
||||
|
||||
- `PortfolioHubUnavailableError` :: 네트워크/5xx/4xx/JSON 파싱 실패 등 fetch 불가. 자격증명/예외 본문은 호출 측에서 sanitize 후 노출(REQ-028 AC-2).
|
||||
|
||||
### portfolio-hub Endpoint (어댑터 구현)
|
||||
|
||||
| HTTP | URL | 응답 |
|
||||
|---|---|---|
|
||||
| GET | `/v1/auth/whoami` | `{daemon_id: str, ...}` |
|
||||
| GET | `/v1/portfolios?managed_by_daemon_id=<id>` | `{items: [PortfolioItem, ...]}` 또는 list root |
|
||||
|
||||
## Interface: `SnapshotStore` + `PauseStore` + `SnapshotScheduler` (Protocol, BAT-008)
|
||||
|
||||
- Type: internal-service
|
||||
- Consumers / Producers: `SnapshotScheduler`(생산) → `SnapshotStore`(read 채널) ← `make_snapshot_rpc_handler`(소비). `PauseStore`(`PostgreSQLPauseStore` 또는 `InMemoryPauseStore`)는 CLI/RPC 양쪽이 쓰고 handler 가 읽는다.
|
||||
|
||||
### Inputs
|
||||
|
||||
- `SnapshotStore.swap(items)` :: atomic immutable swap. 직전 `warning` flag 는 carry-over(다음 reconcile 에서 자동 해제 판단).
|
||||
- `SnapshotStore.set_warning(pid, on)` :: 정합 결과 overlay(in-memory only).
|
||||
- `SnapshotStore.update_cash_position(pid, cash, qty)` :: 옵션 D wiring point(REQ-030 AC-2/AC-3 — portfolio-hub#8 배포 후에만 ledger writer 가 호출).
|
||||
- `SnapshotStore.set_degraded(reason, message)` / `clear_degraded()` :: degraded signal.
|
||||
- `PauseStore.pause(pid, actor)` / `resume(pid)` / `list_paused()` :: durable manual overlay.
|
||||
- `SnapshotScheduler.run_once()` :: fetch + swap + reconcile 1 회.
|
||||
- `SnapshotScheduler.run_forever(stop, tick_sec)` :: boot 즉시 1 회 + 매일 `TREX_SNAPSHOT_SCHEDULE_KST` 시각에 1 회.
|
||||
|
||||
### Outputs / Outcomes
|
||||
|
||||
- `run_once()` returns `True`(성공) / `False`(degraded). `True` 시 reconcile 한 패스가 함께 돈다.
|
||||
- `list_assets()` + `degraded_state()` 를 envelope builder 가 매 RPC 요청마다 읽음.
|
||||
|
||||
### Compatibility Rules
|
||||
|
||||
- pause 의 영속성 단위는 `portfolio_id`(= asset_id). 동일 portfolio_id 재 pause 는 upsert(actor만 갱신).
|
||||
- warning 은 in-memory only — 재시작 시 초기화되며 다음 정합 패스가 다시 판정한다.
|
||||
- universe swap 은 pause/warning 의 결정을 invalidate 하지 않는다(warning 은 carry-over, pause 는 store 가 별도 영속).
|
||||
|
||||
- Type: internal-service
|
||||
- Consumers / Producers: 상위 애플리케이션(예: trex-orbit 류 매매 데몬)의 매수/매도/주문 결정 경로 및 운영자 도구
|
||||
@@ -300,3 +417,4 @@ sell payload 는 `{"intent_type":"sell", "intent_id":..., "slot_id":..., "reason
|
||||
- 2026-06-04 :: BAT-004 — 브로커 집행 레이어 반영(BrokerPort/paper·KIS 어댑터, execution 루프, broker_order_id 실행큐·멱등, reconciliation) (REQ-011~015).
|
||||
- 2026-06-04 :: BAT-006 — LedgerPort/LedgerTrade/LedgerWriteResult 계약, LedgerOutbox/LedgerWriter, portfolio-hub `/v1/assets/{asset_id}/ledger/trades` 엔드포인트 + 409→`LedgerConflictError`, FillStatus.execution_id/fee/tax 확장 (REQ-017~020).
|
||||
- 2026-06-05 :: BAT-007 — HTTP `/v1` API 인터페이스 제거(adapters/api + fastapi/uvicorn 의존 정리), RabbitMQ messaging 계약 추가(스냅샷 RPC `trex.snapshot.req`, intent RPC `trex.intent.req`, 이벤트 topic `trex.events`, 전략별 durable queue + TTL/max-length, DLQ, publisher confirms, ack-after-commit), `MessagingTransport` Protocol + `TransportHealth` 노출 (REQ-021~026).
|
||||
- 2026-06-06 :: BAT-008 — `trex.snapshot.req` envelope 계약 정의(`assets[]/view/available_slots/degraded/reason/message`, no price field), `trex.pause.req` 제어 RPC 추가, `PortfolioHubReadPort`/`SnapshotStore`/`PauseStore`/`SnapshotScheduler` 인터페이스, `BrokerPort.get_balance()` 확장, `trex-core` CLI 추가 (REQ-027~033; REQ-030 옵션 D 는 portfolio-hub#8 배포 후).
|
||||
|
||||
+20
-12
@@ -4,7 +4,7 @@
|
||||
- Baseline Seed: .stage-pilot/bootstrap/baseline.yaml
|
||||
- Status: draft
|
||||
- Owner: project maintainers
|
||||
- Last Updated (KST): 2026-06-05 (BAT-007)
|
||||
- Last Updated (KST): 2026-06-06 (BAT-008)
|
||||
- Source Discovery / Batch: bootstrap-baseline (pre-Discovery, 3-phase lifecycle 밖의 bootstrap 산출물)
|
||||
|
||||
## Project Summary
|
||||
@@ -23,10 +23,12 @@
|
||||
## Primary Runtime
|
||||
- Type: daemon (sync + thread, no HTTP) + library (slot 도메인)
|
||||
- Entry Points:
|
||||
- `trex-core-daemon` (console_script → `trex_core.runtime.daemon:main`) :: 슬롯 코어 데몬 — migrate+preallocate+reconcile 후 4 백그라운드 스레드(intent RPC consumer / snapshot RPC consumer / execution / ledger) 기동, RabbitMQ messaging 으로 전략 모듈과 통신 (BAT-002 + BAT-007)
|
||||
- RabbitMQ `trex.snapshot.req` / `trex.intent.req` / `trex.events` :: 매수·매도 전략 데몬과의 transport (docs/interface-contract.md)
|
||||
- `trex-core-daemon` (console_script → `trex_core.runtime.daemon:main`) :: 슬롯 코어 데몬 — migrate+preallocate+reconcile 후 6 백그라운드 스레드(intent RPC consumer / snapshot RPC consumer / pause RPC consumer / snapshot scheduler / execution / ledger) 기동, RabbitMQ messaging 으로 전략 모듈과 통신 (BAT-002 + BAT-007 + BAT-008)
|
||||
- `trex-core` (console_script → `trex_core.runtime.cli:main`) :: 운영 CLI (`pause` / `resume` / `paused`) (BAT-008)
|
||||
- RabbitMQ `trex.snapshot.req` / `trex.intent.req` / `trex.pause.req` / `trex.events` :: 매수·매도 전략 데몬과의 transport (docs/interface-contract.md)
|
||||
- SlotService / SlotRepository (Protocol) :: in-process 도메인 서비스 + 저장소 경계(라이브러리 사용)
|
||||
- MessagingTransport (Protocol) :: transport 추상화 (RabbitMQ / InMemory stub)
|
||||
- PortfolioHubReadPort (Protocol) :: portfolio-hub universe read 경계 (BAT-008)
|
||||
|
||||
## Purpose
|
||||
- This document is the current approved repository and package structure baseline.
|
||||
@@ -63,23 +65,28 @@
|
||||
│ ├── domain/slot/ # slot 순수 도메인 (BAT-001, 무의존)
|
||||
│ │ ├── __init__.py · state.py · models.py(+EXPECTED_SLOT_FIELDS) · errors.py
|
||||
│ │ ├── repository.py(Protocol) · service.py · in_memory_repository.py
|
||||
│ ├── application/ # 유스케이스 (BAT-002, BAT-004, BAT-006, BAT-007)
|
||||
│ ├── application/ # 유스케이스 (BAT-002, BAT-004, BAT-006, BAT-007, BAT-008)
|
||||
│ │ ├── ports.py # IntentStore Protocol
|
||||
│ │ ├── intents.py # IntentService / BuyIntent / SellIntent / IntentDecision
|
||||
│ │ ├── broker_port.py # BrokerPort + OrderRequest/OrderAck/FillStatus + calculate_fee (BAT-004/BAT-006)
|
||||
│ │ ├── broker_port.py # BrokerPort + OrderRequest/OrderAck/FillStatus + BalanceItem + calculate_fee (BAT-004/BAT-006/BAT-008)
|
||||
│ │ ├── execution.py # ExecutionService (dispatch·poll·transition·reconcile + ledger enqueue + event emit hook)
|
||||
│ │ ├── ledger_port.py # LedgerPort + LedgerTrade/LedgerWriteResult/예외 (BAT-006)
|
||||
│ │ ├── ledger_outbox.py # LedgerOutbox Protocol + LedgerWriter + InMemoryLedgerOutbox (BAT-006)
|
||||
│ │ ├── messaging.py # MessagingTransport Protocol + DTO + TransportHealth (BAT-007)
|
||||
│ │ └── messaging_handlers.py # intent/snapshot RPC handlers + slot event payload builder (BAT-007)
|
||||
│ ├── adapters/ # 인프라 어댑터 (BAT-002, BAT-004, BAT-006, BAT-007)
|
||||
│ │ ├── broker/ # paper.py(결정적 async 더블) · kis.py(KIS Open API) (BAT-004)
|
||||
│ │ ├── messaging_handlers.py # intent/snapshot/pause RPC handlers + slot event payload builder (BAT-007/BAT-008)
|
||||
│ │ ├── portfolio.py # PortfolioHubReadPort + SnapshotStore + PauseStore + envelope builder (BAT-008)
|
||||
│ │ ├── reconciliation.py # reconcile_positions (hub ↔ broker symbol-aggregate) (BAT-008)
|
||||
│ │ └── snapshot_scheduler.py # SnapshotScheduler — daily fetch + swap + reconcile (BAT-008)
|
||||
│ ├── adapters/ # 인프라 어댑터 (BAT-002, BAT-004, BAT-006, BAT-007, BAT-008)
|
||||
│ │ ├── broker/ # paper.py(결정적 async 더블) · kis.py(KIS Open API + 잔고조회) (BAT-004/BAT-008)
|
||||
│ │ ├── ledger/ # in_memory.py(stub) · portfolio_hub.py(HTTP 어댑터) (BAT-006)
|
||||
│ │ ├── messaging/ # topology.py · in_memory.py(stub) · rabbitmq.py(pika 동기) (BAT-007)
|
||||
│ │ └── persistence/ # postgresql.py(+PostgreSQLLedgerOutbox) · in_memory_intent_store.py · migrate.py · sql/(001_…, 002_create_ledger_outbox.sql)
|
||||
│ └── runtime/ # 데몬 (BAT-002, BAT-004, BAT-006, BAT-007)
|
||||
│ ├── config.py # DaemonConfig + KISConfig + PortfolioHubConfig + RabbitMQConfig (env)
|
||||
│ └── daemon.py # Daemon class: setup(migrate/preallocate/reconcile/declare-topology) + 4 worker threads (execution·ledger·intent-rpc·snapshot-rpc) + graceful shutdown
|
||||
│ │ ├── portfolio/ # hub_read.py(HTTP) · stub_read.py(stub) · pause_store.py(Postgres) (BAT-008)
|
||||
│ │ └── persistence/ # postgresql.py(+PostgreSQLLedgerOutbox) · in_memory_intent_store.py · migrate.py · sql/(001_…, 002_create_ledger_outbox.sql, 003_create_snapshot_pause.sql)
|
||||
│ └── runtime/ # 데몬 (BAT-002, BAT-004, BAT-006, BAT-007, BAT-008)
|
||||
│ ├── config.py # DaemonConfig + KISConfig + PortfolioHubConfig + RabbitMQConfig + SnapshotScheduleConfig (env)
|
||||
│ ├── daemon.py # Daemon class: setup(migrate/preallocate/reconcile/declare-topology) + 6 worker threads (execution·ledger·intent-rpc·snapshot-rpc·pause-rpc·snapshot-scheduler) + graceful shutdown
|
||||
│ └── cli.py # trex-core CLI: pause/resume/paused subcommands (BAT-008 / REQ-032)
|
||||
└── tests/
|
||||
├── domain/slot/ # test_state / test_service / test_contract
|
||||
├── domain/ # test_domain_import_sweep (NFR-1 가드, BAT-006/BAT-007)
|
||||
@@ -135,3 +142,4 @@
|
||||
- 2026-06-04 :: BAT-004 — 브로커 집행 레이어 반영(BrokerPort/paper·KIS 어댑터, execution 루프, broker_order_id 실행큐·멱등, reconciliation) (REQ-011~015).
|
||||
- 2026-06-04 :: BAT-006 — ledger 레이어 추가(application LedgerPort/LedgerOutbox, adapters/ledger in_memory·portfolio_hub, persistence PostgreSQLLedgerOutbox + 002 마이그레이션, runtime ledger writer 루프, FillStatus 확장, NFR-1 import 스윕) (REQ-017~020).
|
||||
- 2026-06-05 :: BAT-007 — transport 전환(`adapters/api/` 제거, `application/messaging.py` + `application/messaging_handlers.py` 신설, `adapters/messaging/` 신설(topology/in_memory/rabbitmq), runtime/daemon 을 sync+thread 4 스레드 구조로 재구성, `RabbitMQConfig` + `TREX_RABBITMQ_URL` env, `TREX_API_HOST`/`TREX_API_PORT` 폐기, `fastapi`/`uvicorn` 의존 제거 + `pika` 도입, NFR-1 import 스윕에 pika/messaging 추가, HTTP 표면 0 회귀 가드) (REQ-021~026).
|
||||
- 2026-06-06 :: BAT-008 — portfolio-hub 스냅샷 read 레이어 추가(`application/portfolio.py` + `application/reconciliation.py` + `application/snapshot_scheduler.py` 신설, `adapters/portfolio/` 신설(hub_read/stub_read/pause_store), `BrokerPort.get_balance()` 확장 + paper/KIS 구현, `messaging_handlers` 에 snapshot envelope + pause RPC 추가, runtime/daemon 을 6 스레드로 확장(pause-rpc + snapshot-scheduler), `SnapshotScheduleConfig` + `TREX_SNAPSHOT_*` env, `runtime/cli.py` + `trex-core` 콘솔 스크립트, `003_create_snapshot_pause.sql` 마이그레이션, NFR-1 import 스윕 유지) (REQ-027~033; REQ-030 옵션 D 는 portfolio-hub#8 배포 후 별도 구현).
|
||||
|
||||
+42
-1
@@ -4,7 +4,7 @@
|
||||
- Baseline Seed: .stage-pilot/bootstrap/baseline.yaml
|
||||
- Status: draft
|
||||
- Owner: project maintainers
|
||||
- Last Updated (KST): 2026-06-05 (BAT-007)
|
||||
- Last Updated (KST): 2026-06-06 (BAT-008)
|
||||
- Source Discovery / Batch: bootstrap-baseline (pre-Discovery); 데몬/HTTP 흐름 = dcy-002 / BAT-002
|
||||
- Primary Runtime: daemon (HTTP API) + library (slot 도메인)
|
||||
|
||||
@@ -67,6 +67,46 @@
|
||||
3. 전략별 durable queue(`trex.events.strategy.{strategy_id}`)는 `*.{strategy_id}.#` 패턴으로 바인딩 → broker 단 필터로 자기 자산 이벤트만 수신.
|
||||
4. 전략 down 중 적체된 메시지는 catch-up 으로 복구; TTL(1h) / max-length(10k) 초과는 `drop-head` + 후속 스냅샷 RPC reconcile.
|
||||
|
||||
## Flow: `일일 스냅샷 refresh` (BAT-008 / REQ-030)
|
||||
|
||||
데몬 lifespan 의 `trex-snapshot-scheduler` 스레드가 portfolio-hub universe 를 fetch 해 in-memory 스냅샷을 atomic-swap 으로 교체하고, 같은 패스에서 정합 검증을 수행한다.
|
||||
|
||||
1. boot: `SnapshotScheduler.run_once()` 한 번 호출 → 첫 universe 로딩(또는 degraded 마킹).
|
||||
2. tick(`TREX_SNAPSHOT_TICK_SEC`, 기본 60s): 현재 KST 시각이 `TREX_SNAPSHOT_SCHEDULE_KST`(기본 07:30) 이상이고 오늘 아직 안 돌았으면 fire.
|
||||
3. fire 단계: `PortfolioHubReadPort.whoami()` 로 daemon_id 도출(1회 캐시) → `get_portfolios(daemon_id)` 로 universe 페치 → `SnapshotStore.swap(items)` atomic 교체 → `reconcile_positions(store, broker)` 정합 검증.
|
||||
4. 실패 분기: `PortfolioHubUnavailableError` → `degraded = portfolio_hub_unavailable`; 응답 파싱 실패 → `snapshot_fetch_failed`. 둘 다 다음 RPC 응답 envelope 에 즉시 노출(REQ-028 AC-2).
|
||||
|
||||
## Flow: `포지션 정합 검증` (BAT-008 / REQ-031)
|
||||
|
||||
`reconcile_positions` 는 portfolio-hub 보유 수량을 symbol 별로 합산해 broker `get_balance()` 결과와 비교한다.
|
||||
|
||||
1. `BrokerPort.get_balance() → list[BalanceItem(symbol, hldg_qty)]` 조회. KIS 어댑터는 `TTTC8434R`/`VTTC8434R` `inquire-balance`, paper 는 결정론 fill aggregate. **0수량 row 는 양쪽 모두 drop**(D-2 leftover 처리, Decision 7).
|
||||
2. 자산을 `symbol` 로 그룹화해 `hub_total = sum(asset_quantity)` 계산 → broker 의 같은 symbol `hldg_qty` 와 비교.
|
||||
3. 불일치: 해당 symbol 의 모든 portfolio_id 에 `SnapshotStore.set_warning(pid, True)` → 다음 envelope 부터 응답에서 마스킹. 첫 raise 시 한 번 로그.
|
||||
4. 일치: 이전에 `warning` 이었던 자산은 자동 해제 → 다음 envelope 부터 다시 포함. resume 과 달리 자동·임시 overlay(영속 X).
|
||||
|
||||
## Flow: `pause/resume 제어` (BAT-008 / REQ-032)
|
||||
|
||||
운영자가 자산을 매매에서 제외/복귀시키는 두 경로(CLI + RPC)는 동일한 `snapshot_pause` Postgres 테이블을 가리킨다.
|
||||
|
||||
1. CLI: `trex-core pause <portfolio_id>` / `trex-core resume <portfolio_id>` → `PostgreSQLPauseStore.pause/resume` 호출(`portfolio_id` PK upsert/delete).
|
||||
2. RPC: 전략 모듈/운영자가 `trex.pause.req` 큐에 `{action: pause|resume|list, portfolio_id, actor}` 발행 → `make_pause_rpc_handler` 가 같은 store 호출 → `{status, paused[], action}` 응답.
|
||||
3. 응답 산출: `build_snapshot_envelope` 가 `pause_store.list_paused()` 를 매 요청마다 읽음 → `mask(pending | warning | pause)` 합성. resume 후 **다음 요청부터 즉시 복귀**(별도 reload 불필요).
|
||||
4. 영속: daemon 재시작 + 일일 refresh 후에도 `snapshot_pause` row 유지(universe swap 은 pause 를 만지지 않음).
|
||||
|
||||
## Flow: `스냅샷 RPC 응답 산출` (BAT-008 / REQ-028, REQ-029)
|
||||
|
||||
`trex.snapshot.req` 메시지 처리.
|
||||
|
||||
1. 요청 payload 디코드: `{view ∈ {all, buyable, held}, strategy_key?, trading_date?}`.
|
||||
2. `slot_service.compute_slot_capacity(today, total_slots)` → `available_slots = idle_count`.
|
||||
3. `build_snapshot_envelope(store, pause_store, slot_repo, view, strategy_key, available_slots, trading_date)`:
|
||||
- base 집합: ALL = `universe ∪ holding`, BUYABLE = `universe − (pending ∪ holding)`(`available_slots=0` 이면 `[]`), HELD = `holding 슬롯만`.
|
||||
- 마스킹: pending(slot) OR warning(REQ-031) OR pause(REQ-032) — 어느 하나라도면 제외. slot overlay > portfolio-hub 보유 여부(불변식 A).
|
||||
- `strategy_key` 일치(`==`) 직교 필터.
|
||||
- degraded 상태가 있으면 `degraded=true + reason + sanitized message` 동봉.
|
||||
4. envelope: `{assets[], view, available_slots, degraded, reason, message}` — `assets` 는 항상 배열, null 금지. 항목 필드는 `symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params`, **price 필드는 없음**.
|
||||
|
||||
## Flow: `broker degrade 분기` (BAT-007 / REQ-024)
|
||||
|
||||
1. transport connection drop → 어댑터가 `_mark_disconnected()` + 백오프(1s→2s→4s→8s→16s→30s cap) 재연결.
|
||||
@@ -157,3 +197,4 @@
|
||||
- 2026-06-04 :: BAT-004 — 브로커 집행 레이어 반영(BrokerPort/paper·KIS 어댑터, execution 루프, broker_order_id 실행큐·멱등, reconciliation) (REQ-011~015).
|
||||
- 2026-06-04 :: BAT-006 — ledger 통합 반영(체결→ledger outbox enqueue, LedgerWriter retry/dedup/409 흐름, FillStatus.execution_id/fee 운반, slot 전이와 ledger write 분리) (REQ-017~020).
|
||||
- 2026-06-05 :: BAT-007 — transport 전환(HTTP `/v1` API 제거, RabbitMQ 메시징 도입: 스냅샷/intent RPC + 이벤트 topic, sync+thread daemon, intent_log 멱등 ack-after-commit, publisher confirms + DLQ, per-strategy durable queue + TTL/max-length, broker degrade 분기) (REQ-021~026).
|
||||
- 2026-06-06 :: BAT-008 — portfolio-hub 스냅샷 read 레이어 추가(`PortfolioHubReadPort` + hub_read/stub_read 어댑터, `SnapshotStore` in-memory + `snapshot_pause` Postgres, `SnapshotScheduler` 일일 refresh, `reconcile_positions` 정합 검증 + `BrokerPort.get_balance()` 확장, `trex.snapshot.req` envelope 응답 + degraded 신호, `trex.pause.req` 제어 RPC, `trex-core` CLI) (REQ-027~033; 옵션 D AC-2/AC-3 은 portfolio-hub#8 배포 후 별도 구현).
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# req-033: 스냅샷 read 레이어 baseline 문서 정합
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Documentation
|
||||
- Priority: Medium
|
||||
- Owner: project maintainers
|
||||
|
||||
## Intent
|
||||
- portfolio-hub read 포트·스냅샷 read 메시지 계약·일일 스냅샷 스케줄러·정합 검증을 baseline 문서에 정합시켜 문서-코드 일치를 유지한다.
|
||||
|
||||
## Requirement
|
||||
- `docs/interface-contract.md` 를 read 포트(`PortfolioHubReadPort`)·스냅샷 read 메시지 계약(envelope·view·strategy_key·degraded)에 맞게 갱신한다.
|
||||
- `docs/runtime-flows.md` 를 일일 스냅샷 조회 흐름·옵션 D 현금/포지션 갱신·정합 검증 흐름에 맞게 갱신한다.
|
||||
- `docs/project-structure.md` 를 신규 `adapters/portfolio` read 어댑터·스냅샷 스케줄러 컴포넌트에 맞게 갱신한다.
|
||||
- dcy-006 의 transport baseline 갱신(REQ-026)과 정합을 유지한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given REQ-027~032 구현, When baseline 3개 문서를 검토, Then read 포트·스냅샷 메시지 계약·스케줄러·정합 검증이 실제 코드와 정합한다.
|
||||
2. Given 문서-코드 정합 점검, Then baseline 문서와 실제 포트/계약/흐름 사이 불일치가 0 이다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/interface-contract.md, docs/runtime-flows.md, docs/project-structure.md, docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md
|
||||
- Modules: none(문서)
|
||||
- Tests: 문서-코드 정합 리뷰
|
||||
|
||||
## Notes
|
||||
- dcy-005 FR-5 반영. dcy-006 transport baseline 과 정합.
|
||||
- 보통 REQ-027~032 구현 batch 의 검증 단계에서 함께 마감한다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260606-01
|
||||
- Date: 2026-06-06
|
||||
- Author: project maintainers
|
||||
|
||||
#### Change Summary
|
||||
- dcy-005 FR-5 분해로 최초 생성(Proposed).
|
||||
|
||||
#### Intent
|
||||
- read 레이어 baseline 문서 정합 작업 정의.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~2 신규
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- interface-contract, runtime-flows, project-structure, dcy-005
|
||||
- Modules:
|
||||
- none
|
||||
- Tests:
|
||||
- 문서-코드 정합 리뷰
|
||||
|
||||
#### 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
|
||||
- baseline 문서 vs 실제 포트/계약/흐름 정합 리뷰로 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
|
||||
- 승인 기록. REQ-027~032 구현 batch 검증 단계에서 함께 마감.
|
||||
|
||||
### CHG-20260606-03
|
||||
- Date: 2026-06-06
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- Status 변경: Approved → Implemented. BAT-008 release-candidate verification evidence 기반.
|
||||
|
||||
#### Intent
|
||||
- baseline 3 문서(runtime-flows / interface-contract / project-structure) 에 BAT-008 섹션 + Change Log 추가 완료 상태로 동기화.
|
||||
|
||||
#### 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: 3 baseline 문서 모두 BAT-008 섹션 + 2026-06-06 Change Log 항목 추가됨.
|
||||
- AC-2: BAT-008 verification.md Manual 섹션의 baseline ↔ 코드 정합 리뷰 (필드 시그니처/디렉토리 트리/Protocol 동작 일치 확인).
|
||||
@@ -0,0 +1,135 @@
|
||||
# req-031: 포지션 정합 검증 + warning 마스킹
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Exception
|
||||
- Priority: High
|
||||
- Owner: project maintainers
|
||||
|
||||
## Intent
|
||||
- portfolio-hub 포지션이 실제 브로커 계좌 포지션과 어긋난 자산을 매매에서 보수적으로 제외해, 틀린 baseline 위에서 매매하는 위험을 막는다.
|
||||
|
||||
## Requirement
|
||||
- 스냅샷 페치 시 각 자산에 대해 portfolio-hub 포지션과 실제 브로커 계좌 포지션을 **수량 정확 일치**(정수 shares, 허용 오차 없음)로 검증한다. 현금은 대상이 아니다(수량만).
|
||||
- 브로커 포지션은 KIS 주식잔고조회(실전 `TTTC8434R` / 모의 `VTTC8434R`, `GET /uapi/domestic-stock/v1/trading/inquire-balance`)를 BrokerPort 잔고조회로 조회한다(항목당 `pdno`+`hldg_qty`). paper broker 는 결정론 stub.
|
||||
- 브로커 잔고는 단일 계좌(불변식 B)라 symbol 단위 집계이므로, portfolio-hub per-portfolio 포지션을 symbol 로 합산해 broker per-symbol `hldg_qty` 와 대조한다.
|
||||
- 불일치 자산은 `warning` 상태로 표시·응답에서 마스킹하고, 다음 정합 성공 시 자동 해제한다. warning raise 는 매번 로깅한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given symbol 집계 수량 불일치, When 정합 검증, Then 해당 자산은 `warning` 으로 표시되고 응답에서 마스킹된다.
|
||||
2. Given 이전에 `warning` 인 자산이 다음 정합에서 수량 일치, When 재검증, Then `warning` 이 자동 해제되어 다시 응답에 포함된다.
|
||||
3. Given paper broker, When 정합 검증, Then 결정론 잔고 stub 로 검증이 수행된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md
|
||||
- Modules: BrokerPort 잔고조회(KIS 주식잔고조회) 확장, 정합 검증 + `warning` 상태 로직
|
||||
- Tests: 수량 불일치 주입, warning 자동 해제, symbol 집계 대조
|
||||
|
||||
## Notes
|
||||
- 정확 일치(tolerance 없음) — A-6(유일 매매 주체)상 정확 일치가 정상이며 tolerance 는 실제 이상을 가린다.
|
||||
- 영속 hold 는 pause(REQ-032)로 분리(자동 warning=일시 / 수동 pause=영속).
|
||||
- 당일 전량매도분이 `hldg_qty=0` 으로 D-2 까지 잔고에 남을 수 있음(KIS 015 문서) → 0 수량 잔고 처리 규칙은 설계 시 확정.
|
||||
- 참고: docs/broker/kis/rest/국내주식/주문/계좌/015_v1_국내주식-006_주식잔고조회.md. OQ-8 반영.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260606-01
|
||||
- Date: 2026-06-06
|
||||
- Author: project maintainers
|
||||
|
||||
#### Change Summary
|
||||
- dcy-005 FR-7 + OQ-8 분해로 최초 생성(Proposed).
|
||||
|
||||
#### Intent
|
||||
- 포지션 정합 검증 + warning 마스킹/자동 해제 정의.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~3 신규
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- dcy-005
|
||||
- Modules:
|
||||
- BrokerPort 잔고조회, 정합/warning 로직
|
||||
- Tests:
|
||||
- 불일치 주입, 자동 해제
|
||||
|
||||
#### 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
|
||||
- 불일치 주입 → warning 마스킹 → 일치 복귀 → 자동 해제 시퀀스 테스트로 AC 검증.
|
||||
|
||||
### CHG-20260606-02
|
||||
- Date: 2026-06-06
|
||||
- Author: project maintainers
|
||||
|
||||
#### Change Summary
|
||||
- 승인 게이트 통과 → Proposed → Approved. D-2 0수량 잔고 처리 규칙은 설계 단계 확정(비블로커).
|
||||
|
||||
#### 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
|
||||
- 정합 검증(`reconcile_positions`) + warning 자동 set/clear + `BrokerPort.get_balance()` 확장 구현 완료 상태로 동기화.
|
||||
|
||||
#### 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: 실 KIS 환경에서 D-2 0수량 잔고 케이스 관찰 후 운영 노트화 권장 (별도 작업).
|
||||
|
||||
#### Validation Plan
|
||||
- AC-1: tests/application/test_reconciliation.py::test_mismatch_raises_warning_and_masks_asset.
|
||||
- AC-2: ::test_subsequent_match_auto_clears_warning.
|
||||
- AC-3: ::test_paper_broker_returns_deterministic_balance.
|
||||
@@ -0,0 +1,135 @@
|
||||
# req-027: portfolio-hub read 포트 + 어댑터 + stub
|
||||
|
||||
- Status: Implemented
|
||||
- Type: Integration
|
||||
- Priority: High
|
||||
- Owner: project maintainers
|
||||
|
||||
## Intent
|
||||
- 전략 모듈에 제공할 종목 스냅샷의 원천인 portfolio-hub universe(자신이 관리하는 portfolio 집합)를 trex-core 가 read 할 경로를 만든다. dcy-004 write 어댑터/자격증명을 재사용하고 도메인 순수성을 유지한다.
|
||||
|
||||
## Requirement
|
||||
- `PortfolioHubReadPort.get_portfolios(daemon_id)` application 포트 + portfolio-hub read 어댑터(`managed_by_daemon_id` 스코프 조회, portfolio-hub `list_portfolios_v1`) + 결정론 stub 를 제공한다.
|
||||
- 어댑터는 dcy-004 의 portfolio-hub 자격증명(.env `TREX_PORTFOLIO_HUB_*`)을 재사용한다.
|
||||
- `daemon_id` 는 portfolio-hub 자격증명/인증 토큰에서 도출한다(단일 진실원). 별도 `TREX_DAEMON_ID` 설정값을 1차 출처로 두지 않으며, 필요 시 whoami 1회로 도출·캐시한다.
|
||||
- 각 universe 항목은 symbol, asset_id(=portfolio_id), cash_balance, asset_quantity, active_strategy_id, 전략파라미터(opaque JSON)를 담고 가격(price)은 제외한다. 전략파라미터는 trex-core 가 해석하지 않고 통과시킨다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given daemon 자격증명/토큰, When `get_portfolios` 를 호출, Then `managed_by_daemon_id == 토큰 daemon_id` 인 portfolio 집합을 항목당 symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params(opaque) 형태로 반환하고 가격 필드는 없다.
|
||||
2. Given 결정론 stub 어댑터, When 호출, Then 네트워크 없이 고정된 universe 를 반환한다.
|
||||
3. Given import 스윕, When `trex_core/domain` 을 검사, Then portfolio-hub/네트워크 의존이 0 이다(NFR-1).
|
||||
4. Given `TREX_DAEMON_ID` 미설정, When daemon 기동·universe 조회, Then 토큰에서 도출한 daemon_id 로 동작한다(OQ-7).
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md, docs/interface-contract.md
|
||||
- Modules: trex_core/application (read 포트), trex_core/adapters/portfolio (read 어댑터 + stub), trex_core/runtime/config (daemon_id 토큰 도출)
|
||||
- Tests: stub read 통합테스트, 도메인 import 스윕, daemon_id 토큰 도출
|
||||
|
||||
## Notes
|
||||
- 가정: portfolio-hub `list_portfolios_v1`(`GET`)이 `managed_by_daemon_id=auth.daemon_id` 로 스코프 조회를 제공하고 `PortfolioItem` 에 cash_balance/asset_quantity 포함(confirm-discovery 에서 검증). 전략파라미터는 portfolio-hub `strategy_params` JSONB(dcy-005 A-5).
|
||||
- NFR-1(도메인 순수성)을 본 REQ 의 AC-3 로 흡수한다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260606-01
|
||||
- Date: 2026-06-06
|
||||
- Author: project maintainers
|
||||
|
||||
#### Change Summary
|
||||
- dcy-005 FR-4 + OQ-7 분해로 최초 생성(Proposed). NFR-1 흡수.
|
||||
|
||||
#### Intent
|
||||
- portfolio-hub universe read 경로를 포트/어댑터/stub 로 정의.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~4 신규
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- dcy-005, interface-contract 참조
|
||||
- Modules:
|
||||
- application read 포트, adapters/portfolio
|
||||
- Tests:
|
||||
- stub read 통합테스트, import 스윕
|
||||
|
||||
#### 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
|
||||
- stub read 통합테스트 + 도메인 import 스윕으로 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
|
||||
- `PortfolioHubReadPort` + 어댑터(`PortfolioHubReadAdapter`, `StubPortfolioRead`) 구현과 검증 evidence 확보 후 구현 완료 상태로 동기화.
|
||||
|
||||
#### 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/adapters/portfolio/test_hub_read.py::test_get_portfolios_scoped_by_managed_by_daemon_id + test_stub_read.py.
|
||||
- AC-2: tests/adapters/portfolio/test_stub_read.py 전체.
|
||||
- AC-3: tests/domain/test_domain_import_sweep.py.
|
||||
- AC-4: tests/adapters/portfolio/test_hub_read.py::test_whoami_returns_token_daemon_id.
|
||||
@@ -0,0 +1,135 @@
|
||||
# req-030: 일일 스냅샷 스케줄러 + 옵션 D 현금/포지션 갱신
|
||||
|
||||
- Status: Approved
|
||||
- Type: Integration
|
||||
- Priority: High
|
||||
- Owner: project maintainers
|
||||
|
||||
## Intent
|
||||
- universe 멤버십·전략파라미터는 일일 스냅샷으로 고정하고, 현금/포지션은 portfolio-hub 가 ledger write 응답으로 돌려주는 권위 값으로 유지해 로컬 누적 보정 drift 를 제거한다(옵션 D).
|
||||
|
||||
## Requirement
|
||||
- 설정 가능한 시각(기본 07:30 KST, .env)에 스케줄러(신규 daemon 컴포넌트)가 `daemon_id` universe 를 페치해 스냅샷을 갱신한다. universe 멤버십·전략파라미터는 그 일일 스냅샷으로 고정한다.
|
||||
- 현금/포지션은 스냅샷 baseline 에 더해, 체결 시 portfolio-hub ledger write 응답의 `cash_balance_after` / `asset_quantity_after` 권위 값으로 해당 자산을 갱신한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 설정 시각 도래, When 스케줄러 tick, Then universe 를 페치해 스냅샷(멤버십·전략파라미터·baseline 현금/포지션)을 갱신한다.
|
||||
2. Given 체결 후 ledger write 응답이 `*_after` 를 반환, When 처리, Then 해당 자산의 현금/포지션을 그 권위 값으로 갱신한다.
|
||||
3. Given `duplicate` write 응답(idempotent), When 처리, Then 현재 권위 `*_after` 값으로 동일하게 갱신한다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md, docs/runtime-flows.md
|
||||
- Modules: 일일 스냅샷 스케줄러(런타임 신규), ledger write 응답 소비/스냅샷 갱신 로직, config(스냅샷 페치 시각)
|
||||
- Tests: 스케줄 tick 페치, `*_after` 갱신, duplicate idempotent 갱신
|
||||
|
||||
## Notes
|
||||
- **의존: portfolio-hub#8 — ledger write 응답에 `cash_balance_after`/`asset_quantity_after` 반환(회계 단일 트랜잭션). portfolio-hub 배포(REL-003 등) 전까지 본 REQ 의 옵션 D 갱신 구현은 대기(dcy-005 A-7).** 그 전까지는 baseline + 스케줄러 페치까지만 선구현 가능.
|
||||
- A-6(유일 매매 주체·장중 외부 변동 없음) 전제.
|
||||
- NFR-2(일관성)를 본 REQ 로 흡수한다.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260606-01
|
||||
- Date: 2026-06-06
|
||||
- Author: project maintainers
|
||||
|
||||
#### Change Summary
|
||||
- dcy-005 FR-6 + OQ-2 분해로 최초 생성(Proposed). NFR-2 흡수.
|
||||
|
||||
#### Intent
|
||||
- 일일 스냅샷 스케줄러 + 옵션 D 현금/포지션 갱신 정의.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~3 신규
|
||||
- Updated:
|
||||
- none
|
||||
- Removed:
|
||||
- none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- dcy-005, runtime-flows
|
||||
- Modules:
|
||||
- 스냅샷 스케줄러, write 응답 소비 로직, config
|
||||
- Tests:
|
||||
- 스케줄 tick, *_after 갱신
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- none
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: no
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current
|
||||
- Follow-up Action: portfolio-hub#8 배포 추적 후 옵션 D 구현 착수
|
||||
|
||||
#### Validation Plan
|
||||
- 스케줄 tick 페치 + `*_after` 갱신/idempotent 갱신 테스트로 AC 검증.
|
||||
|
||||
### CHG-20260606-02
|
||||
- Date: 2026-06-06
|
||||
- Author: project maintainers
|
||||
|
||||
#### Change Summary
|
||||
- 승인 게이트 통과 → Proposed → Approved. 옵션 D 구현은 portfolio-hub#8 배포 후 착수(Notes 의존 유지, 비블로커).
|
||||
|
||||
#### 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; 옵션 D 구현은 portfolio-hub#8 배포 트래킹 후
|
||||
|
||||
#### Validation Plan
|
||||
- 승인 기록. 스케줄러 baseline 구현 → portfolio-hub#8 배포 후 옵션 D 갱신 통합 검증.
|
||||
|
||||
### CHG-20260606-03
|
||||
- Date: 2026-06-06
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- Status 유지: Approved. BAT-008 에서 AC-1(일일 스냅샷 스케줄러 baseline)은 구현 완료 + evidence 확보, AC-2/AC-3(옵션 D `*_after` 갱신)은 외부 의존(portfolio-hub#8) 배포 대기로 **deferred**. 본 REQ 는 AC 일부 충족이므로 `Implemented` 전환을 보류한다(SRS `Status Transition Evidence` 의 "미충족 Acceptance Criteria 가 있으면 Implemented 로 전환하지 않는다" 규정 준수).
|
||||
|
||||
#### Intent
|
||||
- 스케줄러 baseline 부분 구현 완료를 추적 + 옵션 D 후속 작업의 wiring point 가 노출되어 있음을 기록.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added/Updated/Removed: 없음
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs/Modules/Tests: 없음 (AC-1 baseline 은 BAT-008 에서 구현 + 검증 완료, AC-2/AC-3 wiring point 노출만 추가)
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-008 (release-candidate; AC-1 evidence)
|
||||
- Releases:
|
||||
- none
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes (portfolio-hub#8 배포 후 AC-2/AC-3 통합 검증)
|
||||
- Existing Implementation Invalidated: no
|
||||
- Status Recommendation: keep-current (Approved 유지)
|
||||
- Follow-up Action: portfolio-hub#8 배포 완료 알림 수신 시 별도 minor-change batch 로 옵션 D 구현 (LedgerWriter 의 ledger write 응답 소비 경로에서 `cash_balance_after`/`asset_quantity_after` → `SnapshotStore.update_cash_position(...)` 호출 1줄 추가) + AC-2/AC-3 통합 evidence 확보 → REQ-030 Approved → Implemented 전환.
|
||||
|
||||
#### Validation Plan
|
||||
- AC-1 (현재 완료): tests/application/test_snapshot_scheduler.py::test_run_once_fetches_universe_and_swaps_store + ::test_swap_preserves_warning_for_carried_over_portfolio + 실 daemon boot 후 첫 fetch 동작 확인.
|
||||
- AC-2 (deferred): portfolio-hub#8 배포 후 ledger write 응답 소비 경로에 wiring 연결 + integration 테스트.
|
||||
- AC-3 (deferred): duplicate write 응답 idempotent 갱신 테스트.
|
||||
|
||||
#### Notes
|
||||
- BAT-008 verification.md `Human Approval Memo` 에 deferred residual risk 로 명시되어 있고, batch 전체는 release-candidate 로 promote 됨.
|
||||
@@ -0,0 +1,134 @@
|
||||
# req-028: 종목 스냅샷 read 메시지 계약 + envelope + degraded 신호
|
||||
|
||||
- Status: Implemented
|
||||
- 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)를 담고 가격은 제외한다.
|
||||
- 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) 이고 가격 필드는 없다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md, docs/interface-contract.md
|
||||
- Modules: trex_core/adapters/messaging (snapshot RPC 핸들러), 응답 스키마(transport-무관)
|
||||
- Tests: envelope 스키마 검증(빈 응답 포함), degraded 주입 테스트
|
||||
|
||||
## 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.
|
||||
@@ -0,0 +1,138 @@
|
||||
# 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 잔여).
|
||||
|
||||
## 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.
|
||||
@@ -0,0 +1,136 @@
|
||||
# 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 시 다음 요청부터 즉시 응답에 복귀한다.
|
||||
|
||||
## 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 상태가 보인다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md
|
||||
- Modules: pause 상태 store(Postgres), CLI 제어, dcy-006 RPC 제어 메시지 핸들러, 응답 산출 시 pause 마스킹
|
||||
- Tests: pause→호출→resume→호출 시퀀스, 재시작/refresh 후 영속
|
||||
|
||||
## 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 운영 검증.
|
||||
+11
-4
@@ -74,7 +74,7 @@
|
||||
|
||||
## Next Requirement ID
|
||||
|
||||
- Current: `REQ-027`
|
||||
- Current: `REQ-034`
|
||||
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
|
||||
|
||||
## Requirement Register
|
||||
@@ -107,11 +107,18 @@
|
||||
| REQ-024 | RabbitMQ 가용성 degrade 정책 (버퍼링 금지 + 보수적 중단 + core 안전 매도 독립) | Non-Functional | Implemented | High | project maintainers | [req-024](./Non-Functional/req-024_rabbitmq-availability-degrade-policy.md) |
|
||||
| REQ-025 | HTTP `/v1` API 완전 제거 (healthz 포함, HTTP 표면 0) | Interface | Implemented | High | project maintainers | [req-025](./Interface/req-025_http-api-complete-removal.md) |
|
||||
| REQ-026 | messaging 레이어 baseline 문서 정합 | Documentation | Implemented | Medium | project maintainers | [req-026](./Documentation/req-026_messaging-baseline-alignment.md) |
|
||||
| REQ-027 | portfolio-hub read 포트 + 어댑터 + stub | Integration | Implemented | High | project maintainers | [req-027](./Integration/req-027_portfolio-hub-read-port-and-adapter.md) |
|
||||
| REQ-028 | 종목 스냅샷 read 메시지 계약 + envelope + degraded 신호 | Interface | Implemented | High | project maintainers | [req-028](./Interface/req-028_snapshot-read-message-contract-and-envelope.md) |
|
||||
| REQ-029 | 자산 선별(slot overlay) + view 모드 + strategy_key 필터 | Interface | Implemented | High | project maintainers | [req-029](./Interface/req-029_asset-selection-slot-overlay-view-and-strategy-key.md) |
|
||||
| REQ-030 | 일일 스냅샷 스케줄러 + 옵션 D 현금/포지션 갱신 | Integration | Approved | High | project maintainers | [req-030](./Integration/req-030_daily-snapshot-scheduler-and-option-d-cash-position.md) |
|
||||
| REQ-031 | 포지션 정합 검증 + warning 마스킹 | Exception | Implemented | High | project maintainers | [req-031](./Exception/req-031_position-reconciliation-and-warning.md) |
|
||||
| REQ-032 | 런타임 pause/resume 제어 | Interface | Implemented | Medium | project maintainers | [req-032](./Interface/req-032_runtime-pause-resume-control.md) |
|
||||
| REQ-033 | 스냅샷 read 레이어 baseline 문서 정합 | Documentation | Implemented | Medium | project maintainers | [req-033](./Documentation/req-033_snapshot-read-baseline-alignment.md) |
|
||||
|
||||
## Recent Change Log Summary
|
||||
|
||||
- 2026-06-06 :: REQ-027~029, REQ-031~033 Approved → Implemented — BAT-008 release-candidate verification evidence 기반. REQ-030 은 AC-1 evidence 확보·AC-2/AC-3 portfolio-hub#8 배포 대기로 Approved 유지. (confirm-req-implemented)
|
||||
- 2026-06-06 :: REQ-027~033 Proposed → Approved — dcy-005 confirmed, 전체 승인 게이트 통과. REQ-030 옵션 D 구현은 portfolio-hub#8 배포 후 착수. (confirm-req)
|
||||
- 2026-06-06 :: REQ-027~033 최초 생성(Proposed) — dcy-005 FR-1~FR-9 분해(NFR-1 → REQ-027 흡수, NFR-2 → REQ-030 흡수, NFR-3 → REQ-028 흡수). (draft-req)
|
||||
- 2026-06-05 :: REQ-021~026 Approved → Implemented — BAT-007 release-candidate verification evidence 기반. (confirm-req-implemented)
|
||||
- 2026-06-05 :: REQ-021~026 Proposed -> Approved — 승인 게이트 통과. (confirm-req)
|
||||
- 2026-06-05 :: REQ-021~026 최초 생성(Proposed) — dcy-006 FR-1~FR-6 분해(NFR-1 → REQ-022 흡수, NFR-2 → REQ-023 흡수, NFR-3 → REQ-024 승격). (draft-req)
|
||||
- 2026-06-04 :: REQ-017~020 Approved → Implemented — BAT-006 release-candidate verification evidence 기반. (confirm-req-implemented)
|
||||
- 2026-06-04 :: REQ-017~020 Proposed -> Approved — 승인 게이트 통과. (confirm-req)
|
||||
|
||||
Reference in New Issue
Block a user