59: Show Evelyn status indices in Mission Control Overview

This commit is contained in:
2026-08-05 14:09:01 +02:00
parent 493a6291a9
commit fdefba91ad
11 changed files with 306 additions and 13 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-05
@@ -0,0 +1,28 @@
## Context
Before this change, `Evelyn` declared `@NotNull String getStatusReport()`, `EvelynImpl` returned `"Hello World!"`, and no other local source called it. Mission Control presents parallel Production and Test tab sets. The API and reference implementations must remain separated by package.
## Goals / Non-Goals
**Goals:** Define a typed immutable measurement contract, replace the text API, and render each environment's Evelyn history in its corresponding existing Overview tab without disturbing the Production/Test tabs or styling.
**Non-Goals:** Real index calculation, persistence, refresh/polling after view creation, environment discovery, dependency resolution, final Nenjim environment wiring, and automated tests.
## Decisions
- Add `EvelynStatusIndexPoint` beside the Evelyn public API as an immutable value type. Use `Instant` for the timestamp and `BigDecimal` for each named index so time semantics are explicit and decimal values retain precision. A map or six-element list was rejected because it would lose compile-time names and completeness.
- Replace, rather than supplement, `getStatusReport()` with `@NotNull List<EvelynStatusIndexPoint> getStatusIndexHistory()`. The implementation returns an immutable hardcoded list in chronological order; callers must also tolerate an empty list. Keeping the text API was rejected because the issue intentionally replaces that contract.
- Make `EvelynMissionControlImpl` accept separate Production and Test Evelyn references. Fetch each reference's history while constructing its corresponding Overview so the two tabs remain independent even when the reference implementations currently return identical hardcoded values.
- Construct a distinct chart, axes, series, and data nodes for each Overview. Sharing a JavaFX `Node` is not valid because a node cannot have two parents.
- Have `NenjimHubImpl` create two separate `EvelynImpl` instances as temporary Production and Test placeholders and pass both to Mission Control. Future Nenjim wiring will supply the actual environment-specific Evelyn references; environment discovery and dependency resolution are outside issue #59.
- Use a time-capable numeric X-axis derived from each point's timestamp and a numeric Y-axis. Compute the largest absolute index magnitude across all series and use its negative and positive values as equal bounds; use a small symmetric fallback span when history is empty or all values are zero so zero remains visible. JavaFX chart construction remains in the reference implementation.
## Risks / Trade-offs
- [Hardcoded history can look authoritative] → Keep values clearly sample-only and isolate them in `EvelynImpl` for later replacement.
- [One extreme index compresses the other lines] → Accept a shared scale because direct comparison and a common zero baseline are required.
- [Breaking API removal affects downstream consumers outside this repository] → Publish the typed replacement in the same release and call out the method migration.
## Migration Plan
Add the value type, replace the interface method and reference implementation, construct distinct Production and Test Overview charts from their corresponding Evelyn references, and compile the project. Roll back the API and Overview changes together if needed; no stored data requires migration.
@@ -0,0 +1,27 @@
## Why
Evelyn exposes only an unstructured textual status report, which prevents Mission Control from plotting status changes over time. A typed historical API will make the six status indexes directly consumable by the existing Overview views.
## What Changes
- **BREAKING** Replace `Evelyn.getStatusReport()` with `List<EvelynStatusIndexPoint> getStatusIndexHistory()`.
- Add a typed measurement point containing a timestamp and the six Evelyn status indexes.
- Initially provide oldest-to-newest hardcoded sample history from the reference implementation.
- Give Mission Control separate Production and Test `Evelyn` references and plot each reference's history in its corresponding Overview tab using separate chart instances with dynamic Y-axes symmetric around a visible zero.
## Capabilities
### New Capabilities
- `evelyn-status-index-history`: Typed historical status-index access and Mission Control visualization.
### Modified Capabilities
None.
## Impact
- Affects the Evelyn public API and reference implementation in `com.fanitas.evelyn.core`.
- Affects Evelyn Mission Control's existing Overview content and introduces explicit Production/Test Evelyn wiring.
- Removes the textual status-report API; the repository currently has no callers beyond its declaration and implementation.
- Adds no persistence, real index calculation, environment discovery, dependency resolution, external dependency, or automated tests.
@@ -0,0 +1,23 @@
## Purpose
Provide typed historical Evelyn status measurements and make all six indexes visible over time in Mission Control.
## ADDED Requirements
### Requirement: Evelyn provides historical status-index measurements
Evelyn SHALL expose a non-null list of typed measurement points ordered from oldest to newest. Each point SHALL contain a timestamp, Evelyn Price Index, EVE_SYRUP Pool Depth Index, EVE_SYRUP Pool Balance Index, AAZDKK_USDT Pool Balance Index, AAZDKK_USDT Pool Price Index, and AAZDKK_USDT Pool Depth Index; the list MAY be empty.
#### Scenario: Status-index history is requested
- **WHEN** a caller requests Evelyn's status-index history
- **THEN** Evelyn returns a non-null, oldest-to-newest list whose points contain a timestamp and all six index values
### Requirement: Evelyn Mission Control visualizes status-index measurements
Evelyn Mission Control SHALL display historical measurements from separate Production and Test Evelyn references in their corresponding Overview tabs as six-line graphs, with timestamp on the X-axis and index value on the Y-axis. Each environment SHALL retrieve its own history and SHALL have a separate graph instance with a dynamic Y-axis range that is symmetric around zero and always displays zero as the desired state. The two histories MAY contain identical values but SHALL remain separate data sources.
#### Scenario: Production and Test Overviews are created with history
- **WHEN** Mission Control creates the Production and Test Overview views
- **THEN** it retrieves history from the corresponding Production and Test Evelyn references and creates a separate six-line graph for each environment whose symmetric Y-axis contains zero
#### Scenario: An environment has empty history
- **WHEN** Mission Control creates an environment's Overview view and that environment's Evelyn history is empty
- **THEN** it displays an empty six-series graph for that environment whose Y-axis still contains zero without substituting the other environment's history
@@ -0,0 +1,15 @@
## 1. Typed Status History
- [x] 1.1 Add the immutable `EvelynStatusIndexPoint` API value type with an `Instant` timestamp and six named `BigDecimal` index values.
- [x] 1.2 Replace `Evelyn.getStatusReport()` with the non-null `getStatusIndexHistory()` list contract.
- [x] 1.3 Implement an immutable, oldest-to-newest hardcoded sample history in `EvelynImpl`.
## 2. Mission Control Overview
- [x] 2.1 Update Mission Control to accept separate Production and Test Evelyn references and fetch each reference's history for its corresponding Overview tab.
- [x] 2.2 Update NenjimHub to supply two separate `EvelynImpl` placeholder instances and keep distinct six-series chart instances for the two histories.
- [x] 2.3 Configure a dynamic symmetric Y-axis around zero, including a usable zero-containing fallback range for empty or all-zero history.
## 3. Verification
- [x] 3.1 Compile the project and manually confirm each Overview tab renders its corresponding Evelyn history in a separate chart without adding automated tests.
@@ -0,0 +1,25 @@
# evelyn-status-index-history Specification
## Purpose
Provide typed historical Evelyn status measurements and make all six indexes visible over time in Mission Control.
## Requirements
### Requirement: Evelyn provides historical status-index measurements
Evelyn SHALL expose a non-null list of typed measurement points ordered from oldest to newest. Each point SHALL contain a timestamp, Evelyn Price Index, EVE_SYRUP Pool Depth Index, EVE_SYRUP Pool Balance Index, AAZDKK_USDT Pool Balance Index, AAZDKK_USDT Pool Price Index, and AAZDKK_USDT Pool Depth Index; the list MAY be empty.
#### Scenario: Status-index history is requested
- **WHEN** a caller requests Evelyn's status-index history
- **THEN** Evelyn returns a non-null, oldest-to-newest list whose points contain a timestamp and all six index values
### Requirement: Evelyn Mission Control visualizes status-index measurements
Evelyn Mission Control SHALL display historical measurements from separate Production and Test Evelyn references in their corresponding Overview tabs as six-line graphs, with timestamp on the X-axis and index value on the Y-axis. Each environment SHALL retrieve its own history and SHALL have a separate graph instance with a dynamic Y-axis range that is symmetric around zero and always displays zero as the desired state. The two histories MAY contain identical values but SHALL remain separate data sources.
#### Scenario: Production and Test Overviews are created with history
- **WHEN** Mission Control creates the Production and Test Overview views
- **THEN** it retrieves history from the corresponding Production and Test Evelyn references and creates a separate six-line graph for each environment whose symmetric Y-axis contains zero
#### Scenario: An environment has empty history
- **WHEN** Mission Control creates an environment's Overview view and that environment's Evelyn history is empty
- **THEN** it displays an empty six-series graph for that environment whose Y-axis still contains zero without substituting the other environment's history