Reconcile internal implementation guides

This commit is contained in:
2026-08-13 04:25:40 +00:00
parent b985c5faac
commit 88fde0df7f
4 changed files with 103 additions and 143 deletions

View File

@@ -2,74 +2,46 @@
`internal/forecast` deterministically selects and summarizes normalized
forecast data. It has no transport, filesystem, CLI, subprocess, or report
registry dependency. Its summaries are consumed by
[fact contracts](facts.md) and later module builders.
registry dependency. The report-scoped caller is [fact
contracts](facts.md), which owns the choice of data required by each report.
## Period and daypart semantics
## Daily Derivation
Selections use `timeutil.Period` half-open overlap: a value is selected only
when both intervals share time. `BuildDailySummary` creates one local civil
day; `BuildPeriodDailySummaries` intersects every local civil day with the
requested period, preserving partial first and last days.
`BuildDailySummary` builds one summary for one local civil day. The facts
layer calls it for Daily, Today, and Tomorrow reports; it does not provide a
multi-day or arbitrary-period summary constructor. `timeutil.Period` supplies
the shared half-open overlap rule used while selecting source values.
`ResolveDayparts` converts each configured name, start clock, and end clock
into a local window. An end clock at or before its start clock wraps into the
next civil day. The daypart and timezone defaults are defined in the
[configuration reference](../config.md), not here.
`ResolveDayparts` turns configured local clock ranges into windows. A range
whose end is not after its start continues into the next civil day. The
available daypart and timezone settings are defined in the
[configuration reference](../config.md).
## Deterministic summaries
The summary keeps selected hourly and narrative values, the discussion,
source warnings and provenance, alert overlaps, and one summary for each
resolved daypart. Daypart summaries derive their measurements, conditions,
weather indicators, and precipitation timing from normalized forecast
periods. `BuildPrecipTiming` is also available to the facts layer for a
report's selected hourly periods.
`BuildDailySummary` requires an hourly run with at least one period. It adds
the selected narrative periods, discussion, alert overlaps, source provenance,
source warnings, and one `DaypartSummary` per resolved window. A daypart keeps
its selected hourly periods and derives temperature and apparent-temperature
ranges, timed precipitation and wind maxima, dominant and notable conditions,
and weather indicators.
## Boundaries And Failures
Hourly precipitation probabilities must be finite percentages from 0 through
100. Daily-summary construction rejects invalid values before they can affect
timed maxima or precipitation windows.
Daily-summary construction requires a bundle with hourly forecast data,
valid precipitation probabilities, and valid daypart definitions. Optional
normalized products remain absent when unavailable. Invalid alerts are ignored
while valid overlaps are selected for the relevant day or daypart window.
Indicators are deterministic checks over normalized values and condition text:
heat, cold, and wind use package-owned numeric cutoffs; snow, ice, fog, and
wind text are detected from the forecast description. `BuildPrecipTiming`
sorts periods, records the maximum and first precipitation, groups contiguous
periods at or above its package-owned probability threshold, and records
thunder mentions.
Ice detection uses the bounded condition vocabulary `ice`, `icy`, `freezing`,
and `sleet` as whole words.
Thresholds, text classification, unit normalization, and alert selection are
package implementation rules. Report identity, period selection, and the
resulting derived-fact shape are owned by [fact contracts](facts.md); external
source semantics are owned by [weather-data internals](weather-data.md).
Daypart temperature and apparent-temperature ranges are Fahrenheit values, and
timed wind maxima are mph values. When only metric source fields are present,
they are converted to those units before they are stored or evaluated against
indicator thresholds; populated US-customary fields take precedence.
## Verification
Alert overlap parsing supports the normalized alert payload's available timing
fields. Unparseable alerts and invalid intervals are ignored; valid overlaps
are clipped to the requested period and ordered by alert start time.
`DailySummary.AlertOverlaps` is limited to the local civil day, while each
daypart evaluates the full alert run against its complete window, including the
next-day portion of an overnight window.
## Missing data and failures
Empty selections yield empty summary fields rather than generated prose.
Direct daily or period-summary calls fail when their required bundle, valid
period, hourly data, or daypart definitions are invalid. A nil location uses
UTC when these APIs are called directly. Optional narrative, discussion, and
alerts remain absent when their normalized products are absent.
Forecast thresholds used for brief indicators and precipitation timing are
implementation rules.
## Verification and invariants
Focused tests cover local civil days, clipped periods, daypart resolution,
summary metrics, precipitation-window threshold behavior, and alert overlap:
Focused `internal/forecast` tests exercise daily and overnight dayparts,
summary derivation, invalid precipitation data, precipitation timing, and
alert overlap handling. `internal/facts` tests cover the report-scoped caller:
```sh
go test ./internal/forecast ./internal/timeutil
go test ./internal/forecast ./internal/facts
```
The package preserves normalized inputs as inspectable structured values and
never decides report identity, delivery, or presentation wording.