# Forecast Derivation Internals This document describes deterministic forecast summarization in `internal/forecast`. ## Purpose `internal/forecast` converts normalized bundle data into daily and period summaries used by briefing builders. ## Inputs And Outputs Inputs: - `forecast.Bundle` - local date or resolved report period - timezone - configured daypart definitions Outputs: - `forecast.DailySummary` for one local civil day - one clipped daily summary per local day or partial day from `BuildPeriodDailySummaries` - daypart summaries with selected hourly periods, ranges, timed maximums, conditions, indicators, and alert overlaps ## Boundaries - This package groups, selects, and summarizes already-normalized forecast data. - It does not perform HTTP calls, parse CLI flags, resolve report definitions, compare prior snapshots, build prompt input packages, or invoke Scriptorium. ## Config Fields Used - `dayparts[].name` - `dayparts[].start` - `dayparts[].end` Threshold constants for basic indicators live in forecast code rather than configuration. ## External Adapters Used None directly. Forecast data arrives through `forecast.Bundle`. ## State Or Manifest Behavior None. Source warnings and provenance from the bundle are carried into summaries for later metadata and briefing output. ## Skip And Resume Behavior None. Missing optional source context can produce empty selections, but missing required hourly data fails summarization. ## Failure Behavior - A nil bundle or missing hourly forecast data returns an error. - Invalid daypart definitions return parse errors with context. - Alert records without parseable RFC3339 timing are skipped. - Empty selected periods produce empty summaries rather than generated prose. ## Tests Inspect: - `internal/forecast/derive_test.go` - `internal/timeutil/periods_test.go` ## Invariants - Go owns report-period selection and meteorological summarization. - Weather facts come from normalized source data. - Outputs remain JSON-inspectable and independent of CLI, state, and adapters.