feat(holdings): REQ-043 현재 보유 평단(WAC) read — GET /v1/portfolios/{id}/holdings/cost-basis (BAT-018, PR #14)

dcy-008(confirmed)/REQ-043(Approved)/BAT-018. trex-core dcy-034 FR-7 cold-start seed 의존. AC 11/11, QC PASS. worktree+PR 워크플로 첫 파일럿.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
This commit is contained in:
2026-06-26 00:07:43 +09:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 8f9865bd8a
commit d93c0bcaf5
14 changed files with 1229 additions and 9 deletions
@@ -0,0 +1,60 @@
# BAT-018 Verification
- Status: draft-batch-verification
- Verified At: 2026-06-25
- Profile: batch-lite (app-service)
## pytest 실행 결과 (원문)
```
============================================================= test session starts =============================================================
platform linux -- Python 3.12.3, pytest-8.4.2, pluggy-1.6.0 -- /home/genichin/workspace/trex-lead/repos/portfolio-hub/.venv/bin/python3
cachedir: .pytest_cache
rootdir: /home/genichin/workspace/trex-lead/repos/portfolio-hub/.claude/worktrees/agent-adf14aa7889b45655
configfile: pyproject.toml
plugins: anyio-4.3.0
collecting ... collected 447 items
447 passed, 11 warnings in 23.24s
```
신규 테스트 20개: 전부 PASS
기존 회귀 427개: 전부 PASS (0 failed, 0 error)
경고 11개: 기존 DeprecationWarning (HTTP_422_UNPROCESSABLE_ENTITY deprecated) — 본 batch 변경과 무관, 선행 코드에서 유입.
## AC 커버리지
| AC | 테스트 함수 | 결과 |
| --- | --- | --- |
| AC-1 (buy-only WAC=11,000) | TestAC1WacBuysOnly::test_cost_basis_per_unit_is_11000 + 4개 | PASS |
| AC-2 (부분매도 WAC 불변, qty=50) | TestAC2PartialSellWacUnchanged::* (3개) | PASS |
| AC-3 (user owner → 200) | test_ac3_user_owner_read_token_returns_200 | PASS |
| AC-4 (비소유자 user → 403) | test_ac4_user_non_owner_returns_403 | PASS |
| AC-5 (daemon mismatch → 403) | test_ac5_daemon_mismatch_returns_403 | PASS |
| AC-6 (null daemon → 403) | test_ac6_null_daemon_returns_403 | PASS |
| AC-7 (미존재 portfolio → 404) | test_ac7_nonexistent_portfolio_returns_404 | PASS |
| AC-8 (빈 이력, qty=0 → 200 null) | test_ac8_empty_ledger_returns_200_null_fields | PASS |
| AC-9 (sell without buy → warning) | test_ac9_sell_without_buy_triggers_warning | PASS |
| AC-10 (no token → 401) | test_ac10_no_auth_token_returns_401 | PASS |
| AC-11 (OpenAPI 문서화) | test_ac11_endpoint_in_openapi | PASS |
## 추가 테스트 (커버리지 보강)
| 테스트 | 내용 |
| --- | --- |
| test_response_contains_all_required_fields | 7개 응답 필드 전부 존재 확인 |
| test_cost_basis_from_is_first_buy_date | cost_basis_from 비null 확인 |
| test_portfolio_id_in_response_matches_request | 응답 portfolio_id 일치 확인 |
## 회귀 영향
- 기존 테스트 427개 전부 통과 — 본 batch 변경(신규 함수/엔드포인트/스키마 추가)이 기존 코드에 미치는 회귀 없음.
- 변경 파일(app/domain/pnl.py, app/schemas/v1.py, app/api/v1_portfolios.py)은 모두 additive 변경(기존 코드 수정 없음, 신규 추가만).
## 검증 결론
- AC-1~11 전부 PASS.
- 기존 회귀 0 실패.
- HTTP API 계약: `GET /v1/portfolios/{portfolio_id}/holdings/cost-basis` 신규 추가(호환성 깨짐 없음, read-only).
- DB 마이그레이션: 없음(쓰기/스키마 변경 없음).
- 상태: `draft-batch-verification` 완료 → 팀장 `confirm-batch-verification` 대기.