The dashboard had several oversized orchestration, component, and CSS files that made product-copy changes and mobile/performance work risky. This refactor preserves behavior while splitting scan terminal CSS, opportunity helpers, future forecast panels, history/detail charts, and probability/model sections into smaller ownership boundaries.
Constraint: No user-visible version bump because this batch is architecture and performance cleanup, not a release announcement.
Rejected: Rewrite dashboard state management in the same batch | too broad for a safe upload after CSS and component splitting.
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep new component/CSS boundaries instead of moving product copy back into the large dashboard files.
Tested: npm run build; npm run test:business; git diff --check
Not-tested: Browser visual smoke test after push
The dashboard risk is now mostly contradictory state combinations rather than styling. This extracts calendar action grouping into a pure utility and adds a lightweight TypeScript business-state runner so key decision states can be asserted without adding a test dependency.
Constraint: No new dependencies; use the existing TypeScript package for a local runner.
Rejected: Only rely on Next build/typecheck | it cannot catch product-language regressions such as fallback AI being labeled complete.
Confidence: high
Scope-risk: moderate
Reversibility: clean
Tested: npm run test:business
Tested: npm run build
Not-tested: Browser-rendered mobile fold interaction snapshots.
Temperature formatting was embedded in the large dashboard utility module, so small scan-terminal views had to import the heavy utility surface for simple labels. This moves the pure temperature helpers into a lightweight module while keeping dashboard-utils re-exports for compatibility.
Constraint: Preserve existing temperature text output and all dashboard-utils import compatibility.
Rejected: Split chart, pace, and model helpers in the same pass | those helpers have wider coupling and should move one boundary at a time.
Confidence: high
Scope-risk: narrow
Reversibility: clean
Tested: TypeScript diagnostics for temperature-utils, dashboard-utils, and OpportunityTable
Tested: npm run build
Not-tested: Bundle analyzer size comparison.
Opportunity and calendar cards now isolate item rendering behind memoized components. This preserves the current action grouping and copy while preventing selection or parent dashboard updates from re-rendering every dense card body.
Constraint: Do not change ranking, grouping, or product wording in this performance pass.
Rejected: Introduce virtual list dependency | the current list size can benefit from memo boundaries first without new dependencies.
Confidence: high
Scope-risk: narrow
Reversibility: clean
Tested: TypeScript diagnostics for CalendarView and OpportunityOverview
Tested: npm run build
Not-tested: Browser profiler capture with a large production city set.
Users need to know whether a city can be acted on before reading the full explanation. City cards now expose METAR or official-observation freshness, model update timing, market quote freshness, and AI state in a dedicated trust block, while the calendar view groups rows into action-oriented timing buckets with a single reason per city.
Constraint: Keep the existing card and calendar data contracts; derive freshness and action reasons from fields already present in the frontend payload.
Rejected: Add another long explanatory paragraph | it would repeat the same trust problem instead of making the first glance clearer.
Confidence: high
Scope-risk: moderate
Reversibility: clean
Tested: npm run build
Not-tested: Live browser visual QA with stale METAR and delayed quote examples.