docs(srs): REQ-027 CHG-04 — correct portfolio-hub read contract for release
Align REQ-027 and BAT-008 verification/design with the live portfolio-hub
API discovered during release prep: whoami via /v1/user_info, {portfolios}
envelope, client-side managed_by_daemon_id filter, http:// scheme default,
and strategy fields deferred (None/{}). Records the re-verification evidence
(new contract tests + live e2e) so BAT-008 can bundle into the first release
with non-stale verification. REQ-027 stays Implemented.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -9,16 +9,16 @@
|
||||
- 전략 모듈에 제공할 종목 스냅샷의 원천인 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 가 해석하지 않고 통과시킨다.
|
||||
- `PortfolioHubReadPort.get_portfolios(daemon_id)` application 포트 + portfolio-hub read 어댑터(portfolio-hub `GET /v1/portfolios`, `list_portfolios_v1`) + 결정론 stub 를 제공한다. `/v1/portfolios` 는 토큰 스코프 조회라 `managed_by_daemon_id` 쿼리 파라미터가 없으므로, 어댑터는 응답 항목의 `managed_by_daemon_id == daemon_id` 로 **클라이언트측 필터**한다. (정정: CHG-04)
|
||||
- 어댑터는 dcy-004 의 portfolio-hub 자격증명(.env `TREX_PORTFOLIO_HUB_*`)을 재사용한다. base URL 에 스킴이 없으면 `http://` 를 기본 적용한다.
|
||||
- `daemon_id` 는 portfolio-hub 자격증명/인증 토큰에서 도출한다(단일 진실원). 별도 `TREX_DAEMON_ID` 설정값을 1차 출처로 두지 않으며, `GET /v1/user_info` 응답의 `daemon_id` 로 1회 도출·캐시한다. (정정: CHG-04, `/v1/auth/whoami` 부재)
|
||||
- 각 universe 항목은 symbol, asset_id(=portfolio_id), cash_balance, asset_quantity, active_strategy_id, 전략파라미터(opaque JSON)를 담고 가격(price)은 제외한다. 전략파라미터는 trex-core 가 해석하지 않고 통과시킨다. 단, 실 `/v1/portfolios`(`PortfolioItem`)는 `active_strategy_id`/`strategy_params` 를 제공하지 않아 두 필드는 None/`{}` 로 채워진다(실데이터 채움 이월 — CHG-04).
|
||||
|
||||
## 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) 형태로 반환하고 가격 필드는 없다.
|
||||
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) 형태로 반환하고 가격 필드는 없다. (실 list 응답에 전략 필드가 없으면 None/`{}` — CHG-04)
|
||||
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).
|
||||
4. Given `TREX_DAEMON_ID` 미설정, When daemon 기동·universe 조회, Then `GET /v1/user_info` 응답에서 도출한 daemon_id 로 동작한다(OQ-7, CHG-04).
|
||||
|
||||
## Impacted Area
|
||||
- Docs: docs/discovery/dcy-005_20260604_portfolio-hub-asset-snapshot-api.md, docs/interface-contract.md
|
||||
@@ -26,7 +26,8 @@
|
||||
- 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).
|
||||
- (정정, CHG-04) 라이브 portfolio-hub 실측 계약: `GET /v1/user_info` → `UserInfoResponse{daemon_id,…}`; `GET /v1/portfolios` → `PortfolioListResponse{portfolios:[PortfolioItem], total}` (토큰 스코프, `managed_by_daemon_id` 쿼리 없음 → 클라이언트측 필터). `PortfolioItem` 은 cash_balance/asset_quantity/managed_by_daemon_id 는 포함하나 `active_strategy_id`/`strategy_params` 는 미포함(detail 의 `strategy_set` 에만 존재). 구 가정(`/v1/auth/whoami`, `{items:[…]}`, `managed_by_daemon_id` 쿼리 스코프)은 폐기.
|
||||
- 전략 필드 부재는 단일 전략(orb-v1, `strategy_key` 미사용) 단계에서 무해(REQ-029 CHG-04). 2번째 전략 도입 시 strategy_set 보강 또는 별도 change-req 로 해소.
|
||||
- NFR-1(도메인 순수성)을 본 REQ 의 AC-3 로 흡수한다.
|
||||
|
||||
## Change Log
|
||||
@@ -133,3 +134,46 @@
|
||||
- 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.
|
||||
|
||||
### CHG-20260606-04
|
||||
- Date: 2026-06-06
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 실 portfolio-hub API 와의 계약 불일치를 정정: whoami 엔드포인트는 `/v1/auth/whoami`(부재) → **`GET /v1/user_info`**, list 응답 envelope 는 `{items:[…]}` → **`{portfolios:[…], total}`**, `/v1/portfolios` 는 토큰 스코프라 `managed_by_daemon_id` 쿼리 파라미터가 없어 **클라이언트측 필터**로 전환. 실 `PortfolioItem` 에 `active_strategy_id`/`strategy_params` 가 없어 None/`{}` 기본값으로 통과(전략 필드 실데이터 채움은 이월). 어댑터/테스트는 이미 정정 구현·재검증됨.
|
||||
|
||||
#### Intent
|
||||
- 가정 기반(confirm-discovery 미검증)으로 작성됐던 read 계약을 라이브 API 실측에 맞춰 정정하고, 정정 구현의 재검증 evidence(신규 테스트 + 실 e2e)를 연결한다.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added: none
|
||||
- Updated:
|
||||
- AC-1: list 조회는 토큰 스코프 + 클라이언트측 `managed_by_daemon_id` 필터로 동작. 반환 항목은 동일 필드 형태(가격 없음)를 유지하되, 실 `/v1/portfolios`(`PortfolioItem`)가 `active_strategy_id`/`strategy_params` 를 제공하지 않아 해당 두 필드는 None/`{}` 로 채워진다(실데이터 채움은 이월 — REQ-029 CHG-04, detail `strategy_set` 보강 또는 별도 change-req).
|
||||
- AC-4: 토큰 daemon_id 도출은 `GET /v1/user_info` 응답의 `daemon_id` 로 한다(`/v1/auth/whoami` 아님).
|
||||
- Removed: none
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs:
|
||||
- 본 REQ Requirement/AC-1/AC-4/Notes 정정
|
||||
- BAT-008 design.md/verification.md 계약 정정 반영(같은 변경 묶음)
|
||||
- Modules:
|
||||
- trex_core/adapters/portfolio/hub_read.py (정정 구현 완료, commit 43bad24)
|
||||
- Tests:
|
||||
- tests/adapters/portfolio/test_hub_read.py (실 계약으로 갱신, commit 43bad24)
|
||||
|
||||
#### Delivery Trace Delta
|
||||
- Batches:
|
||||
- BAT-008 (release-candidate) — 계약 정정 반영, verification 재확인 대상
|
||||
- Releases:
|
||||
- none (첫 릴리즈 묶음 대상)
|
||||
|
||||
#### Revalidation Impact
|
||||
- Reverification Needed: yes — 완료. 정정 어댑터에 대해 신규 contract 테스트 통과 + 실 portfolio-hub e2e(whoami→get_portfolios→scheduler run_once `degraded=false`, 삼성전자 1건 수신) 확인.
|
||||
- Existing Implementation Invalidated: no — 현재 코드가 실 계약과 일치(정정 후). 무효화된 것은 구 verification 산출물의 테스트명/엔드포인트 기술뿐이며 BAT-008 verification 갱신으로 동기화.
|
||||
- Status Recommendation: Implemented 유지.
|
||||
- Follow-up Action: 전략 필드 실데이터 채움(2번째 전략 도입 시) 재검토. portfolio-hub#9(user_info 500) 수정 완료로 daemon_id 도출 가능.
|
||||
|
||||
#### Validation Plan
|
||||
- AC-1: tests/adapters/portfolio/test_hub_read.py::test_get_portfolios_parses_envelope_and_filters_by_daemon + ::test_get_portfolios_includes_items_without_daemon_field + test_stub_read.py.
|
||||
- AC-4: ::test_whoami_returns_token_daemon_id (`/v1/user_info` 단언) + ::test_base_url_without_scheme_defaults_to_http.
|
||||
- 실 e2e: SnapshotScheduler.run_once() against live portfolio-hub → degraded=None, universe 1건.
|
||||
|
||||
Reference in New Issue
Block a user