47 lines
1.2 KiB
Python
47 lines
1.2 KiB
Python
"""Fail-closed holding mirror auto-reconciliation contracts (issue #94)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from typing import Protocol
|
|
from uuid import UUID
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class HoldingsCostBasisEvidence:
|
|
"""Canonical portfolio-hub evidence captured by one successful HTTP read."""
|
|
|
|
portfolio_id: str
|
|
symbol: str
|
|
current_quantity: float
|
|
cost_basis_per_unit: float
|
|
total_cost_basis: float
|
|
observed_at: datetime
|
|
data_completeness_warning: str | None = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AutoReconcileCommand:
|
|
"""CAS-bound command for one atomic mirror repair."""
|
|
|
|
slot_id: UUID
|
|
instance_key: str
|
|
portfolio_id: str
|
|
symbol: str
|
|
expected_qty: float
|
|
expected_avg_price: float | None
|
|
target_qty: float
|
|
target_avg_price: float
|
|
hub_quantity: float
|
|
broker_quantity: int
|
|
evidence_observed_at: datetime
|
|
|
|
|
|
class AutoReconcileStore(Protocol):
|
|
"""Atomic qty/avg/audit/B-warning persistence boundary."""
|
|
|
|
def apply_holding_mirror(self, command: AutoReconcileCommand) -> bool:
|
|
"""Apply exactly once when every CAS/eligibility condition still holds."""
|
|
...
|