Generated file. Source:
docs/analysis_models_architecture.mdEdit the source document and runnpm run docs:syncto refresh this published copy.
Analysis Models Architecture¶
This document defines the architectural layer for interpretation and analysis models built on top of the canonical bond-engine result.
Goal¶
The product must support more than one defended interpretation of the same simulation result without corrupting the canonical result contract.
This layer exists to make that possible.
It should allow the project to add new analytical interpretations over time, such as:
- investment progression
- year-by-year liquidation comparison
- future scenario analysis
- future portfolio analysis
- future prediction-vs-reality comparison
Architectural Position¶
The analysis-model layer sits between:
- the canonical result model produced by the engine
- view adapters and UI components
Simplified flow:
flowchart LR
A[Selection and normalized inputs] --> B[Bond engine]
B --> C[Canonical result model]
C --> D[Analysis model]
D --> E[View adapters]
E --> F[Table]
E --> G[Chart]
E --> H[Summary]
Layering Rules¶
1. Canonical result model¶
Responsibility:
- remain the stable engine output
- describe the real progression of the investment under product mechanics
- stay independent from any one analytical interpretation
Current source of truth:
2. Analysis models¶
Responsibility:
- reinterpret the same canonical result in an explicit and defensible way
- expose contracts owned by the analytical meaning, not by one UI component
- keep product semantics out of view components
Initial models:
investment_progressionyear_by_year_liquidation
3. View adapters¶
Responsibility:
- prepare analysis-model outputs for table, chart, summary, export, or future UI needs
- stay presentation-oriented
- not invent financial semantics locally
Why This Layer Is Needed¶
Without this layer, new interpretations tend to end up in the wrong places:
- inside table components
- inside generic result adapters
- as convenience fields added directly to the canonical result contract
All three would make the product harder to extend and easier to misinterpret.
Initial Semantics¶
investment_progression¶
This is the defended meaning of the current yearly interpretation.
It answers:
- how the investment evolves under the actual product mechanics
- what taxes, redemption costs, and carried value look like during the investment
Important:
- intermediate rows describe the in-flight state of the investment
- the last year remains the authoritative answer for the chosen horizon
year_by_year_liquidation¶
This is a separate comparative interpretation.
It answers:
- what outcome should be presented if the investment is treated as ending in year
X
Important:
- it is not the hidden meaning of current yearly rows
- it must be explicitly labeled as a comparison mode
- in v1 it is implemented as a dedicated analysis model above the canonical result
- in v1 each yearly comparison row is produced by recalculating the engine for the same investment setup with the horizon shortened to year
X
Contract Direction¶
The layer should use:
- a small shared base contract for analysis models
- model-specific output contracts for real analytical differences
Examples:
InvestmentProgressionAnalysisYearByYearLiquidationAnalysis
The project should avoid creating one giant universal output type with many optional fields.
Dependency Rules¶
- engine strategies may produce canonical results and optional simulation details
- canonical result types must not depend on analysis models
- analysis models may depend on canonical result types and documented simulation details
- view adapters may depend on analysis-model outputs
- UI components should depend on view adapters, not on analytical logic
Extensibility Rules¶
Adding a new analysis model should normally require:
- a new model id
- a dedicated model module
- a registration entry
- contract tests
- documentation updates
Adding a new analysis model should not normally require:
- changing the canonical result contract
- changing engine strategy outputs
- adding interpretation-specific fields directly to
BondCalculationResult
If a model cannot be implemented without new source data, that gap should be documented explicitly as an engine-support need rather than hidden in UI code.
First Implementation Scope¶
The first product rollout of this layer is now exposed through:
- one shared global analysis-mode state
- two small section-level UI switches acting as interfaces to that same state
That shared state controls:
- chart semantics
- summary semantics
- yearly-table semantics
Why:
- the product decision is no longer local to one component
- the user is choosing one defended interpretation of the same simulation
- keeping the state global reduces semantic drift between result sections
Current UI implementation:
- one switch is placed in
Wykres Porównawczy - one switch is placed in
Szczegółowa Tabela Roczna - both operate on the same global
analysisMode Podsumowanie Wynikówreflects the active mode without introducing a third competing control
UI control map:
| UI section | Own switch | Consumes active mode | Responsibility |
|---|---|---|---|
Wykres Porównawczy |
Yes |
Yes |
lets the user change the shared analysis state while reading aggregated output |
Podsumowanie Wyników |
No |
Yes |
reflects the selected interpretation without creating a competing control |
Szczegółowa Tabela Roczna |
Yes |
Yes |
lets the user change the shared analysis state while reading detailed yearly output |
Shared-control diagram:
This diagram shows the architectural flow from the shared global state into analysis-aware adapters, not just the user-facing placement of controls.
flowchart LR
A[Chart switch] --> C[Global analysisMode state]
B[Yearly-table switch] --> C
C --> D[Chart adapters]
C --> E[Summary adapters]
C --> F[Yearly-table adapters]
The yearly table remains the most detailed consumer of the difference between progression and liquidation semantics, but it is no longer the only entry point for that choice.