Files
weatherreporter/docs/templates.md

8.5 KiB

Report Templates

This guide is for maintainers editing Weatherreporter's embedded Markdown templates. Templates format already validated report inputs; they do not select sources, derive weather facts, or validate generated prose. For those details, see Generated Text internals and Report Template internals.

Template Assets

Only the generated-text reports use repository-native Markdown templates. Each report has one matching template ID, generated-text schema ID, and prompt source:

Report Template Schema Prompt ID and source
Daily templates/daily.md.tmpl (daily) daily weather.daily_generated_text; internal/promptassets/assets/prompts/daily/
Today templates/today.md.tmpl (today) today weather.today_generated_text; internal/promptassets/assets/prompts/today/
Tomorrow templates/tomorrow.md.tmpl (tomorrow) tomorrow weather.tomorrow_generated_text; internal/promptassets/assets/prompts/tomorrow/
Hourly templates/hourly.md.tmpl (hourly) hourly weather.hourly_generated_text; internal/promptassets/assets/prompts/hourly/

The matching schemas and Promptkit definitions are embedded by internal/promptassets. The generated-text catalog pairs each schema ID with its template ID; keep the matching prompt definition aligned with that pair.

Shared partials are under internal/reporttemplate/templates/partials/:

Partial Used by
alert_digest.md.tmpl Daily, Today, Tomorrow, and Hourly
precipitation_timing.md.tmpl Daily, Today, Tomorrow, and Hourly
daypart_forecast.md.tmpl Daily and Tomorrow
today_daypart_forecast.md.tmpl Today

All shared partials are parsed whenever any top-level template is rendered. A syntax error in a partial can therefore prevent every generated-text report from rendering.

Editing Rules

  • Use Go text/template syntax and keep changes to Markdown structure, ordering, and display conditions.
  • Templates use missingkey=error; reference only documented fields and guard optional module pointers with with or if.
  • Prefer .Modules for deterministic display values. Do not add weather calculations, source selection, or prompt-input shaping to a template.
  • Keep generated prose in .GeneratedText; do not restate deterministic facts in generated prose merely to compensate for a template change.
  • When changing the generated-prose contract, update the matching prompt, schema, validator, render context, and template together. The validation and catalog rules are owned by Generated Text internals.
  • Use .Modules.Dayparts for ordered daypart output. Do not range over .Modules.DerivedDaypartSummaries, which is a map.

Minimal optional-value pattern:

{{ with .Modules.CurrentConditions }}
Currently, it is {{ with .TemperatureF }}{{ . }}°F{{ end }}.
{{ else }}
Current conditions are unavailable.
{{ end }}

Minimal list pattern:

{{ range .GeneratedText.ForecastDiscussion }}
{{ . }}
{{ end }}

Registered Functions

Templates have these helpers in addition to Go template built-ins:

Function Accepts Returns true when
hasRelevantAlerts an alert-digest value or pointer its Relevant slice is nonempty
hasEnhancedOrHigherSPCRisk an SPC outlook value or pointer its RiskDigest contains an Enhanced, Moderate, or High Risk entry
isEnhancedOrHigherSPCRisk one SPC risk-digest entry its LabelText, or fallback RiskLabel, is Enhanced, Moderate, or High Risk

For example, the alert partial uses the first two functions to decide whether to render the section:

{{ if hasRelevantAlerts .Modules.AlertDigest }}
## Alert Digest
{{ end }}

Render Context

Every rendered template receives one typed context with these five top-level fields:

Field Purpose
.Report Display labels and canonical report timing metadata.
.GeneratedText Validated prose supplied by Promptkit.
.Modules Deterministic, typed values prepared for Markdown rendering.
.Collected Normalized upstream facts for advanced use.
.Derived Shared calculated facts for advanced use.

.Collected and .Derived are available for an exceptional display need, but they are lower-level contracts. Keep reusable weather derivation in Go and use the module surface for normal template work.

Report Metadata

All contexts provide .Report.Title, .Report.GeneratedAt, .Report.GeneratedAtLabel, .Report.ValidPeriod, and .Report.Timezone.

Hourly additionally provides .Report.LocationName and .Report.ValidPeriodLabel.

Daily, Today, and Tomorrow additionally provide .Report.ForecastDate, .Report.ForecastDateLabel, and .Report.ForecastDayName. Their valid-period field remains canonical timing data; use the supplied display labels instead of formatting timestamps in a template.

Validated GeneratedText Prose

GeneratedText is prose returned by Promptkit and validated before rendering. It is not a source for deterministic weather facts.

Field Hourly type Daily, Today, and Tomorrow type Notes
.GeneratedText.Summary string string Required.
.GeneratedText.ForecastDiscussion string []string Required; range over the day-style paragraph slice.
.GeneratedText.PrecipitationTiming string string Required field; an empty string represents no supported prose. The precipitation partial uses nonempty prose only when deterministic windows exist.

The JSON schema rejects unknown properties and defines the required fields, but the schema body and validation behavior are documented in Generated Text internals.

Deterministic Module Values

Module values are deterministic outputs built from collected and derived facts. Module pointers can be nil when their source or policy permits omission.

Module field Available in
.Modules.Metadata, .Modules.CurrentConditions, .Modules.HourlyForecast, .Modules.PrecipTiming, .Modules.AlertDigest, .Modules.SPCConvectiveOutlooks, .Modules.AreaForecastDiscussion, .Modules.SPCConvectiveDiscussion, .Modules.WeatherStory All four contexts
.Modules.DerivedDailySummary, .Modules.DerivedDaypartSummaries, .Modules.Dayparts Daily, Today, Tomorrow
.Modules.OutdoorWindows, .Modules.DailyPlanning Daily
.Modules.TodayPlanning Today
.Modules.TomorrowPlanning Tomorrow

The repository templates currently use the following nested display values. They are the preferred surface for comparable edits:

Area Values
Current conditions .TemperatureF, .ConditionText, .ConditionTextLower, .ApparentTemperatureF, .RelativeHumidityPercent, .WindDirectionText, .WindSpeedMph
Hourly periods .Periods, .HourLabel, .Name, .TemperatureF, .TextDescription, .TextDescriptionLower, .MentionPrecipitation, .ProbabilityOfPrecipitationPercent
Dayparts .Dayparts[].Key and .Dayparts[].Summary fields DisplayName, DominantCondition, DominantConditionDisplay, TemperatureTrend, TemperatureStartPhraseF, TemperatureEndPhraseF, TemperaturePeakPhraseF, TemperatureSteadyPhraseF, TemperaturePhraseF, MentionPrecipitation, and MaxPopPercent
Precipitation timing .PrecipitationWindows, plus each window's PeriodBegins, PeriodBeginsHourLabel, PeriodEnds, PeriodEndsHourLabel, ExpectationPhrase, MaxPopPercent, MaxPopTime, and MaxPopHourLabel
Alert digest .AlertDigest.Relevant entries' Event, Headline, PeriodBegins, and PeriodEnds
SPC risk digest .SPCConvectiveOutlooks.RiskDigest entries' LabelText, RiskLabel, PeriodBegins, and PeriodEnds

Other fields on these typed modules remain available when a template has a well-defined display need. Their module contracts and weather derivation belong to Module contract internals, Module builder internals, and Forecast derivation internals.

Validate Changes

Run the focused checks after editing templates, partials, prompts, or schemas:

go test ./internal/reporttemplate ./internal/generatedtext ./internal/app
git diff --check

The render-context and template tests cover Daily, Today, Tomorrow, and Hourly contexts. Run the repository-wide test suite before merging a broader change.