180 lines
8.5 KiB
Markdown
180 lines
8.5 KiB
Markdown
# 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](internal/generatedtext.md) and [Report Template
|
|
internals](internal/reporttemplate.md).
|
|
|
|
## 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`; `prompts/daily.generated_text.md` |
|
|
| Today | `templates/today.md.tmpl` (`today`) | `today` | `weather.today_generated_text`; `prompts/today.generated_text.md` |
|
|
| Tomorrow | `templates/tomorrow.md.tmpl` (`tomorrow`) | `tomorrow` | `weather.tomorrow_generated_text`; `prompts/tomorrow.generated_text.md` |
|
|
| Hourly | `templates/hourly.md.tmpl` (`hourly`) | `hourly` | `weather.hourly_generated_text`; `prompts/hourly.generated_text.md` |
|
|
|
|
The matching schema files are under `internal/reporttemplate/schemas/`. The
|
|
generated-text catalog pairs each schema ID with its template ID; keep the
|
|
matching report prompt source 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](internal/generatedtext.md).
|
|
- Use `.Modules.Dayparts` for ordered daypart output. Do not range over
|
|
`.Modules.DerivedDaypartSummaries`, which is a map.
|
|
|
|
Minimal optional-value pattern:
|
|
|
|
```gotemplate
|
|
{{ with .Modules.CurrentConditions }}
|
|
Currently, it is {{ with .TemperatureF }}{{ . }}°F{{ end }}.
|
|
{{ else }}
|
|
Current conditions are unavailable.
|
|
{{ end }}
|
|
```
|
|
|
|
Minimal list pattern:
|
|
|
|
```gotemplate
|
|
{{ 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:
|
|
|
|
```gotemplate
|
|
{{ 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 Scriptorium. |
|
|
| `.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 Scriptorium 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` | Optional prose used by the precipitation partial when deterministic windows exist. |
|
|
| `.GeneratedText.Confidence` | `string` | `string` | Optional validated prose; the current templates do not render it. |
|
|
|
|
The JSON schema rejects unknown properties and defines the required fields, but
|
|
the schema body and validation behavior are documented in [Generated Text
|
|
internals](internal/generatedtext.md).
|
|
|
|
### 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](internal/module.md), [Module builder
|
|
internals](internal/briefing.md), and [Forecast derivation
|
|
internals](internal/forecast-derivation.md).
|
|
|
|
## Validate Changes
|
|
|
|
Run the focused checks after editing templates, partials, prompts, or schemas:
|
|
|
|
```sh
|
|
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.
|