docs: scope decimal boundary cleanup
This commit is contained in:
129
docs/CORE-001D_BOUNDARY_CLEANUP_PLAN.md
Normal file
129
docs/CORE-001D_BOUNDARY_CLEANUP_PLAN.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# CORE-001D Boundary and Persistence Cleanup Plan
|
||||
|
||||
## Goal
|
||||
Make Decimal/unit-safe domain types reliable at external boundaries without forcing a risky full-model rewrite.
|
||||
|
||||
This slice follows:
|
||||
- `CORE-001A` Decimal/unit foundations
|
||||
- `CORE-001B` overview + hedge migration
|
||||
- `CORE-001C` backtests + event comparison migration
|
||||
|
||||
## Why this exists
|
||||
The visible math paths now use unit-safe domain helpers, but several persistence and adapter seams still store or pass raw floats. That is acceptable at the edge for now, but the boundaries should be explicit, tested, and stable.
|
||||
|
||||
## Main hotspots found in the current codebase
|
||||
|
||||
### 1. Portfolio persistence still serializes raw floats
|
||||
Files:
|
||||
- `app/models/portfolio.py`
|
||||
- workspace-backed `portfolio_config.json` payloads
|
||||
|
||||
Current state:
|
||||
- `PortfolioConfig` stores float fields
|
||||
- `PortfolioRepository.save/load` round-trips plain JSON numbers
|
||||
|
||||
Risk:
|
||||
- persistence format is implicit
|
||||
- Decimal-safe internal math can be silently rounded or reinterpreted at reload boundaries
|
||||
|
||||
### 2. Legacy portfolio/domain types still expose float-heavy APIs
|
||||
Files:
|
||||
- `app/models/portfolio.py`
|
||||
- `app/services/settings_status.py`
|
||||
- `app/services/alerts.py`
|
||||
|
||||
Current state:
|
||||
- `LombardPortfolio` remains float-based for compatibility
|
||||
- several services convert Decimal-backed results back to float for formatting/threshold checks
|
||||
|
||||
Risk:
|
||||
- domain-safe calculations exist, but callers can still drift into ambiguous float semantics
|
||||
|
||||
### 3. Backtesting UI/service seams still take float inputs
|
||||
Files:
|
||||
- `app/services/backtesting/ui_service.py`
|
||||
- `app/services/backtesting/comparison.py`
|
||||
- `app/services/event_comparison_ui.py`
|
||||
- `app/domain/backtesting_math.py`
|
||||
|
||||
Current state:
|
||||
- typed materialization exists, but service entrypoints still accept `float`
|
||||
- conversions back to float happen for model compatibility
|
||||
|
||||
Risk:
|
||||
- callers can bypass intent and reintroduce unit ambiguity at service boundaries
|
||||
|
||||
### 4. Provider/cache adapters use generic JSON and float payloads
|
||||
Files:
|
||||
- `app/services/cache.py`
|
||||
- `app/services/price_feed.py`
|
||||
- `app/services/data_service.py`
|
||||
- `app/services/backtesting/historical_provider.py`
|
||||
|
||||
Current state:
|
||||
- cache serialization supports datetime only via custom default
|
||||
- provider payloads are mostly raw floats, dicts, and lists
|
||||
|
||||
Risk:
|
||||
- external payloads are fine to keep float-heavy, but conversion into domain-safe structures should happen at named boundaries and be test-covered
|
||||
|
||||
## Recommended implementation order
|
||||
|
||||
### Step 1: make persistence format explicit
|
||||
Target:
|
||||
- `PortfolioConfig` JSON shape
|
||||
- workspace portfolio JSON shape
|
||||
|
||||
Deliverables:
|
||||
- explicit serialization helpers for persisted money/price/weight-like fields
|
||||
- tests proving stable round-trip behavior
|
||||
- docs for JSON number vs string decisions
|
||||
|
||||
Preferred near-term approach:
|
||||
- keep external JSON ergonomic
|
||||
- document exact persisted field meanings and units
|
||||
- ensure reload path normalizes through a single constructor/adapter
|
||||
|
||||
### Step 2: add named boundary adapters
|
||||
Target:
|
||||
- portfolio persistence load/save
|
||||
- price feed quote ingestion
|
||||
- historical close ingestion
|
||||
- options-chain normalization
|
||||
|
||||
Deliverables:
|
||||
- helper functions with explicit names such as `*_from_provider_payload(...)` or `*_to_persistence_dict(...)`
|
||||
- tests proving conversion behavior and fail-closed validation
|
||||
|
||||
### Step 3: reduce raw-float service entrypoints where practical
|
||||
Target:
|
||||
- backtesting UI/comparison service inputs
|
||||
- settings/alerts status helpers
|
||||
|
||||
Deliverables:
|
||||
- services accept typed or normalized values earlier
|
||||
- float conversion, where still required, happens at the last compatibility seam
|
||||
|
||||
## Non-goals
|
||||
- replacing every float in every Pydantic/dataclass immediately
|
||||
- redesigning third-party payload models wholesale
|
||||
- changing public UI formatting behavior just for type purity
|
||||
|
||||
## First candidate sub-slices
|
||||
|
||||
### CORE-001D1 — Portfolio persistence serialization seam
|
||||
- make `PortfolioConfig` persistence round-trip explicit
|
||||
- add serialization tests for workspace-scoped config files
|
||||
|
||||
### CORE-001D2 — Provider and cache adapter boundaries
|
||||
- document/test cache + provider conversion seams
|
||||
- ensure raw external floats are normalized before domain math
|
||||
|
||||
### CORE-001D3 — Service entrypoint tightening
|
||||
- narrow float-heavy internal service APIs where easy and low-risk
|
||||
|
||||
## Success criteria
|
||||
- persistence schema for bookkeeping-sensitive fields is explicit and tested
|
||||
- Decimal/unit-safe values cross boundaries through named adapters
|
||||
- remaining float-heavy hotspots are either removed or intentionally documented as edge-only
|
||||
- no regression in existing browser-visible flows
|
||||
@@ -13,3 +13,6 @@ acceptance_criteria:
|
||||
- Decimal-bearing JSON/API serialization is documented and tested.
|
||||
- Float-heavy integrations have named conversion boundaries.
|
||||
- Remaining raw-float domain hotspots are identified or removed.
|
||||
technical_notes:
|
||||
- Prioritize portfolio/workspace persistence, provider normalization, and cache serialization seams.
|
||||
- See `docs/CORE-001D_BOUNDARY_CLEANUP_PLAN.md` for the current hotspot inventory and proposed sub-slices.
|
||||
|
||||
Reference in New Issue
Block a user