8.4 KiB
Module Contract Internals
This document describes the module contract in internal/module.
Purpose
internal/module defines the shared identifiers and data envelopes used for
report modules. Report definitions use module IDs for composition, module
builders produce rich outputs with stanza names, prompt input packages consume
runtime prompt export values, and Recent Changes compares snapshot stanzas.
Inputs And Outputs
Inputs:
- ordered
module.ConfigItemvalues from report definitions or config overrides module.Outputvalues produced by module builders
Outputs:
- stable
module.IDconstants - typed option structs for registered modules
module.Snapshotwith schema versionweatherreporter.modules.v1- ordered snapshot outputs with module ID, stanza name, and typed value
- runtime-only prompt export values on module outputs
module.Output.DataPackageValue, which selects the prompt export value and falls back to the rich value for hand-built or loaded snapshots- typed stanza lookup through
module.StanzaValue
Rich Values And Prompt Exports
Each module.Output has two value surfaces:
Value: the rich module value used by templates, module snapshots, inspection, Recent Changes, and render contexts.PromptValue: the runtime-only prompt export used when building Scriptorium data packages.
PromptValue is deliberately excluded from module snapshot JSON. Persisted
module snapshots keep only the rich value field so inspection and
render-context reconstruction keep the full deterministic template surface.
The internal/briefing module registry attaches prompt export values when it
builds module outputs. Modules without a custom exporter use default
pass-through behavior, so their prompt value is the same as their rich value.
Modules with custom prompt export policy own typed prompt export structs near
the module builder. Custom prompt exports are:
current_conditionshourly_forecastderived_daypart_summaries
Custom exporters remove template-only helpers or confusing duplicates from the data package without shrinking the rich module structs used by templates. Exporter failures include module ID and stanza context.
Registered Module IDs
The registry recognizes these IDs:
metadatacurrent_conditionsnarrative_forecasthourly_forecastderived_daily_summaryderived_daypart_summariesprecip_timingalert_digestspc_convective_outlooksarea_forecast_discussionspc_convective_discussionweather_storyoutdoor_windowstoday_planningtomorrow_planningdaily_planning
Every registered module has a builder. Report composition entries that refer to unknown or unimplemented module IDs fail validation instead of being skipped.
Daily Composition
The default Daily Report module order is:
metadatacurrent_conditionsnarrative_forecastderived_daily_summaryderived_daypart_summariesprecip_timingalert_digestspc_convective_outlooksarea_forecast_discussionspc_convective_discussionweather_storyoutdoor_windowsdaily_planninghourly_forecast
The embedded Daily template uses selected deterministic fields from these module outputs after GeneratedText validation.
Today Composition
The default Today Report module order is:
metadatacurrent_conditionsnarrative_forecastderived_daily_summaryderived_daypart_summariesprecip_timingalert_digestspc_convective_outlooksarea_forecast_discussionspc_convective_discussionweather_storyoutdoor_windowshourly_forecasttoday_planning
The embedded Today template uses selected deterministic fields from these module outputs after GeneratedText validation.
Tomorrow Composition
The default Tomorrow Report module order is:
metadatacurrent_conditionsnarrative_forecastderived_daily_summaryderived_daypart_summariesprecip_timingalert_digestspc_convective_outlooksarea_forecast_discussionspc_convective_discussionweather_storyoutdoor_windowstomorrow_planninghourly_forecast
The embedded Tomorrow template uses selected deterministic fields from these module outputs after GeneratedText validation.
Daily Planning
daily_planning emits dated daily planning facts for the daily report ID.
Its output stanza is also named daily_planning. The module is supported only
by that report ID and depends on daily summaries for the selected local civil
day. The default Daily Report composition includes it.
The output uses this shape:
morning_readinesscommute_school_workday_concernsovernight_change_watch
The type is briefing.DailyPlanningModule; it is independent from
briefing.TomorrowPlanningModule.
Today Planning
today_planning emits current-day planning facts for Today Report. Its output
stanza is also named today_planning. The module is supported only by Today
Report and depends on daily and daypart summaries for the current local civil
day.
The output uses this shape:
morning_readinesscommute_school_workday_concernsoutdoor_planninglate_day_change_watch
The type is briefing.TodayPlanningModule; it is independent from
briefing.TomorrowPlanningModule.
Hourly Composition
The default Hourly Report module order is:
metadatacurrent_conditionshourly_forecastprecip_timingalert_digestspc_convective_outlooksarea_forecast_discussionspc_convective_discussionweather_story
Hourly Report does not include daily or daypart summary modules by default.
Its area_forecast_discussion item is configured to include only
key_messages and short_term.
Options
Most modules use an empty options struct, including
spc_convective_outlooks and spc_convective_discussion.
area_forecast_discussion accepts:
sections:
- product
- key_messages
- short_term
- long_term
An omitted or empty sections list includes all available discussion sections.
Invalid option shapes fail during config normalization or composition
validation.
SPC Convective Module Outputs
spc_convective_outlooks emits a risk-product stanza with:
checkedas_ofissued_atlocation_idlocation_nameoutlook_countoutlooks
Each outlook entry may include day, outlook_type, label, label_text,
period_begins, period_ends, issued_at, contains_location, and
image_url. It omits GeoJSON geometry, source URL, expiration time, and
severity rank.
spc_convective_discussion emits a narrative stanza only when a retained
report-period categorical outlook has severity rank 3 or higher and matching
discussion text is available. Its output includes included_because and
discussions; each discussion may include day, period_begins,
period_ends, headline, summary, discussion, and updated_at.
Discussions are included only for SPC days whose retained categorical outlooks
meet the severity threshold.
Boundaries
- This package owns module identifiers, config item envelopes, output envelopes, snapshot validation, and typed stanza lookup.
- It does not define report IDs, execute builders, fetch weather data, derive forecast facts, write state, or invoke Scriptorium.
State Or Manifest Behavior
module.Snapshot values are persisted by internal/state as JSON. Snapshot
validation rejects missing schema version, missing module IDs, missing stanza
names, duplicate module outputs, and duplicate stanza names while preserving
output order. Snapshot JSON contains rich module values only; runtime prompt
export values are not persisted.
Failure Behavior
- Snapshot construction fails for duplicate module outputs or duplicate stanza names.
- Typed stanza lookup returns
found=falsefor missing stanzas. - Typed stanza lookup wraps JSON marshal/decode failures with stanza context.
Tests
Inspect:
internal/module/module_test.gointernal/briefing/modules_test.gointernal/report/period_test.go
Invariants
internal/moduledoes not importinternal/report.- Module IDs are stable strings.
- Each emitted module output has exactly one stanza name and one rich typed value.
- Built module outputs have a data-package value, either from a custom prompt exporter or from default pass-through behavior.
- Snapshot output order is caller-owned and preserved.