447 lines
24 KiB
Markdown
447 lines
24 KiB
Markdown
# Report Templates
|
|
|
|
## Purpose
|
|
|
|
This guide describes the implemented Markdown report template surface for
|
|
`weatherreporter`. It is for maintainers editing embedded report templates,
|
|
especially generated-text-template reports.
|
|
|
|
Templates are Go `text/template` files. The implemented top-level templates
|
|
are:
|
|
|
|
- `internal/reporttemplate/templates/daily.md.tmpl`
|
|
- `internal/reporttemplate/templates/today.md.tmpl`
|
|
- `internal/reporttemplate/templates/tomorrow.md.tmpl`
|
|
- `internal/reporttemplate/templates/hourly.md.tmpl`
|
|
|
|
Shared named partials live under `internal/reporttemplate/templates/partials/`:
|
|
|
|
- `alert_digest.md.tmpl`, used by Daily, Today, Tomorrow, and Hourly for the
|
|
combined Alerts and Risk Products section
|
|
- `daypart_forecast.md.tmpl`, used by Daily and Tomorrow
|
|
- `today_daypart_forecast.md.tmpl`, used by Today
|
|
- `precipitation_timing.md.tmpl`, used by Daily, Today, Tomorrow, and Hourly
|
|
|
|
Templates are rendered from structured contexts such as `DailyRenderContext`,
|
|
`TodayRenderContext`, `TomorrowRenderContext`, and `HourlyRenderContext`.
|
|
Weather data collection, derivation, module execution, generated text
|
|
validation, and artifact paths are handled before template rendering.
|
|
|
|
## Editing Rules
|
|
|
|
- Use Go `text/template` syntax.
|
|
- Keep templates focused on Markdown layout, headings, ordering, and simple
|
|
conditional display.
|
|
- Do not put weather derivation, source selection, or path construction logic in
|
|
templates.
|
|
- Missing template keys are errors. A misspelled variable will fail rendering.
|
|
- No custom template functions are registered.
|
|
- Named partials are invoked with `{{ template "name" . }}`. Pass the current
|
|
render context (`.`) unless the partial is intentionally designed for a
|
|
narrower value.
|
|
- Optional module stanzas are pointers and should be guarded with
|
|
`{{ with .Modules.WeatherStory }}...{{ end }}`.
|
|
- Slices can be rendered with `{{ range .Items }}...{{ else }}...{{ end }}`.
|
|
|
|
## Hourly Context
|
|
|
|
The hourly template receives five top-level values:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Report` | HourlyReportContext | Display metadata and friendly labels for the rendered report. |
|
|
| `.GeneratedText` | Hourly | Structured text returned by Scriptorium. |
|
|
| `.Modules` | HourlyTemplateModules | Preferred deterministic template surface, keyed by module purpose. |
|
|
| `.Collected` | facts.CollectedFacts | Normalized upstream facts for advanced template use. |
|
|
| `.Derived` | facts.DerivedFacts | Shared derived facts for advanced template use. |
|
|
|
|
Prefer `.Modules` for normal template edits. `.Collected` and `.Derived` are
|
|
available when a template needs lower-level facts, but templates should still
|
|
avoid nontrivial derivation.
|
|
|
|
## Report
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Report.Title` | string | Display title. Currently `Hourly Report`. |
|
|
| `.Report.LocationName` | string | Prompt/report location label, such as `Brentwood, MO`. |
|
|
| `.Report.GeneratedAt` | time.Time | Canonical generation timestamp. |
|
|
| `.Report.GeneratedAtLabel` | string | Friendly local generation time label. |
|
|
| `.Report.ValidPeriod` | timeutil.Period | Canonical valid period. |
|
|
| `.Report.ValidPeriodLabel` | string | Friendly local valid period label, such as `2026-05-29 at 8:30 AM to 2026-05-29 at 2:30 PM`. |
|
|
| `.Report.Timezone` | string | Effective report timezone. |
|
|
|
|
## GeneratedText
|
|
|
|
These fields are written by Scriptorium as structured JSON, validated by
|
|
weatherreporter, and then inserted into the render context.
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.GeneratedText.Summary` | string | Required short prose summary. |
|
|
| `.GeneratedText.ForecastDiscussion` | string | Required prose for the Forecast Discussion section. |
|
|
| `.GeneratedText.PrecipitationTiming` | string | Optional prose rendered after deterministic precipitation windows. |
|
|
| `.GeneratedText.Confidence` | string | Optional confidence or uncertainty note. Empty when omitted by the LLM; not rendered by the current hourly template. |
|
|
|
|
Example:
|
|
|
|
```gotemplate
|
|
{{ .GeneratedText.Summary }}
|
|
|
|
## Forecast Discussion
|
|
|
|
{{ .GeneratedText.ForecastDiscussion }}
|
|
```
|
|
|
|
## Tomorrow Context
|
|
|
|
The Tomorrow template receives five top-level values:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Report` | TomorrowReportContext | Display metadata and friendly labels for the rendered report. |
|
|
| `.GeneratedText` | Tomorrow | Structured text returned by Scriptorium. |
|
|
| `.Modules` | TomorrowTemplateModules | Preferred deterministic template surface, keyed by module purpose. |
|
|
| `.Collected` | facts.CollectedFacts | Normalized upstream facts for advanced template use. |
|
|
| `.Derived` | facts.DerivedFacts | Shared derived facts for advanced template use. |
|
|
|
|
Tomorrow report metadata includes `.Report.Title`, `.Report.ForecastDate`,
|
|
`.Report.ForecastDateLabel`, `.Report.ForecastDayName`,
|
|
`.Report.GeneratedAt`, `.Report.GeneratedAtLabel`, `.Report.ValidPeriod`, and
|
|
`.Report.Timezone`.
|
|
|
|
Tomorrow generated text uses the same `.GeneratedText.Summary`,
|
|
`.GeneratedText.PrecipitationTiming`, and `.GeneratedText.Confidence` fields as
|
|
Hourly. `.GeneratedText.ForecastDiscussion` is a slice of paragraphs and should
|
|
be rendered with `range`.
|
|
|
|
Tomorrow uses the shared `alert_digest`, `daypart_forecast`, and
|
|
`precipitation_timing` partials.
|
|
|
|
Tomorrow modules include the Hourly module fields plus:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.DerivedDailySummary` | *briefing.DerivedDailySummaryModule | Daily summary facts for the forecast date. |
|
|
| `.Modules.DerivedDaypartSummaries` | *map[string]briefing.DerivedDaypartSummaryModule | Raw daypart summary map, when direct keyed access is needed. |
|
|
| `.Modules.Dayparts` | []generatedtext.TomorrowDaypartContext | Ordered daypart summaries for deterministic template rendering. |
|
|
| `.Modules.TomorrowPlanning` | *briefing.TomorrowPlanningModule | Planning facts for the next local civil day. |
|
|
|
|
Prefer `.Modules.Dayparts` over ranging through
|
|
`.Modules.DerivedDaypartSummaries`; it follows configured daypart order and
|
|
falls back to sorted keys for any unmatched entries.
|
|
|
|
## Daily Context
|
|
|
|
The Daily template receives the same five top-level values as Tomorrow, using
|
|
`DailyReportContext`, `Daily`, and `DailyTemplateModules`.
|
|
|
|
Daily report metadata includes `.Report.Title`, `.Report.ForecastDate`,
|
|
`.Report.ForecastDateLabel`, `.Report.ForecastDayName`,
|
|
`.Report.GeneratedAt`, `.Report.GeneratedAtLabel`, `.Report.ValidPeriod`, and
|
|
`.Report.Timezone`.
|
|
|
|
Daily generated text uses `.GeneratedText.Summary`,
|
|
`.GeneratedText.ForecastDiscussion`, `.GeneratedText.PrecipitationTiming`, and
|
|
`.GeneratedText.Confidence`. Forecast discussion is a slice of paragraphs and
|
|
should be rendered with `range`.
|
|
|
|
Daily uses the shared `alert_digest`, `daypart_forecast`, and
|
|
`precipitation_timing` partials.
|
|
|
|
Daily uses template ID `daily`, generated-text schema ID `daily`, and prompt
|
|
source `internal/reporttemplate/prompts/daily.generated_text.md`.
|
|
|
|
Daily modules include the Hourly module fields plus:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.DerivedDailySummary` | *briefing.DerivedDailySummaryModule | Daily summary facts for the forecast date. |
|
|
| `.Modules.DerivedDaypartSummaries` | *map[string]briefing.DerivedDaypartSummaryModule | Raw daypart summary map, when direct keyed access is needed. |
|
|
| `.Modules.Dayparts` | []generatedtext.DailyDaypartContext | Ordered daypart summaries for deterministic template rendering. |
|
|
| `.Modules.DailyPlanning` | *briefing.DailyPlanningModule | Planning facts for the selected local civil day. |
|
|
|
|
Prefer `.Modules.Dayparts` over ranging through
|
|
`.Modules.DerivedDaypartSummaries`; it follows configured daypart order and
|
|
falls back to sorted keys for any unmatched entries.
|
|
|
|
## Today Context
|
|
|
|
The Today template receives the same five top-level values as Tomorrow, using
|
|
`TodayReportContext`, `Today`, and `TodayTemplateModules`.
|
|
|
|
Today report metadata includes `.Report.Title`, `.Report.ForecastDate`,
|
|
`.Report.ForecastDateLabel`, `.Report.ForecastDayName`,
|
|
`.Report.GeneratedAt`, `.Report.GeneratedAtLabel`, `.Report.ValidPeriod`, and
|
|
`.Report.Timezone`.
|
|
|
|
Today generated text uses `.GeneratedText.Summary`,
|
|
`.GeneratedText.ForecastDiscussion`, `.GeneratedText.PrecipitationTiming`, and
|
|
`.GeneratedText.Confidence`. Forecast discussion is a slice of paragraphs and
|
|
should be rendered with `range`.
|
|
|
|
Today uses the `today_daypart_forecast` partial so elapsed or missing dayparts
|
|
can be omitted while Daily and Tomorrow keep their fallback row. It also uses
|
|
the shared `alert_digest` and `precipitation_timing` partials.
|
|
|
|
Today uses template ID `today`, generated-text schema ID `today`, and prompt
|
|
source `internal/reporttemplate/prompts/today.generated_text.md`.
|
|
|
|
Today modules include the Hourly module fields plus:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.DerivedDailySummary` | *briefing.DerivedDailySummaryModule | Daily summary facts for the forecast date. |
|
|
| `.Modules.DerivedDaypartSummaries` | *map[string]briefing.DerivedDaypartSummaryModule | Raw daypart summary map, when direct keyed access is needed. |
|
|
| `.Modules.Dayparts` | []generatedtext.TodayDaypartContext | Ordered daypart summaries for deterministic template rendering. |
|
|
| `.Modules.TodayPlanning` | *briefing.TodayPlanningModule | Planning facts for the current local civil day. |
|
|
|
|
Prefer `.Modules.Dayparts` over ranging through
|
|
`.Modules.DerivedDaypartSummaries`; it follows configured daypart order and
|
|
falls back to sorted keys for any unmatched entries.
|
|
|
|
## Modules
|
|
|
|
`.Modules` exposes typed outputs from the same module pipeline used for the
|
|
prompt data package. Module fields are pointers because missing-data policy may
|
|
omit a stanza.
|
|
|
|
Templates render from rich module values, not from the curated YAML data
|
|
package. Some fields documented below are deterministic wording helpers for
|
|
Markdown templates and are intentionally omitted from data packages passed to
|
|
Scriptorium. The data package is a prompt input, while the render context is the
|
|
template surface.
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.Metadata` | *briefing.MetadataModule | Report metadata module output, when present. |
|
|
| `.Modules.CurrentConditions` | *briefing.CurrentConditionsModule | Current conditions from `/conditions/current`. |
|
|
| `.Modules.HourlyForecast` | *briefing.HourlyForecastModule | Hourly forecast periods overlapping the report valid period. |
|
|
| `.Modules.PrecipTiming` | *briefing.PrecipTimingModule | Derived precipitation timing facts and threshold windows. |
|
|
| `.Modules.AlertDigest` | *briefing.AlertDigestModule | Active alert status and relevant alert overlaps. |
|
|
| `.Modules.SPCConvectiveOutlooks` | *briefing.SPCConvectiveOutlooksModule | SPC outlooks that overlap the report valid period. |
|
|
| `.Modules.AreaForecastDiscussion` | *briefing.AreaForecastDiscussionModule | AFD key messages and configured discussion sections. |
|
|
| `.Modules.SPCConvectiveDiscussion` | *briefing.SPCConvectiveDiscussionModule | SPC discussions retained for qualifying overlapping categorical risk days. |
|
|
| `.Modules.WeatherStory` | *briefing.WeatherStoryModule | Latest NWS weather story, when available. |
|
|
|
|
### Current Conditions
|
|
|
|
Common fields:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.CurrentConditions.ConditionText` | string | Current condition text. |
|
|
| `.Modules.CurrentConditions.ConditionTextLower` | string | Lower-case current condition text for inline sentences. |
|
|
| `.Modules.CurrentConditions.TemperatureF` | *int | Rounded current temperature. |
|
|
| `.Modules.CurrentConditions.ApparentTemperatureF` | *int | Rounded apparent temperature. |
|
|
| `.Modules.CurrentConditions.RelativeHumidityPercent` | *int | Rounded relative humidity. |
|
|
| `.Modules.CurrentConditions.WindDirection` | string | 16-point compass wind direction. |
|
|
| `.Modules.CurrentConditions.WindDirectionText` | string | Lower-case full wind direction text, such as `northwest`. |
|
|
| `.Modules.CurrentConditions.WindSpeedMph` | *int | Rounded wind speed. |
|
|
|
|
Example:
|
|
|
|
```gotemplate
|
|
{{ with .Modules.CurrentConditions }}
|
|
{{ .ConditionText }}{{ with .TemperatureF }}; {{ . }} F{{ end }}{{ with .WindDirection }}; wind {{ . }}{{ end }}{{ with .WindSpeedMph }} {{ . }} mph{{ end }}
|
|
{{ else }}
|
|
No current conditions available.
|
|
{{ end }}
|
|
```
|
|
|
|
### Hourly Forecast
|
|
|
|
Common period fields:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.HourlyForecast.Periods` | []briefing.HourlyForecastPeriod | Ordered periods for the hourly report valid period. |
|
|
| `.Modules.HourlyForecast.Periods[].HourLabel` | string | Friendly hour label such as `4:00 PM`. |
|
|
| `.Modules.HourlyForecast.Periods[].PeriodBegins` | string | Friendly local period start label. |
|
|
| `.Modules.HourlyForecast.Periods[].PeriodEnds` | string | Friendly local period end label. |
|
|
| `.Modules.HourlyForecast.Periods[].Name` | string | Source period name. |
|
|
| `.Modules.HourlyForecast.Periods[].TextDescription` | string | Hourly forecast text. |
|
|
| `.Modules.HourlyForecast.Periods[].TextDescriptionLower` | string | Lower-case hourly forecast text for inline sentences. |
|
|
| `.Modules.HourlyForecast.Periods[].TemperatureF` | *float64 | Forecast temperature. |
|
|
| `.Modules.HourlyForecast.Periods[].ProbabilityOfPrecipitationPercent` | *float64 | Forecast precipitation probability. |
|
|
| `.Modules.HourlyForecast.Periods[].MentionPrecipitation` | bool | True when precipitation probability meets the hourly mention threshold. |
|
|
| `.Modules.HourlyForecast.Periods[].WindDirection` | string | 16-point compass wind direction. |
|
|
| `.Modules.HourlyForecast.Periods[].WindSpeedMph` | *float64 | Wind speed. |
|
|
| `.Modules.HourlyForecast.Periods[].WindGustMph` | *float64 | Wind gust. |
|
|
|
|
Example:
|
|
|
|
```gotemplate
|
|
{{ with .Modules.HourlyForecast }}{{ range .Periods }}
|
|
- **{{ .HourLabel }}:**{{ with .TemperatureF }} {{ . }}°F{{ end }} and {{ .TextDescriptionLower }}.{{ if .MentionPrecipitation }}{{ with .ProbabilityOfPrecipitationPercent }} Probability of precipitation is {{ . }}%.{{ end }}{{ end }}
|
|
{{ else }}
|
|
- No hourly forecast rows available.
|
|
{{ end }}{{ end }}
|
|
```
|
|
|
|
### Precipitation Timing
|
|
|
|
Common fields:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.PrecipTiming.MaxPopPercent` | *int | Highest hourly precipitation probability in the valid period. |
|
|
| `.Modules.PrecipTiming.MaxPopTime` | string | Friendly local time for the highest hourly precipitation probability. |
|
|
| `.Modules.PrecipTiming.ProbabilityThreshold` | float64 | Threshold used to define precipitation windows. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows` | []briefing.PrecipitationWindowModule | One or more threshold precipitation windows. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].PeriodBegins` | string | Friendly local window start. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].PeriodBeginsHourLabel` | string | Friendly window start hour, such as `4:00 PM`. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].PeriodEnds` | string | Friendly local window end; omitted for open windows. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].PeriodEndsHourLabel` | string | Friendly window end hour; omitted for open windows. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].MaxPopPercent` | *int | Highest precipitation probability inside the window. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].MaxPopTime` | string | Friendly local time for the window maximum. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].MaxPopHourLabel` | string | Friendly hour label for the window maximum. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].PrecipitationType` | string | Conservatively inferred precipitation type, such as `showers and thunderstorms`. |
|
|
| `.Modules.PrecipTiming.PrecipitationWindows[].ExpectationPhrase` | string | Probability-based sentence used by precipitation timing templates. |
|
|
| `.Modules.PrecipTiming.ThunderMentioned` | bool | Whether thunder is mentioned in the forecast text. |
|
|
|
|
### Daypart Summaries
|
|
|
|
Daily, Today, and Tomorrow templates should use `.Modules.Dayparts` for
|
|
ordered daypart rendering. Each item has `Key` and `Summary`; `Summary` is a
|
|
rich `briefing.DerivedDaypartSummaryModule`.
|
|
|
|
The shared daypart partials render from these same `.Modules.Dayparts` values.
|
|
Edit `daypart_forecast.md.tmpl` for common Daily/Tomorrow wording, and edit
|
|
`today_daypart_forecast.md.tmpl` for Today-specific omission behavior.
|
|
|
|
Common rich daypart fields:
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.Dayparts[].Summary.DisplayName` | string | Human-readable daypart label. |
|
|
| `.Modules.Dayparts[].Summary.PeriodBegins` | string | Friendly local daypart start. |
|
|
| `.Modules.Dayparts[].Summary.PeriodEnds` | string | Friendly local daypart end. |
|
|
| `.Modules.Dayparts[].Summary.TempRangeF` | string | Rounded temperature range or single temperature. |
|
|
| `.Modules.Dayparts[].Summary.TemperaturePhraseF` | string | Temperature phrase used for steady template wording. |
|
|
| `.Modules.Dayparts[].Summary.TemperatureTrend` | string | Trend category such as `rising`, `falling`, `peaking`, or `steady`. |
|
|
| `.Modules.Dayparts[].Summary.TemperatureStartPhraseF` | string | Starting temperature phrase for rising/falling wording. |
|
|
| `.Modules.Dayparts[].Summary.TemperatureEndPhraseF` | string | Ending temperature phrase for rising/falling wording. |
|
|
| `.Modules.Dayparts[].Summary.TemperaturePeakPhraseF` | string | Peak temperature phrase for peaking wording. |
|
|
| `.Modules.Dayparts[].Summary.TemperatureSteadyPhraseF` | string | Steady temperature phrase. |
|
|
| `.Modules.Dayparts[].Summary.MaxPopPercent` | *int | Highest precipitation probability in the daypart. |
|
|
| `.Modules.Dayparts[].Summary.MaxPopTime` | string | Friendly local time for the highest precipitation probability. |
|
|
| `.Modules.Dayparts[].Summary.MaxPopTimeLabel` | string | Clock-style label for deterministic precipitation timing text. |
|
|
| `.Modules.Dayparts[].Summary.MentionPrecipitation` | bool | True when precipitation probability should be mentioned by the template. |
|
|
| `.Modules.Dayparts[].Summary.DominantCondition` | string | Dominant condition text. |
|
|
| `.Modules.Dayparts[].Summary.DominantConditionLower` | string | Lower-case condition text for inline sentences. |
|
|
| `.Modules.Dayparts[].Summary.DominantConditionDisplay` | string | Display-case condition text for bullet starts. |
|
|
| `.Modules.Dayparts[].Summary.NotableConditions` | []string | Notable condition labels retained for the daypart. |
|
|
|
|
Template-only daypart helpers such as `TemperaturePhraseF`,
|
|
`DominantConditionLower`, `DominantConditionDisplay`, and `MaxPopTimeLabel`
|
|
remain available here even though they are not serialized into data-package
|
|
YAML.
|
|
|
|
### Alert Digest
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.AlertDigest.Checked` | bool | Whether alert data was checked successfully. |
|
|
| `.Modules.AlertDigest.ActiveCount` | int | Active alert count from the source. |
|
|
| `.Modules.AlertDigest.RelevantCount` | int | Alert count overlapping the report period. |
|
|
| `.Modules.AlertDigest.Missing` | bool | True when alert data is unavailable. |
|
|
| `.Modules.AlertDigest.Relevant` | []briefing.AlertSummary | Relevant alert summaries. |
|
|
| `.Modules.AlertDigest.Relevant[].Event` | string | Alert event name. |
|
|
| `.Modules.AlertDigest.Relevant[].Headline` | string | Alert headline. |
|
|
| `.Modules.AlertDigest.Relevant[].Severity` | string | Alert severity. |
|
|
| `.Modules.AlertDigest.Relevant[].PeriodBegins` | string | Friendly local alert applicability start. |
|
|
| `.Modules.AlertDigest.Relevant[].PeriodEnds` | string | Friendly local alert applicability end. |
|
|
| `.Modules.AlertDigest.Relevant[].Instruction` | string | Alert instruction text, when provided. |
|
|
| `.Modules.AlertDigest.Relevant[].Description` | string | Alert description text, when provided. |
|
|
|
|
### SPC Outlooks And Discussion
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.SPCConvectiveOutlooks.Checked` | bool | Whether SPC outlook data was checked successfully. |
|
|
| `.Modules.SPCConvectiveOutlooks.AsOf` | string | Friendly source as-of time. |
|
|
| `.Modules.SPCConvectiveOutlooks.IssuedAt` | string | Friendly source issue time. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks` | []briefing.SPCConvectiveOutlookRecord | Overlapping outlook records. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].Day` | int | SPC day number. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].OutlookType` | string | Outlook type, such as `categorical`. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].Label` | string | Short outlook label. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].LabelText` | string | Human-readable outlook label. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].BackgroundDefinition` | *briefing.SPCOutlookBackgroundDefinition | Embedded background context for known SPC outlook products. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].BackgroundDefinition.PlainLanguage` | string | Plain-language outlook definition. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].BackgroundDefinition.OfficialDescription` | string | Official or source-aligned outlook definition. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].BackgroundDefinition.RelativeLevel` | string | Relative categorical risk level, when defined. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].PeriodBegins` | string | Friendly outlook period start. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].PeriodEnds` | string | Friendly outlook period end. |
|
|
| `.Modules.SPCConvectiveOutlooks.Outlooks[].ImageURL` | string | Source image URL. |
|
|
| `.Modules.SPCConvectiveOutlooks.RiskDigest` | []briefing.SPCConvectiveOutlookDigest | Curated categorical outlooks for the shared Alerts and Risk Products section. |
|
|
| `.Modules.SPCConvectiveOutlooks.RiskDigest[].LabelText` | string | Human-readable outlook label. |
|
|
| `.Modules.SPCConvectiveOutlooks.RiskDigest[].RiskLabel` | string | Sentence-style risk label for report rendering. |
|
|
| `.Modules.SPCConvectiveOutlooks.RiskDigest[].PeriodBegins` | string | Friendly outlook period start. |
|
|
| `.Modules.SPCConvectiveOutlooks.RiskDigest[].PeriodEnds` | string | Friendly outlook period end. |
|
|
| `.Modules.SPCConvectiveDiscussion.IncludedBecause` | string | Criterion used to include discussions. |
|
|
| `.Modules.SPCConvectiveDiscussion.Discussions` | []briefing.SPCConvectiveDiscussionRecord | Retained discussion records. |
|
|
| `.Modules.SPCConvectiveDiscussion.Discussions[].Headline` | string | Discussion headline. |
|
|
| `.Modules.SPCConvectiveDiscussion.Discussions[].Summary` | string | Discussion summary. |
|
|
| `.Modules.SPCConvectiveDiscussion.Discussions[].Discussion` | string | Full discussion text. |
|
|
|
|
### Area Forecast Discussion
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.AreaForecastDiscussion.Product` | string | Source product identifier. |
|
|
| `.Modules.AreaForecastDiscussion.KeyMessages` | []string | AFD key messages. |
|
|
| `.Modules.AreaForecastDiscussion.ShortTerm` | string | AFD short-term section text. |
|
|
| `.Modules.AreaForecastDiscussion.LongTerm` | string | AFD long-term section text. |
|
|
|
|
### Weather Story
|
|
|
|
| Variable | Type | Description |
|
|
| --- | --- | --- |
|
|
| `.Modules.WeatherStory.Available` | bool | True when a story is available. |
|
|
| `.Modules.WeatherStory.OfficeID` | string | Source office ID. |
|
|
| `.Modules.WeatherStory.PeriodBegins` | string | Friendly story period start. |
|
|
| `.Modules.WeatherStory.PeriodEnds` | string | Friendly story period end. |
|
|
| `.Modules.WeatherStory.UpdatedAt` | *time.Time | Canonical update timestamp. |
|
|
| `.Modules.WeatherStory.Title` | string | Story title. |
|
|
| `.Modules.WeatherStory.Description` | string | Story description. |
|
|
| `.Modules.WeatherStory.AltText` | string | Story image alt text. |
|
|
| `.Modules.WeatherStory.Priority` | bool | Source priority flag. |
|
|
| `.Modules.WeatherStory.Order` | int | Source order. |
|
|
| `.Modules.WeatherStory.DownloadURL` | string | Source download URL. |
|
|
|
|
## Collected And Derived Facts
|
|
|
|
The template also receives the full `facts.CollectedFacts` and
|
|
`facts.DerivedFacts` structs:
|
|
|
|
- `.Collected` contains normalized source data and provenance from upstream
|
|
Weather API fetches.
|
|
- `.Derived` contains shared slices and calculations used across modules, such
|
|
as valid-period hourly periods, precipitation timing, alert overlaps, and SPC
|
|
filtering inputs.
|
|
|
|
These values are intentionally lower-level than `.Modules`. Use them when a
|
|
template needs a specific field that is not exposed by a module, but keep
|
|
calculation-heavy changes in Go.
|
|
|
|
## Validation
|
|
|
|
After editing a template, run:
|
|
|
|
```bash
|
|
go test ./internal/reporttemplate ./internal/generatedtext ./internal/app
|
|
```
|
|
|
|
For a full check, run:
|
|
|
|
```bash
|
|
go test ./...
|
|
go run ./cmd/weatherreporter --help
|
|
git diff --check
|
|
```
|
|
|
|
Template render tests exercise the Daily, Today, Tomorrow, and Hourly
|
|
templates through `internal/generatedtext/render_context_test.go` and
|
|
`internal/reporttemplate/reporttemplate_test.go`.
|