fix(ledger): disjoint unified action schema and refresh req-001 traceability docs
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
co-authored by
genichin
parent
e261a41b7f
commit
42297030ca
+1
-1
@@ -269,7 +269,7 @@ class LedgerHistoryItem(BaseModel):
|
||||
ledger_entry_id: int
|
||||
portfolio_id: str
|
||||
source: str
|
||||
action: str
|
||||
action: Literal["INVEST", "BUFFER_OUT", "BUFFER_IN", "WITHDRAW", "PROFIT", "BUY", "SELL", "REVERSAL"]
|
||||
recorded_at: datetime
|
||||
executed_at: datetime | None = None
|
||||
order_id: str | None = None
|
||||
|
||||
@@ -13,10 +13,9 @@ Test ID: TC-REQ-001-002
|
||||
Verifies:
|
||||
- REQ-001.01-AC02
|
||||
Test reference:
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_dividend_requires_executed_at_and_rejects_fee_field
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_dividend_rejects_invalid_amount_tax_and_unrelated_fields_without_state_change
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_dividend_rejects_sub_minimum_numeric_precision
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_dividend_rejects_amount_exceeding_numeric_20_8
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_dividend_rejects_invalid_amount_tax_and_unrelated_fields_without_state_change
|
||||
Automated: true
|
||||
|
||||
Test ID: TC-REQ-001-003
|
||||
@@ -41,6 +40,7 @@ Verifies:
|
||||
Test reference:
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_unified_ledger_includes_dividend_fields
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_unified_ledger_openapi_contains_nullable_amount
|
||||
- tests/test_v1_portfolios_manual_ledger.py::test_unified_ledger_history_item_rejects_dividend_numeric_branch_payload
|
||||
Automated: true
|
||||
|
||||
Test ID: TC-REQ-001-006
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
## Evidence Batch: local API regression run
|
||||
|
||||
Requirement revision: `REQ-001@1.0`
|
||||
Commit: `7aa3de524af5013341dbb25cf9afc28142010be7`
|
||||
Commit: `e261a41b7fdb9e614748218bc4f7ab06a2d7019d` + working-tree follow-up
|
||||
Environment: `local sandbox / pytest / fake repository`
|
||||
Executed at: `2026-09-09T12:16:43Z`
|
||||
Executed at: `2026-09-09T13:41:00Z`
|
||||
Run selector: `pytest -q -o addopts='' tests/test_v1_portfolios_manual_ledger.py`
|
||||
Run result: `35 passed`
|
||||
Run result: `38 passed`
|
||||
|
||||
Test ID: TC-REQ-001-002
|
||||
Result: PASS
|
||||
@@ -39,11 +39,11 @@ Result: PASS
|
||||
## Evidence Batch: independent real PostgreSQL re-review run
|
||||
|
||||
Requirement revision: `REQ-001@1.0`
|
||||
Commit: `f193aa6da33428783b91c1144fc8b9de5b3fb4bb`
|
||||
Commit: `e261a41b7fdb9e614748218bc4f7ab06a2d7019d`
|
||||
Environment: `disposable PostgreSQL / independent re-review`
|
||||
Executed at: `2026-09-09T12:05:39Z`
|
||||
Executed at: `2026-09-09T13:31:46Z`
|
||||
Run selector: `tests/test_bat025_portfolio_ledger_manual_metadata_migration.py (module)`
|
||||
Run result: `7 passed, 2 failed` (`2 failed` are pre-existing stale migration-head baseline)
|
||||
Run result: `9 passed, 2 failed` (`2 failed` are pre-existing stale migration-head baseline)
|
||||
|
||||
Test ID: TC-REQ-001-003
|
||||
Result: PASS
|
||||
@@ -59,15 +59,3 @@ Result: PASS
|
||||
|
||||
Test ID: TC-REQ-001-011
|
||||
Result: PASS
|
||||
|
||||
## Evidence Batch: local real PostgreSQL availability
|
||||
|
||||
Requirement revision: `REQ-001@1.0`
|
||||
Commit: `7aa3de524af5013341dbb25cf9afc28142010be7`
|
||||
Environment: `local sandbox / PostgreSQL DSN not configured`
|
||||
Executed at: `2026-09-09T12:16:43Z`
|
||||
Run selector: `pytest -q -o addopts='' tests/test_bat025_portfolio_ledger_manual_metadata_migration.py::test_dividend_tax_omitted_persists_zero_on_real_postgres`
|
||||
Run result: `1 skipped`
|
||||
|
||||
Test ID: TC-REQ-001-001
|
||||
Result: BLOCKED
|
||||
|
||||
@@ -12,10 +12,12 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import ValidationError
|
||||
|
||||
from app.core.config import Settings, get_settings
|
||||
from app.domain.models import LedgerEntry, Portfolio, TokenPrincipal
|
||||
from app.main import create_app
|
||||
from app.schemas.v1 import LedgerHistoryItem
|
||||
|
||||
_PORTFOLIO_ID = "pf-001"
|
||||
_USER_ID = "user-001"
|
||||
@@ -987,6 +989,21 @@ def test_unified_ledger_openapi_contains_nullable_amount() -> None:
|
||||
history_amount_types = {option.get("type") for option in schemas["LedgerHistoryItem"]["properties"]["amount"]["anyOf"]}
|
||||
assert history_amount_types == {"number", "null"}
|
||||
assert schemas["DividendLedgerHistoryItem"]["properties"]["amount"]["type"] == "string"
|
||||
assert "DIVIDEND" not in schemas["LedgerHistoryItem"]["properties"]["action"]["enum"]
|
||||
assert schemas["DividendLedgerHistoryItem"]["properties"]["action"]["const"] == "DIVIDEND"
|
||||
|
||||
|
||||
def test_unified_ledger_history_item_rejects_dividend_numeric_branch_payload() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
LedgerHistoryItem(
|
||||
ledger_entry_id=1,
|
||||
portfolio_id=_PORTFOLIO_ID,
|
||||
source="manual",
|
||||
action="DIVIDEND",
|
||||
recorded_at=datetime.now(UTC),
|
||||
amount=1.0,
|
||||
tax_amount=0.0,
|
||||
)
|
||||
|
||||
|
||||
def test_reversal_rejects_fee_tax_and_missing_target() -> None:
|
||||
|
||||
Reference in New Issue
Block a user