Validate render identity and daypart fallbacks

This commit is contained in:
2026-08-13 02:11:25 +00:00
parent 360c665a3e
commit 2bd921f247
12 changed files with 253 additions and 184 deletions

View File

@@ -40,18 +40,24 @@ receive the same enforcement in this package.
## Render contexts
The catalog's report-specific builders receive briefing metadata, a rich module
snapshot, collected facts, derived facts, and the matching validated generated
text. They decode the module stanzas needed by the template and build typed
Daily, Today, Tomorrow, or Hourly contexts. Context construction validates
metadata and periods, preserves rich module values, and uses ordered slices for
template iteration rather than maps.
The catalog's report-specific builders receive the prepared report identity, a
rich module snapshot, derived facts needed to order dayparts, and the matching
validated generated text. They require the identity's report ID to match the
selected builder. When the optional metadata stanza is present, every shared
identity field must agree with that prepared authority before context
construction continues. Builders then decode the module stanzas needed by the
template and build typed Daily, Today, Tomorrow, or Hourly contexts. Contexts
expose only display-ready report values, generated prose, and module values;
they do not expose complete collected or derived fact bundles. Ordered slices
remain the template iteration surface rather than maps.
Optional source stanzas become nil or fallback context fields. Missing required
stanzas, type-decoding failures, invalid metadata, or a generated-text type
that does not match the chosen handler fail before template execution. Prompt
packages, raw Promptkit output handling, and template asset lookup remain
outside this package.
Optional source stanzas become nil or fallback context fields. Today also
computes whether its ordered dayparts contain a displayable condition so the
template can render either rows or its explicit no-details fallback. Missing
required stanzas, type-decoding failures, conflicting identity values, invalid
metadata, or a generated-text type that does not match the chosen handler fail
before template execution. Prompt packages, raw Promptkit output handling, and
template asset lookup remain outside this package.
## Verification and invariants

View File

@@ -28,8 +28,9 @@ failures actionable with template or partial context.
Top-level templates decide which shared partials they invoke. The current
partials cover daypart forecast variants, alert digest, and precipitation
timing. Template code receives curated typed contexts rather than raw data
packages, and it must not reimplement weather selection or generated-text
validation.
packages or complete fact bundles, and it must not reimplement weather
selection or generated-text validation. Context construction rejects
report-identity disagreements before template execution.
## Boundaries and verification
@@ -38,8 +39,8 @@ text, construct contexts, resolve report definitions, write state, execute
Promptkit, or upload reports. It produces Markdown bytes for application
orchestration to persist.
Focused tests cover template lookup, rendering, partial
behavior, missing keys, and malformed context:
Focused tests cover template lookup, rendering, partial behavior, daypart
fallbacks, missing keys, and malformed context:
```sh
go test ./internal/reporttemplate

View File

@@ -51,7 +51,9 @@ from rendering.
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.
`.Modules.DerivedDaypartSummaries`, which is a map. The Today partial uses
`.Modules.HasDaypartDetails` to ensure its heading has either rows or the
explicit no-details fallback.
Minimal optional-value pattern:
@@ -92,7 +94,7 @@ to render the section:
## Render Context
Every rendered template receives one typed context with these five top-level
Every rendered template receives one typed context with these three top-level
fields:
| Field | Purpose |
@@ -100,12 +102,6 @@ fields:
| `.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
@@ -144,8 +140,9 @@ 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.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.HasDaypartDetails` | Today |
| `.Modules.OutdoorWindows`, `.Modules.DailyPlanning` | Daily |
| `.Modules.TodayPlanning` | Today |
| `.Modules.TomorrowPlanning` | Tomorrow |