Refresh deterministic domain documentation
This commit is contained in:
@@ -1,75 +1,61 @@
|
|||||||
# Changes Internals
|
# Changes Internals
|
||||||
|
|
||||||
This document describes structured Recent Changes comparison.
|
`internal/changes` deterministically compares a compatible prior module
|
||||||
|
snapshot with the current snapshot. It returns compact structured changes for
|
||||||
|
prompt input; it never reads state, finds a prior report, renders Markdown, or
|
||||||
|
compares generated text. Snapshot construction belongs to
|
||||||
|
[module internals](module.md), and prior-snapshot discovery belongs to
|
||||||
|
[state internals](state.md).
|
||||||
|
|
||||||
## Purpose
|
## Comparison inputs and output
|
||||||
|
|
||||||
`internal/changes` compares current and prior module snapshots and emits
|
Each comparator receives a prior snapshot, a current snapshot, and
|
||||||
compact change records for prompt input data packages.
|
`Thresholds`. A `Change` has a stable type and message plus previous and
|
||||||
|
current values where useful. Changes are sorted by type and then message, so
|
||||||
|
the same inputs always yield the same order.
|
||||||
|
|
||||||
## Inputs And Outputs
|
Threshold values are supplied by application orchestration from the
|
||||||
|
[Recent Changes configuration](../config.md#recent_change); this package does
|
||||||
|
not load configuration or choose defaults. Numeric changes are emitted when
|
||||||
|
the absolute difference meets the configured threshold. Precipitation also
|
||||||
|
requires a change between its low, possible, likely, and high categories.
|
||||||
|
|
||||||
Inputs:
|
## Strategies
|
||||||
|
|
||||||
- prior module snapshot
|
| Comparator | Required snapshot data | Compared values |
|
||||||
- current module snapshot
|
| --- | --- | --- |
|
||||||
- comparison thresholds from configuration
|
| `CompareDaily` | `derived_daily_summary`, `derived_daypart_summaries` | Low and high temperature, daily precipitation probability and timing, peak gust, alerts, and aggregate indicators |
|
||||||
|
| `CompareThreeDay` | `derived_daypart_summaries` | Per-day temperatures, precipitation probability and timing, peak gust, indicators, and added or removed outlook days |
|
||||||
|
| `CompareWeekend` | `derived_daypart_summaries` | The three-day values with weekend-prefixed change types |
|
||||||
|
|
||||||
Outputs:
|
For daily comparison, `alert_digest` and `precip_timing` are optional: alerts
|
||||||
|
are compared when present, and timing is compared only when both snapshots
|
||||||
|
contain it. The multi-day comparators build their day map from daypart
|
||||||
|
summaries. A missing or added day becomes a dedicated change rather than a
|
||||||
|
comparison against invented data.
|
||||||
|
|
||||||
- ordered `changes.Change` items with type, message, previous value, and current
|
The application selects a comparator only after state lookup establishes a
|
||||||
value where useful
|
compatible prior snapshot. Daily, Today, and Tomorrow use the daily comparator;
|
||||||
|
Three-day and Weekend use their named comparators. Other report types, such as
|
||||||
|
Storm, produce no Recent Changes list.
|
||||||
|
|
||||||
## Boundaries
|
## Missing data and failures
|
||||||
|
|
||||||
- This package compares structured module snapshot data only.
|
Required stanzas that are absent or cannot be decoded return an error with the
|
||||||
- It does not read filesystem state, find prior snapshots, render Markdown,
|
snapshot and stanza context. Optional stanzas may be absent. A snapshot with no
|
||||||
invoke Scriptorium, or compare generated report text.
|
eligible predecessor is not a comparison failure: the caller supplies an empty
|
||||||
|
change list without invoking this package.
|
||||||
|
|
||||||
## Config Fields Used
|
The package has no filesystem, transport, CLI, renderer, or persistence
|
||||||
|
behavior. It does not decide report compatibility or retain snapshots.
|
||||||
|
|
||||||
The app maps these fields into comparison thresholds:
|
## Verification and invariants
|
||||||
|
|
||||||
- `recent_change.temperature_degrees`
|
Focused tests cover the daily, three-day, and weekend strategies, threshold
|
||||||
- `recent_change.precip_probability_points`
|
boundaries, indicator and alert changes, and missing required stanzas:
|
||||||
- `recent_change.wind_gust_miles_per_hour`
|
|
||||||
- `recent_change.precip_timing_shift_minutes`
|
|
||||||
|
|
||||||
## External Adapters Used
|
```sh
|
||||||
|
go test ./internal/changes
|
||||||
|
```
|
||||||
|
|
||||||
None.
|
Recent Changes always compare structured snapshot values, never report prose.
|
||||||
|
|
||||||
## State Or Manifest Behavior
|
|
||||||
|
|
||||||
None directly. The app loads prior module snapshots through `internal/state`
|
|
||||||
before calling comparison functions.
|
|
||||||
|
|
||||||
## Skip And Resume Behavior
|
|
||||||
|
|
||||||
No resume behavior. When the app has no prior comparable snapshot, it sends an
|
|
||||||
empty Recent Changes list without calling a comparison function.
|
|
||||||
|
|
||||||
## Failure Behavior
|
|
||||||
|
|
||||||
- Daily comparison requires `derived_daily_summary` and
|
|
||||||
`derived_daypart_summaries` stanzas. It also uses `alert_digest` and
|
|
||||||
`precip_timing` when present.
|
|
||||||
- 3-Day comparison requires `derived_daypart_summaries`.
|
|
||||||
- Weekend comparison requires `derived_daypart_summaries`.
|
|
||||||
- Storm Report comparison returns no changes.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/changes/daily_test.go`
|
|
||||||
- `internal/changes/three_day_test.go`
|
|
||||||
- `internal/changes/weekend_test.go`
|
|
||||||
- `internal/app/app_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- Recent Changes are based on structured snapshots, not Markdown report text.
|
|
||||||
- Report compatibility is determined outside this package by report definitions
|
|
||||||
and state lookup.
|
|
||||||
- Output stays compact enough for prompt input.
|
|
||||||
|
|||||||
@@ -1,94 +1,67 @@
|
|||||||
# Fact Contracts Internals
|
# Fact Contracts Internals
|
||||||
|
|
||||||
This document describes the fact contract boundary.
|
`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).
|
||||||
|
|
||||||
## Purpose
|
## Collected facts
|
||||||
|
|
||||||
`internal/facts` separates normalized upstream facts collected for a report run
|
`BuildCollected` projects a `weatherdata.Bundle` into `CollectedFacts`. It
|
||||||
from conservative report-scoped facts derived from them. The package gives app
|
retains the fetched timestamp and every normalized product: observations,
|
||||||
orchestration one place to build reusable facts before module execution.
|
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.
|
||||||
|
|
||||||
## Inputs And Outputs
|
A nil bundle produces an empty collected value. Collection itself, missing
|
||||||
|
source policy, and source hashes are outside this package.
|
||||||
|
|
||||||
Inputs:
|
## Report-scoped derivation
|
||||||
|
|
||||||
- `weatherdata.Bundle` from the Weather API adapter
|
`BuildDerived` requires a valid resolved period and a valid report timezone. It
|
||||||
- resolved report definition and valid period
|
uses half-open period overlap to select hourly, narrative, daily, and alert
|
||||||
- report timezone
|
data; it also derives precipitation timing. Convective outlooks are retained
|
||||||
- configured daypart definitions
|
only when their valid interval overlaps the report period, with discussions
|
||||||
|
kept for represented outlook days. Both collections are sorted deterministically.
|
||||||
|
|
||||||
Outputs:
|
Report identity controls the summary shape:
|
||||||
|
|
||||||
- `facts.CollectedFacts` with normalized source facts plus separate source
|
| Report family | Derived summary |
|
||||||
provenance and warnings. SPC convective outlook source data is carried
|
| --- | --- |
|
||||||
through when present in the bundle, including upstream geometry and source
|
| Hourly | Rolling-period selections and precipitation timing; no daily or daypart summary |
|
||||||
provenance.
|
| Daily, Today, Tomorrow | One local civil-day summary and its dayparts |
|
||||||
- `facts.DerivedFacts` with valid-period forecast slices, alert overlaps,
|
| Three-day, Weekend | One clipped daily summary for each overlapping local day |
|
||||||
report-period SPC convective outlooks and discussions, daily summaries,
|
| Storm | One summary for the explicit report window |
|
||||||
daypart summaries, and Storm Report window summary
|
|
||||||
|
|
||||||
Hourly Report uses the generic valid-period hourly and narrative selection
|
`DaypartSummaries` is collected from the resulting daily or storm summaries.
|
||||||
for its rolling six-hour window. Its derived facts include precipitation timing
|
The detailed grouping, daypart-window, and alert rules are owned by
|
||||||
from the selected hourly periods, alert overlaps for the six-hour period, and
|
[forecast derivation](forecast-derivation.md).
|
||||||
SPC outlooks/discussions overlapping that period. It does not build daily
|
|
||||||
summaries, daypart summaries, or a storm-window summary.
|
|
||||||
|
|
||||||
## Boundaries
|
## Missing data and failures
|
||||||
|
|
||||||
- This package owns fact assembly and reusable deterministic derivation for a
|
Optional normalized products remain nil or yield empty selections; the package
|
||||||
report run.
|
does not create substitute values. A present convective-outlook run with no
|
||||||
- SPC convective outlook derivation selects already-collected outlooks whose
|
matching outlooks produces non-nil empty outlook and discussion slices, while
|
||||||
half-open valid intervals overlap the resolved report period and retains
|
a missing run produces nil slices.
|
||||||
discussions for represented outlook days.
|
|
||||||
- Derived SPC outlook records preserve the collected outlook fields, including
|
|
||||||
geometry, for downstream components that need source-level facts. Prompt
|
|
||||||
modules decide which fields are exposed to Scriptorium.
|
|
||||||
- It does not fetch upstream data, build prompt wording, compare prior
|
|
||||||
snapshots, write workflow state, invoke Scriptorium, or define modules.
|
|
||||||
|
|
||||||
## Config Fields Used
|
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.
|
||||||
|
|
||||||
- `dayparts[].name`
|
## Verification and invariants
|
||||||
- `dayparts[].start`
|
|
||||||
- `dayparts[].end`
|
|
||||||
- `weather_api.timezone`
|
|
||||||
|
|
||||||
## External Adapters Used
|
Focused tests cover collected-fact separation, report-period selection,
|
||||||
|
hourly and storm behavior, daily and partial-day summaries, and convective
|
||||||
|
outlook selection:
|
||||||
|
|
||||||
None directly. Collected facts are built from `weatherdata.Bundle`.
|
```sh
|
||||||
|
go test ./internal/facts
|
||||||
|
```
|
||||||
|
|
||||||
## State Or Manifest Behavior
|
Facts are derived once for a resolved report from already collected data.
|
||||||
|
They remain reusable structured values: prompt wording, state persistence,
|
||||||
None. Source provenance and warnings remain data fields for downstream metadata
|
prior-report comparison, and template presentation are owned elsewhere.
|
||||||
and inspection.
|
|
||||||
|
|
||||||
## Failure Behavior
|
|
||||||
|
|
||||||
- Invalid or missing report valid periods return an error.
|
|
||||||
- Invalid timezone names return an error.
|
|
||||||
- Missing required hourly forecast data returns the underlying forecast
|
|
||||||
derivation error for reports that require daily summaries.
|
|
||||||
- Hourly Report can derive its default module facts without daily or
|
|
||||||
daypart summaries.
|
|
||||||
- Missing optional narrative, alert, discussion, daily, or weather story data
|
|
||||||
produces empty or nil derived fields.
|
|
||||||
- Missing optional SPC convective outlook data produces a nil collected field.
|
|
||||||
- A present SPC convective outlook source with no report-period matches
|
|
||||||
produces non-nil empty derived outlook and discussion slices.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/facts/facts_test.go`
|
|
||||||
- `internal/app/app_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- Collected facts are built once from a fetched bundle.
|
|
||||||
- Derived facts are scoped to one resolved report.
|
|
||||||
- SPC convective outlook selection uses the resolved report period and the
|
|
||||||
already-collected outlook run.
|
|
||||||
- Source provenance and warnings stay separate from ordinary fact fields.
|
|
||||||
- Prompt-specific wording and one-off presentation decisions stay outside this
|
|
||||||
package.
|
|
||||||
|
|||||||
@@ -1,76 +1,63 @@
|
|||||||
# Forecast Derivation Internals
|
# Forecast Derivation Internals
|
||||||
|
|
||||||
This document describes deterministic forecast summarization in
|
`internal/forecast` deterministically selects and summarizes normalized
|
||||||
`internal/forecast`.
|
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.
|
||||||
|
|
||||||
## Purpose
|
## Period and daypart semantics
|
||||||
|
|
||||||
`internal/forecast` converts normalized weather data into daily and period
|
Selections use `timeutil.Period` half-open overlap: a value is selected only
|
||||||
summaries used by fact builders and module builders.
|
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.
|
||||||
|
|
||||||
## Inputs And Outputs
|
`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.
|
||||||
|
|
||||||
Inputs:
|
## Deterministic summaries
|
||||||
|
|
||||||
- `weatherdata.Bundle`
|
`BuildDailySummary` requires an hourly run with at least one period. It adds
|
||||||
- local date or resolved report period
|
the selected narrative periods, discussion, alert overlaps, source provenance,
|
||||||
- timezone
|
source warnings, and one `DaypartSummary` per resolved window. A daypart keeps
|
||||||
- configured daypart definitions
|
its selected hourly periods and derives temperature and apparent-temperature
|
||||||
|
ranges, timed precipitation and wind maxima, dominant and notable conditions,
|
||||||
|
and weather indicators.
|
||||||
|
|
||||||
Outputs:
|
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.
|
||||||
|
|
||||||
- `forecast.DailySummary` for one local civil day
|
Alert overlap parsing supports the normalized alert payload's available timing
|
||||||
- one clipped daily summary per local day or partial day from
|
fields. Unparseable alerts and invalid intervals are ignored; valid overlaps
|
||||||
`BuildPeriodDailySummaries`
|
are clipped to the requested period and ordered by alert start time.
|
||||||
- daypart summaries with selected hourly periods, ranges, timed maximums,
|
|
||||||
conditions, indicators, and alert overlaps
|
|
||||||
|
|
||||||
## Boundaries
|
## Missing data and failures
|
||||||
|
|
||||||
- This package groups, selects, and summarizes already-normalized forecast
|
Empty selections yield empty summary fields rather than generated prose.
|
||||||
data.
|
Direct daily or period-summary calls fail when their required bundle, valid
|
||||||
- It does not perform HTTP calls, parse CLI flags, resolve report definitions,
|
period, hourly data, or daypart definitions are invalid. A nil location uses
|
||||||
compare prior snapshots, build prompt input packages, or invoke Scriptorium.
|
UTC when these APIs are called directly. Optional narrative, discussion, and
|
||||||
|
alerts remain absent when their normalized products are absent.
|
||||||
|
|
||||||
## Config Fields Used
|
Forecast thresholds used for brief indicators and precipitation timing are
|
||||||
|
implementation rules. User-configurable Recent Changes thresholds are applied
|
||||||
|
by [changes internals](changes.md), whose defaults are documented in
|
||||||
|
[configuration](../config.md).
|
||||||
|
|
||||||
- `dayparts[].name`
|
## Verification and invariants
|
||||||
- `dayparts[].start`
|
|
||||||
- `dayparts[].end`
|
|
||||||
|
|
||||||
Threshold constants for basic indicators live in forecast code rather than
|
Focused tests cover local civil days, clipped periods, daypart resolution,
|
||||||
configuration.
|
summary metrics, precipitation windows, threshold helpers, and alert overlap:
|
||||||
|
|
||||||
## External Adapters Used
|
```sh
|
||||||
|
go test ./internal/forecast ./internal/timeutil
|
||||||
|
```
|
||||||
|
|
||||||
None directly. Forecast data arrives through `weatherdata.Bundle`.
|
The package preserves normalized inputs as inspectable structured values and
|
||||||
|
never decides report identity, delivery, or presentation wording.
|
||||||
## State Or Manifest Behavior
|
|
||||||
|
|
||||||
None. Source warnings and provenance from the bundle are carried into summaries
|
|
||||||
for later metadata and module 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.
|
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ the paths safe to use below the configured workspace.
|
|||||||
| Generated-text source and result | `snapshots/<group>/<date>/generated_text_raw.<run-id>.json` and `generated_text_result.<run-id>.json` |
|
| Generated-text source and result | `snapshots/<group>/<date>/generated_text_raw.<run-id>.json` and `generated_text_result.<run-id>.json` |
|
||||||
| Generated-text render context | `snapshots/<group>/<date>/render_context.<run-id>.json` |
|
| Generated-text render context | `snapshots/<group>/<date>/render_context.<run-id>.json` |
|
||||||
|
|
||||||
Notification records use their own configured date directory, because they
|
The configured notification root separates notification artifacts from report
|
||||||
are not necessarily tied to a report valid period. Report producers create
|
artifacts; single-report notification paths use the report's valid date. Report
|
||||||
parent directories as needed and write the report body; state is responsible
|
producers create parent directories as needed and write the report body; state
|
||||||
for the surrounding paths and saved run artifacts.
|
is responsible for the surrounding paths and saved run artifacts.
|
||||||
|
|
||||||
Batch Distributor notifications are derived separately as
|
Batch Distributor notifications are derived separately as
|
||||||
`notifications/batches/<batch>/<local-date>/distributor.<batch-run-id>.json`.
|
`notifications/batches/<batch>/<local-date>/distributor.<batch-run-id>.json`.
|
||||||
|
|||||||
Reference in New Issue
Block a user