72 lines
3.3 KiB
Markdown
72 lines
3.3 KiB
Markdown
# 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](weather-data.md); report identity and valid-period
|
|
selection belong to [report registry internals](report-registry.md).
|
|
|
|
## 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](forecast-derivation.md).
|
|
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:
|
|
|
|
```sh
|
|
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.
|