# Forecast Public V2 Cleanup Plan

This is a plan, not an active contract change. `forecast-public-v1` remains the live public boundary.

## Goals

- Remove deprecated aliases without breaking known consumers
- Replace the nested legacy `forecast` bag with an explicit versioned object
- Make camelCase universal across the public payload
- Tighten version boundaries so future additions happen intentionally

## Proposed V2 Scope

### 1. Remove deprecated aliases

Delete these v1-only compatibility fields once consumers are migrated:

- `forecast_balance`
- `prob`
- `line`
- `projected_stat_value`
- `stat_type`
- `normalized_stat_type`
- `market_line_value`

Requirements before removal:

- frontend and any downstream consumers read only canonical camelCase fields
- route-contract snapshot coverage is updated for the v2 shape
- changelog/release note calls out the removals explicitly

### 2. Replace the nested legacy forecast blob

Current problem:

- `/forecast` still exposes a legacy `forecast` object with snake_case keys and mixed historical structure

V2 target:

- replace `forecast` with an explicit `forecastData` contract object
- camelCase all nested fields
- move known nested structures into named typed sections instead of a loose bag
- remove legacy-only nested keys rather than carrying them forward

Suggested shape:

- `forecastData.summary`
- `forecastData.winnerPick`
- `forecastData.forecastSide`
- `forecastData.keyFactors`
- `forecastData.propHighlights`
- `forecastData.projectedLines`
- `forecastData.totalDirection`
- `forecastData.valueRating`
- `forecastData.spreadEdge`
- `forecastData.mlbPhaseContext`

### 3. Tighten route version boundaries

Options:

- explicit `/v2/forecast/...` routes
- negotiated contract version header
- serializer-level `forecast-public-v2` constant with route opt-in

Practical recommendation:

- keep the current routes
- add a serializer switch with a clear `forecast-public-v2` version constant
- only expose v2 once snapshots, frontend, and any external consumers are ready

### 4. Finish public camelCase normalization

V2 should remove remaining legacy snake_case from all public surfaces, especially:

- nested `/forecast` payload keys
- any UI-only holdover fields that duplicate canonical values

### 5. Strengthen contract ownership

Before shipping v2:

- extract shared public contract types into a true repo-shared package if the current cross-import setup becomes brittle
- keep alias maps and serializer builders version-specific
- require golden snapshot updates for every public response change

## Migration Sequence

1. Audit all consumers for v1 deprecated alias usage.
2. Switch frontend reads to canonical camelCase only.
3. Introduce a v2 serializer and golden snapshots in parallel.
4. Validate v2 in staging with real consumer traffic if available.
5. Announce deprecation window for v1 aliases and nested legacy fields.
6. Ship v2 intentionally instead of mutating v1.
