Files
weatherreporter/docs/internal/facts.md

3.3 KiB

Fact Contracts Internals

internal/facts is the deterministic boundary between a collected weather bundle and report-scoped facts. It preserves normalized source values and then selects and summarizes the values needed for one resolved report. Provider transport and normalized bundle semantics belong to weather-data internals; report identity and valid-period selection belong to report registry internals.

Collected facts

BuildCollected projects a weatherdata.Bundle into CollectedFacts. It retains the fetched timestamp and every normalized product: observations, current conditions, hourly, narrative, alerts, discussion, daily, weather story, and convective outlook data. Source provenance and warnings are copied into their own slices so downstream consumers can inspect data completeness without treating it as an ordinary weather fact.

Alert facts retain individual alert payloads for period selection together with their copied source provenance; they do not retain a provider response envelope.

A nil bundle produces an empty collected value. Collection itself, missing source policy, and source hashes are outside this package.

Report-scoped derivation

BuildDerived requires a valid resolved period and a valid report timezone. It uses half-open period overlap to select hourly, narrative, daily, and alert data; it also derives precipitation timing. Convective outlooks are retained only when their valid interval overlaps the report period, with discussions kept for represented outlook days. Both collections are sorted deterministically. It rejects collected hourly data with a precipitation probability outside the finite 0 through 100 percentage domain before constructing derived facts.

Report identity controls the summary shape:

Report family Derived summary
Hourly Rolling-period selections and precipitation timing; no daily or daypart summary
Daily, Today, Tomorrow One local civil-day summary and its dayparts

DaypartSummaries is collected from the resulting daily summaries. The detailed grouping, daypart-window, and alert rules are owned by forecast derivation. Daily alert overlaps remain scoped to the civil day, while overnight daypart summaries retain alerts that overlap their complete next-day window.

Missing data and failures

Optional normalized products remain nil or yield empty selections; the package does not create substitute values. A present convective-outlook run with no matching outlooks produces non-nil empty outlook and discussion slices, while a missing run produces nil slices.

Derivation fails for an invalid report period, invalid timezone, unsupported report ID, or when a requested daily summary has no hourly forecast data. Invalid daypart definitions surface from forecast derivation. The package does not access the CLI, filesystem, subprocesses, or network.

Verification and invariants

Focused tests cover collected-fact separation, report-period selection, hourly behavior, daily summaries, and convective outlook selection:

go test ./internal/facts

Facts are derived once for a resolved report from already collected data. They remain reusable structured values for prompt input and template presentation, which are owned elsewhere.