The city card had accumulated independent checks for AI status, market availability, stale observations, breakouts, peak timing, model consensus, and next-bulletin waits. This introduces a CityDecisionState builder so UI components consume one coherent recommendation, urgency, evidence quality, AI status, market status, badges, and primary reason.
Constraint: Keep the current card copy and badge priority behavior while moving decision-state ownership out of the component.
Rejected: Refactor calendar and opportunity lanes in the same commit | the shared model should land behind the city card first, then other views can migrate with smaller visual-risk diffs.
Confidence: high
Scope-risk: moderate
Reversibility: clean
Tested: npm run build
Not-tested: Browser visual regression and dedicated unit tests for every decision-state combination.
AiPinnedForecastView had become a mini application that owned list state, card shell, freshness, market, AI evidence, and model evidence rendering in one place. This split keeps the workspace wrapper thin and gives the decision card explicit product-component seams for future recommendation reasons, risk levels, and mobile-specific layout work.
Constraint: Preserve existing weather, market, AI read, chart, refresh, remove, collapse, and mobile behavior.
Rejected: Rewrite the decision-state construction in the same pass | this component split should stay behavior-preserving before a state-model refactor.
Confidence: high
Scope-risk: moderate
Reversibility: clean
Tested: npm run build
Not-tested: Browser visual regression on physical mobile devices.