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:
@@ -27,7 +27,7 @@
|
||||
|
||||
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).
|
||||
3. **daemon_id 도출**: `PortfolioHubReadPort` 초기화 시 portfolio-hub `GET /v1/user_info` 1회 호출 → 응답 `daemon_id` 추출·캐시. `TREX_PORTFOLIO_HUB_TOKEN` 자격증명 재사용(REQ-027 A-1). (정정: REQ-027 CHG-04 — `/v1/auth/whoami` 부재로 `/v1/user_info` 로 변경)
|
||||
|
||||
4. **strategy_key 필터**: 요청 payload 의 `strategy_key`(str) 를 자산의 `active_strategy_id` 와 **대소문자 구분 정확 일치**(`==`)로 필터링. 생략 시 필터 없음.
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- REQ-027:
|
||||
- AC-1: stub + HTTP MockTransport 통합테스트에서 `PortfolioItem` 항목당 `symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params` 필드 + `price` 부재 확인.
|
||||
- REQ-027 (계약 정정 CHG-04 반영):
|
||||
- AC-1: HTTP MockTransport 통합테스트에서 `{portfolios:[…]}` envelope 파싱 + `managed_by_daemon_id` 클라이언트측 필터 + `PortfolioItem` 항목 `symbol/asset_id/cash_balance/asset_quantity/active_strategy_id/strategy_params` 필드 + `price` 부재 확인. 실 list 응답에 전략 필드 없으면 None/`{}` 기본값.
|
||||
- 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).
|
||||
- AC-4: HTTP MockTransport 가 `/v1/user_info` 호출 + Bearer 토큰 헤더 + `daemon_id` 도출 확인. 스킴 없는 base URL → `http://` 기본 적용. `TREX_DAEMON_ID` env 1차 출처 없음(코드 review).
|
||||
|
||||
- REQ-028:
|
||||
- AC-1: envelope 응답이 정확히 `{assets, view, available_slots, degraded, reason, message}` 키 집합 + `assets` 가 항상 list(null 금지) 확인.
|
||||
@@ -48,10 +48,10 @@
|
||||
### 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-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::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-027 AC-4: `tests/adapters/portfolio/test_hub_read.py::test_whoami_returns_token_daemon_id` (`/v1/user_info` URL/Bearer 헤더/응답 디코드 + daemon_id 추출) + `::test_base_url_without_scheme_defaults_to_http`.
|
||||
- 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`.
|
||||
@@ -89,6 +89,15 @@
|
||||
- `.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` 정상 노출.
|
||||
|
||||
### Re-verification Addendum (2026-06-06, REQ-027 CHG-04 — release 선행 정리)
|
||||
- 사유: release-candidate 확정 이후 실 portfolio-hub API 실측으로 read 계약 불일치 발견 → 어댑터/테스트 정정(commit 43bad24). 본 batch verification 을 정정 계약 기준으로 재확인.
|
||||
- 정정 요지: whoami `/v1/auth/whoami`→`/v1/user_info`; list envelope `{items}`→`{portfolios,total}`; 토큰 스코프 → 클라이언트측 `managed_by_daemon_id` 필터; base URL 스킴 누락 시 `http://` 보정; 실 `PortfolioItem` 전략 필드 부재 → None/`{}`(이월).
|
||||
- 재실행 결과:
|
||||
- `.venv/bin/python -m pytest tests/adapters/portfolio/test_hub_read.py -q` → `6 passed`.
|
||||
- `.venv/bin/python -m pytest -q` (infra env 미설정 invocation) → `165 passed, 23 skipped` (PG/RabbitMQ/KIS 게이트 skip). `ruff check trex_core tests` → `All checks passed!`.
|
||||
- 실 portfolio-hub e2e (portfolio-hub#9 user_info 500 수정 반영 후): `PortfolioHubReadAdapter.whoami()`→`daemon_id=b5084542-…`, `get_portfolios()`→삼성전자(005930) 1건, `SnapshotScheduler.run_once()`→`degraded=None`, universe 1건, warning 없음.
|
||||
- 영향 결론: 현재 코드가 실 계약과 일치하고 모든 AC evidence 가 정정 테스트명으로 재연결됨. REQ-027 Implemented 유지, BAT-008 release-candidate 유지. Ready for Release 변동 없음.
|
||||
|
||||
## Result
|
||||
- Ready for Release: true
|
||||
- Blocking Issues:
|
||||
|
||||
Reference in New Issue
Block a user