# BAT-024 Verification ## Status - Stage: draft-batch-verification - Result: PASS (developer self-verification) - Date: 2026-07-14 KST ## Scope - REQ-056: owner-scoped 수동 장부 입력 HTTP API - Implemented endpoints: - `POST /v1/portfolios/{portfolio_id}/ledger/manual` - `GET /v1/portfolios/{portfolio_id}/ledger/manual` - `GET /v1/portfolios/{portfolio_id}/returns/summary` - Preserved endpoint: - `POST /v1/portfolios/{portfolio_id}/ledger/trades` ## Evidence ### Static/syntax ```text python3 -m compileall app exit_code=0 ``` ### Full regression ```text PYTHONPATH=. uv run python -m pytest -q --override-ini addopts='' 594 passed, 12 warnings in 37.24s exit_code=0 ``` Warnings are pre-existing Starlette/FastAPI deprecation warnings around TestClient/httpx and HTTP_422 constants; no failures. ### Targeted regression ```text PYTHONPATH=. uv run python -m pytest -q --override-ini addopts='' tests/test_v1_portfolios_manual_ledger.py tests/test_v1_portfolios_crud.py tests/test_v1_portfolios_trades.py 45 passed, 8 warnings in 5.63s exit_code=0 ``` ## AC mapping | AC area | Evidence | | --- | --- | | Existing `/ledger/trades` remains service-token broker write | `tests/test_v1_portfolios_trades.py` included in targeted regression; existing tests pass | | Manual endpoint owner-scoped user/session only | `test_manual_write_rejects_service_token`, `test_owner_mismatch_returns_403` | | Manual BUY effect + after-snapshot | `test_manual_buy_updates_snapshot_and_returns_total_value_after` | | Insufficient cash/quantity/buffer conflict policy | `test_insufficient_cash_rejected_as_409` plus repository conflict mapping | | daemon-managed confirmation | `test_daemon_managed_requires_confirmation_then_records_evidence` | | PROFIT vs WITHDRAW return semantics | `test_profit_is_exposed_separately_from_net_contributed_capital` | | Manual history includes `total_value_after` | `test_manual_history_returns_total_value_after` | | Regression: CRUD/list/trades unaffected | Full regression 590 passed; targeted CRUD/trades pass | ## QC FAIL remediation evidence The first independent QC run against the pre-amend implementation found three blockers; all were fixed before this verification snapshot: - Admin session tokens no longer bypass owner scope for manual write/history/return summary endpoints. - Amount/reversal actions reject explicit `fee`/`tax` fields with HTTP 422. - REVERSAL target-not-found now maps to HTTP 404 `LEDGER_ENTRY_NOT_FOUND`. Added regression coverage in `tests/test_v1_portfolios_manual_ledger.py`: - `test_admin_session_does_not_bypass_manual_owner_scope` - `test_admin_session_does_not_bypass_manual_read_owner_scope` - `test_amount_actions_reject_fee_and_tax_fields` - `test_reversal_rejects_fee_tax_and_missing_target` ## Independent QC result - QC delegation: `deleg_f2337a39` - Target HEAD: `b3447f6` - Verdict: PASS - QC compile evidence: `python3 -m compileall app` → `exit_code=0` - QC full regression: `PYTHONPATH=. uv run python -m pytest -q --override-ini addopts=''` → `594 passed, 12 warnings in 37.29s` - QC focused remediation tests: admin owner-scope, manual read owner-scope, fee/tax validation, reversal missing target → `4 passed, 1 warning in 0.92s` - Lead decision: `confirm-batch-verification` PASS accepted. ## Notes / follow-up risks - The implementation adds additive bootstrap columns via `ensure_schema()` for `portfolio_ledger`: `source`, `target_ledger_entry_id`, `confirmation_evidence`, `actor_user_id`. - No Alembic migration file was added in this batch. Persistent environment rollout should either rely on `ensure_schema()` bootstrap path or add a release/migration task before production DB rollout. - `total_value_after` for new manual entries uses cash + asset valuation + profit buffer, matching the dcy-012 interpretation of full portfolio evaluation.