fix(review): address PR review findings for CORE-003

Critical fixes:
- Add math.isfinite() check to reject NaN/Infinity in _safe_quote_price
- Raise TypeError instead of silent 0.0 fallback in price_feed.py
- Use dict instead of Mapping for external data validation

Type improvements:
- Add PortfolioSnapshot TypedDict for type safety
- Add DisplayMode and EntryBasisMode Literal types
- Add explicit dict[str, Any] annotation in to_dict()
- Remove cast() in favor of type comment validation
This commit is contained in:
Bu5hm4nn
2026-03-30 00:39:02 +02:00
parent 1dce5bfd23
commit 98e3208b5e
4 changed files with 48 additions and 19 deletions

View File

@@ -8,10 +8,14 @@ from dataclasses import dataclass, field
from datetime import date
from decimal import Decimal
from pathlib import Path
from typing import Any
from typing import Any, Literal
from app.models.position import Position, create_position
# Type aliases for display mode and entry basis
DisplayMode = Literal["GLD", "XAU"]
EntryBasisMode = Literal["value_price", "weight"]
_DEFAULT_GOLD_VALUE = 215_000.0
_DEFAULT_ENTRY_PRICE = 2_150.0
_LEGACY_DEFAULT_ENTRY_PRICE = 215.0
@@ -102,7 +106,7 @@ class PortfolioConfig:
gold_value: float | None = None
entry_price: float | None = _DEFAULT_ENTRY_PRICE
gold_ounces: float | None = None
entry_basis_mode: str = "value_price"
entry_basis_mode: EntryBasisMode = "value_price"
loan_amount: float = 145000.0
margin_threshold: float = 0.75
monthly_budget: float = 8000.0
@@ -117,7 +121,7 @@ class PortfolioConfig:
underlying: str = "GLD"
# Display mode: how to show positions (GLD shares vs physical gold)
display_mode: str = "XAU" # "GLD" for share view, "XAU" for physical gold view
display_mode: DisplayMode = "XAU" # "GLD" for share view, "XAU" for physical gold view
# Alert settings
volatility_spike: float = 0.25
@@ -301,7 +305,7 @@ class PortfolioConfig:
assert self.gold_ounces is not None
# Sync legacy fields from positions before serializing
self._sync_legacy_fields_from_positions()
result = {
result: dict[str, Any] = {
"gold_value": self.gold_value,
"entry_price": self.entry_price,
"gold_ounces": self.gold_ounces,