Refresh report and template internals documentation
This commit is contained in:
@@ -1,164 +1,69 @@
|
|||||||
# Module Builder Internals
|
# Module Builder Internals
|
||||||
|
|
||||||
This document describes module builder behavior in `internal/briefing`.
|
`internal/briefing` builds typed module outputs from resolved report context,
|
||||||
|
collected facts, and derived facts. It owns the module registry, including
|
||||||
|
module support, fact requirements, option types, missing-data policy, builders,
|
||||||
|
and prompt-export hooks. It does not collect data, derive periods, write a
|
||||||
|
snapshot, construct YAML, invoke Scriptorium, or render a report.
|
||||||
|
|
||||||
## Purpose
|
## Registry and construction
|
||||||
|
|
||||||
`internal/briefing` turns report metadata, collected weather data, and derived
|
Every `ModuleDefinition` declares an ID, stanza name, default option value,
|
||||||
forecast facts into prompt-facing module outputs. The package also owns the
|
required collected and derived facts, supported report IDs, missing-data
|
||||||
module registry used to validate report composition and config overrides.
|
behavior, duplicate policy, builder, and optional prompt exporter.
|
||||||
|
|
||||||
Module outputs are structured prompt inputs. They are not rendered report prose
|
`BuildModule` first verifies the requested module, report compatibility, and
|
||||||
and they are not persisted by this package.
|
option shape. It then applies the declared missing-data behavior:
|
||||||
|
|
||||||
## Inputs And Outputs
|
- `omit` returns no output for unavailable optional facts;
|
||||||
|
- `error` returns the missing fact requirements; and
|
||||||
|
- `empty` allows the builder to emit an explicit checked-empty value.
|
||||||
|
|
||||||
Inputs:
|
Unsupported `warn` behavior, missing builders, duplicate registry IDs or
|
||||||
|
stanza names, output ID or stanza mismatches, and exporter failures all return
|
||||||
|
errors with module context. A successful builder gets a pass-through prompt
|
||||||
|
value unless its definition supplies an exporter.
|
||||||
|
|
||||||
- resolved report definition, generation time, timezone, and valid period
|
## Built value families
|
||||||
- collected facts built from `weatherdata.Bundle`
|
|
||||||
- derived daily, daypart, precipitation, alert, and storm-window facts where
|
|
||||||
required
|
|
||||||
- configured units, timezone, and descriptive location context
|
|
||||||
- typed module options from report defaults or config overrides
|
|
||||||
|
|
||||||
Outputs:
|
Source-oriented builders shape report metadata, current conditions, narrative
|
||||||
|
and hourly forecasts, alert digest, SPC outlooks and discussion, area forecast
|
||||||
|
discussion, and weather story. Derived builders shape daily and daypart
|
||||||
|
summaries, precipitation timing, outdoor windows, and the report-specific
|
||||||
|
Daily, Today, and Tomorrow planning values.
|
||||||
|
|
||||||
- `ModuleDefinition` values with module ID, stanza name, option type,
|
The module registry preserves rich values for templates and snapshots while
|
||||||
supported reports, fact requirements, missing-data behavior, and builder
|
curating prompt exports where needed. In particular, source warnings are a
|
||||||
- `module.Output` values for source-oriented stanzas:
|
metadata summary, checked-empty alerts and SPC outlooks remain distinct from
|
||||||
`metadata`, `current_conditions`, `narrative_forecast`, `hourly_forecast`,
|
missing sources, and prompt-safe SPC values omit geometry and other
|
||||||
`alert_digest`, `spc_convective_outlooks`,
|
template-only or source details. The complete module composition is in
|
||||||
`area_forecast_discussion`, `spc_convective_discussion`, and
|
[module internals](module.md); fact derivation is in [fact contracts](facts.md).
|
||||||
`weather_story`
|
|
||||||
- `module.Output` values for derived stanzas:
|
|
||||||
`derived_daily_summary`, `derived_daypart_summaries`, `precip_timing`,
|
|
||||||
`outdoor_windows`, `today_planning`, `tomorrow_planning`, and
|
|
||||||
`daily_planning`
|
|
||||||
|
|
||||||
Every registered composition entry has a builder. Unknown or unimplemented
|
`area_forecast_discussion` accepts an optional typed section filter. Planning
|
||||||
module IDs fail validation instead of being skipped.
|
modules are report-specific: `daily_planning` supports Daily,
|
||||||
|
`today_planning` supports Today, and `tomorrow_planning` supports Tomorrow.
|
||||||
|
|
||||||
Daily Report supports the Daily-style civil-day modules plus `daily_planning`
|
## Missing data and boundaries
|
||||||
and `hourly_forecast`; those outputs feed the dated Daily GeneratedText prompt
|
|
||||||
package and embedded Markdown template.
|
|
||||||
|
|
||||||
Tomorrow Report supports the Daily-style civil-day modules plus
|
Optional current conditions, narrative products, discussions, and weather
|
||||||
`tomorrow_planning` and `hourly_forecast`; those outputs feed the Tomorrow
|
stories may be omitted. Required derived modules fail when their declared facts
|
||||||
GeneratedText prompt package and embedded Markdown template.
|
are unavailable. Empty alert and outlook runs can still produce checked-empty
|
||||||
|
modules. SPC discussion is omitted unless a retained categorical outlook meets
|
||||||
|
the package's severity criterion and matching discussion text exists.
|
||||||
|
|
||||||
Today Report supports the Daily-style civil-day modules plus `today_planning`
|
Effective units, timezone, and location context arrive in `ModuleContext` from
|
||||||
and `hourly_forecast`; those outputs feed the Today GeneratedText prompt
|
configuration and resolved report metadata. Field defaults are owned by
|
||||||
package and embedded Markdown template.
|
[configuration](../config.md), and prompt-package layout is owned by
|
||||||
|
[prompt input](prompt-input.md).
|
||||||
|
|
||||||
`today_planning` is a Today-specific deterministic planning stanza with
|
## Verification and invariants
|
||||||
morning readiness, commute/school/workday concerns, outdoor planning, and
|
|
||||||
late-day change-watch fields. It is compatible with `report.Today` only.
|
|
||||||
|
|
||||||
`daily_planning` is a dated Daily deterministic planning stanza with morning
|
Focused tests cover source and derived values, registry validation, option
|
||||||
readiness, commute/school/workday concerns, and overnight change-watch fields.
|
handling, prompt exporters, support rules, and missing-data behavior:
|
||||||
It is compatible only with the `daily` report ID value. The default Daily
|
|
||||||
Report composition includes it.
|
|
||||||
|
|
||||||
Hourly Report supports source and valid-period modules that operate over its
|
```sh
|
||||||
rolling six-hour period: `metadata`, `current_conditions`, `hourly_forecast`,
|
go test ./internal/briefing
|
||||||
`precip_timing`, `alert_digest`, `spc_convective_outlooks`,
|
```
|
||||||
`area_forecast_discussion`, `spc_convective_discussion`, and `weather_story`.
|
|
||||||
It does not support daily/daypart-only modules such as
|
|
||||||
`derived_daily_summary`, `derived_daypart_summaries`, `outdoor_windows`,
|
|
||||||
`today_planning`, `tomorrow_planning`, or `daily_planning`.
|
|
||||||
|
|
||||||
Prompt-facing module values use local, human-readable date and time labels
|
Builders emit structured facts, never report prose. The app collects their
|
||||||
where the LLM is expected to reason about report content. Canonical timestamps
|
outputs into a module snapshot, and state persists that snapshot.
|
||||||
remain in report metadata, source provenance, and integration artifacts.
|
|
||||||
|
|
||||||
## Boundaries
|
|
||||||
|
|
||||||
- This package selects and shapes already-collected weather facts for prompts.
|
|
||||||
- It validates module composition against report compatibility and option
|
|
||||||
types.
|
|
||||||
- It does not collect weather data, compare prior snapshots, write module
|
|
||||||
snapshots, build YAML data packages, invoke Scriptorium, or write workflow
|
|
||||||
metadata.
|
|
||||||
|
|
||||||
## Config Fields Used
|
|
||||||
|
|
||||||
The app layer passes effective units, timezone, and location context into the
|
|
||||||
module context. `internal/facts` consumes daypart configuration before module
|
|
||||||
builders run. Configured `location` values are prompt context only; Weather API
|
|
||||||
`sourceLocationId` and `sourceLocation` remain source provenance.
|
|
||||||
The `metadata` module carries report context and source warnings only; alert
|
|
||||||
status and relevant alert details belong in the `alert_digest` module.
|
|
||||||
|
|
||||||
`area_forecast_discussion` uses optional `sections` configuration to include a
|
|
||||||
subset of discussion fields. Hourly Report defaults this module to
|
|
||||||
`key_messages` and `short_term`; Daily Report defaults it to `long_term`.
|
|
||||||
|
|
||||||
`spc_convective_outlooks` uses collected SPC run metadata and derived
|
|
||||||
report-period outlooks. It emits `checked: true` for a successfully fetched
|
|
||||||
empty run, reports `outlook_count`, and includes prompt-facing outlook fields
|
|
||||||
such as risk label, `period_begins`, `period_ends`, image URL, and whether the
|
|
||||||
outlook contains the configured location. It enriches matching outlooks with
|
|
||||||
embedded background definitions owned by this package. It also emits a curated
|
|
||||||
`risk_digest` for categorical outlooks that overlap the report period, contain
|
|
||||||
the location, and meet the configured-in-code minimum severity for report
|
|
||||||
rendering. It does not emit GeoJSON geometry, source URL, expiration time, or
|
|
||||||
severity rank.
|
|
||||||
|
|
||||||
Prompt-facing module intervals use friendly local `period_begins` and
|
|
||||||
`period_ends` labels. Canonical report metadata, source provenance,
|
|
||||||
`issued_at`, `updated_at`, and point-in-time fields remain separate.
|
|
||||||
|
|
||||||
`spc_convective_discussion` uses the same derived report-period outlooks and
|
|
||||||
discussion records. It is omitted unless at least one retained categorical
|
|
||||||
outlook for the same SPC day has severity rank `3` or higher and matching
|
|
||||||
discussion text exists.
|
|
||||||
|
|
||||||
## External Adapters Used
|
|
||||||
|
|
||||||
None directly.
|
|
||||||
|
|
||||||
## State Or Manifest Behavior
|
|
||||||
|
|
||||||
None. `internal/app` collects module outputs into a `module.Snapshot`, and
|
|
||||||
`internal/state` persists that snapshot.
|
|
||||||
|
|
||||||
## Skip And Resume Behavior
|
|
||||||
|
|
||||||
None. Builders either emit a module output, omit optional unavailable data, or
|
|
||||||
return an error for invalid required inputs.
|
|
||||||
|
|
||||||
## Failure Behavior
|
|
||||||
|
|
||||||
- Required derived modules return errors when their dependent facts are not
|
|
||||||
available.
|
|
||||||
- Module registry construction rejects duplicate module IDs and duplicate
|
|
||||||
stanza names.
|
|
||||||
- Composition validation rejects unknown modules, duplicate modules,
|
|
||||||
incompatible report/module combinations, duplicate stanza names, and invalid
|
|
||||||
option shapes.
|
|
||||||
- Source-oriented module builders omit missing optional current conditions,
|
|
||||||
forecast discussion, and weather story stanzas.
|
|
||||||
- Alert digest output distinguishes checked empty alert data from missing alert
|
|
||||||
source data.
|
|
||||||
- SPC convective outlook output distinguishes checked empty outlook data from
|
|
||||||
missing outlook source data and omits GeoJSON geometry from prompt-facing
|
|
||||||
fields.
|
|
||||||
- SPC convective discussion output is omitted unless a retained outlook has
|
|
||||||
severity rank `3` or higher and matching discussion text is available.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/briefing/base_modules_test.go`
|
|
||||||
- `internal/briefing/derived_modules_test.go`
|
|
||||||
- `internal/briefing/modules_test.go`
|
|
||||||
- `internal/app/app_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- Module outputs contain structured weather facts and source context.
|
|
||||||
- Common metadata includes RunID, report ID, prompt ID, valid period, source
|
|
||||||
provenance, source hashes, source warnings, and configured prompt location.
|
|
||||||
- Prompt input packaging and Scriptorium execution remain outside this package.
|
|
||||||
|
|||||||
@@ -1,149 +1,51 @@
|
|||||||
# Generated Text Internals
|
# Generated Text Internals
|
||||||
|
|
||||||
This document describes structured generated-text handling in
|
`internal/generatedtext` validates the structured prose produced for generated-
|
||||||
`internal/generatedtext`.
|
text reports and turns validated prose plus rich module values into typed render
|
||||||
|
contexts. It owns the catalog that pairs a generated-text report definition
|
||||||
|
with its validator, schema ID, template ID, and context builder. The complete
|
||||||
|
maintainer-facing context fields belong to [report templates](../templates.md).
|
||||||
|
|
||||||
## Purpose
|
## Catalog and validation
|
||||||
|
|
||||||
`internal/generatedtext` validates structured text returned for
|
Only the Daily, Today, Tomorrow, and Hourly report definitions use the
|
||||||
generated-text-template reports and builds curated render contexts for
|
generated-text-template mode. `LookupDefinition` rejects a direct-Markdown
|
||||||
templates. It also owns the generated-text catalog that connects report
|
definition, unknown schema or template IDs, and unsupported schema/template
|
||||||
definitions to validators, render-context builders, schema assets, and template
|
pairs before the run begins. A handler validates raw JSON, returns a typed
|
||||||
assets.
|
value and canonical normalized JSON, loads its schema, builds a render context,
|
||||||
|
and renders through `internal/reporttemplate`.
|
||||||
|
|
||||||
## Inputs And Outputs
|
Daily, Today, and Tomorrow use a day-style value with required trimmed summary
|
||||||
|
and one or more nonblank discussion paragraphs. Hourly requires trimmed summary
|
||||||
|
and a single trimmed discussion string. Each form permits optional trimmed
|
||||||
|
precipitation-timing and confidence prose. Typed decoding rejects unknown JSON
|
||||||
|
fields; no general-purpose JSON Schema engine is used at runtime.
|
||||||
|
|
||||||
Inputs:
|
## Render contexts
|
||||||
|
|
||||||
- raw GeneratedText JSON for Daily, Today, Tomorrow Report, or Hourly Report
|
The catalog's report-specific builders receive briefing metadata, a rich module
|
||||||
- report metadata from `internal/briefing`
|
snapshot, collected facts, derived facts, and the matching validated generated
|
||||||
- a module snapshot from `internal/module`
|
text. They decode the module stanzas needed by the template and build typed
|
||||||
- validated generated text
|
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.
|
||||||
|
|
||||||
Outputs:
|
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 Scriptorium output, state persistence, and template asset lookup
|
||||||
|
remain outside this package.
|
||||||
|
|
||||||
- typed `Daily` generated text
|
## Verification and invariants
|
||||||
- typed `Today` generated text
|
|
||||||
- typed `Tomorrow` generated text
|
|
||||||
- typed `Hourly` generated text
|
|
||||||
- normalized stable JSON for validated generated text
|
|
||||||
- typed `DailyRenderContext` values for `internal/reporttemplate`
|
|
||||||
- typed `TodayRenderContext` values for `internal/reporttemplate`
|
|
||||||
- typed `TomorrowRenderContext` values for `internal/reporttemplate`
|
|
||||||
- typed `HourlyRenderContext` values for `internal/reporttemplate`
|
|
||||||
- generated-text catalog handlers for report definitions that use
|
|
||||||
`generated_text_template`
|
|
||||||
|
|
||||||
## JSON Contracts
|
Focused tests cover the catalog, each report-specific validator, normalization,
|
||||||
|
schema/template mismatches, context construction, optional modules, and typed
|
||||||
|
stanza errors:
|
||||||
|
|
||||||
Daily, Today, and Tomorrow use the same day-style generated-text JSON shape:
|
```sh
|
||||||
|
go test ./internal/generatedtext
|
||||||
```json
|
|
||||||
{
|
|
||||||
"summary": "string",
|
|
||||||
"forecast_discussion": ["string"],
|
|
||||||
"precipitation_timing": "string",
|
|
||||||
"confidence": "string"
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The day-style contract requires `summary` after trimming whitespace.
|
Generated text supplies prose slots only; deterministic weather facts remain in
|
||||||
`forecast_discussion` must contain at least one nonblank paragraph after
|
module and fact values. Every generated-text definition must resolve to exactly
|
||||||
trimming blank items. `precipitation_timing` and `confidence` are optional and
|
one supported catalog pair.
|
||||||
omitted from normalized JSON when blank. Unknown fields are rejected.
|
|
||||||
|
|
||||||
The report-specific Go API is:
|
|
||||||
|
|
||||||
| Report | Type | Validator | Schema ID | Template ID | Prompt ID |
|
|
||||||
| --- | --- | --- | --- | --- | --- |
|
|
||||||
| Daily Report | `Daily` | `ValidateDaily` | `daily` | `daily` | `weather.daily_generated_text` |
|
|
||||||
| Today Report | `Today` | `ValidateToday` | `today` | `today` | `weather.today_generated_text` |
|
|
||||||
| Tomorrow Report | `Tomorrow` | `ValidateTomorrow` | `tomorrow` | `tomorrow` | `weather.tomorrow_generated_text` |
|
|
||||||
|
|
||||||
Hourly generated text uses the same top-level field names, but
|
|
||||||
`forecast_discussion` is a single string:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"summary": "string",
|
|
||||||
"forecast_discussion": "string",
|
|
||||||
"precipitation_timing": "string",
|
|
||||||
"confidence": "string"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Hourly `summary` and `forecast_discussion` are required after trimming
|
|
||||||
whitespace. `precipitation_timing` and `confidence` are optional and omitted
|
|
||||||
from normalized JSON when blank. Unknown fields are rejected. The Hourly catalog
|
|
||||||
entry uses type `Hourly`, validator `ValidateHourly`, schema ID `hourly`,
|
|
||||||
template ID `hourly`, and prompt ID `weather.hourly_generated_text`.
|
|
||||||
|
|
||||||
## Render Contexts
|
|
||||||
|
|
||||||
Daily, Today, Tomorrow, and Hourly render contexts all include:
|
|
||||||
|
|
||||||
- display metadata derived from report metadata;
|
|
||||||
- validated generated text;
|
|
||||||
- typed module outputs decoded from the module snapshot;
|
|
||||||
- collected facts;
|
|
||||||
- derived facts.
|
|
||||||
|
|
||||||
Daily, Today, and Tomorrow share common civil-day render-context fields such as
|
|
||||||
forecast date labels, valid period, generated-at labels, current conditions,
|
|
||||||
hourly forecast, precipitation timing, alert digest, SPC outlooks, AFD, SPC
|
|
||||||
discussion, weather story, daily summary, and ordered daypart summaries.
|
|
||||||
|
|
||||||
Each civil-day report keeps its report-specific planning module:
|
|
||||||
|
|
||||||
- Daily exposes `DailyPlanning`.
|
|
||||||
- Today exposes `TodayPlanning`.
|
|
||||||
- Tomorrow exposes `TomorrowPlanning`.
|
|
||||||
|
|
||||||
Today's ordered daypart context omits unavailable or elapsed dayparts according
|
|
||||||
to Today report rules. Daily and Tomorrow use fallback daypart behavior.
|
|
||||||
|
|
||||||
## Boundaries
|
|
||||||
|
|
||||||
- This package owns typed generated-text validation and render-context shaping.
|
|
||||||
- It owns generated-text catalog lookup for schema/template combinations.
|
|
||||||
- It uses typed module snapshot decoding through `module.StanzaValue`.
|
|
||||||
- It does not invoke Scriptorium, write state artifacts, choose report
|
|
||||||
definitions, compare snapshots, or own embedded template/schema files.
|
|
||||||
- It renders through `internal/reporttemplate`; embedded asset lookup remains
|
|
||||||
in `internal/reporttemplate`.
|
|
||||||
- It does not use a Go JSON Schema dependency; schema enforcement in Go is
|
|
||||||
limited to typed JSON decoding, unknown-field rejection, and required-field
|
|
||||||
checks.
|
|
||||||
|
|
||||||
## Failure Behavior
|
|
||||||
|
|
||||||
- Malformed generated-text JSON fails with decode context.
|
|
||||||
- Unknown generated-text JSON fields fail during decoding.
|
|
||||||
- Empty required fields fail after trimming whitespace.
|
|
||||||
- Daily, Today, and Tomorrow forecast discussion fails when no nonblank
|
|
||||||
paragraphs remain.
|
|
||||||
- Missing optional render-context stanzas become nil module pointers.
|
|
||||||
- Invalid render metadata, including missing timezone, missing generated time,
|
|
||||||
or invalid valid period, fails before template rendering.
|
|
||||||
- Unsupported generated-text schema IDs, template IDs, or schema/template
|
|
||||||
combinations fail during catalog lookup with report ID context.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/generatedtext/hourly_test.go`
|
|
||||||
- `internal/generatedtext/daily_test.go`
|
|
||||||
- `internal/generatedtext/today_test.go`
|
|
||||||
- `internal/generatedtext/tomorrow_test.go`
|
|
||||||
- `internal/generatedtext/catalog_test.go`
|
|
||||||
- `internal/generatedtext/render_context_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- Render contexts are curated structs, not raw prompt-input packages.
|
|
||||||
- Required generated text is normalized before downstream artifact storage.
|
|
||||||
- Generated-text-template reports must have one catalog entry matching their
|
|
||||||
report definition schema and template IDs.
|
|
||||||
- Missing optional weather narrative stanzas produce empty or fallback render
|
|
||||||
context fields rather than forcing raw module data into templates.
|
|
||||||
|
|||||||
@@ -1,290 +1,68 @@
|
|||||||
# Module Contract Internals
|
# Module Contract Internals
|
||||||
|
|
||||||
This document describes the module contract in `internal/module`.
|
`internal/module` defines the stable envelope between report composition,
|
||||||
|
module builders, snapshots, comparisons, templates, and prompt packages. It
|
||||||
|
does not define a report, execute a builder, or choose prompt-export policy;
|
||||||
|
those responsibilities belong to [report registry](report-registry.md) and
|
||||||
|
[briefing](briefing.md).
|
||||||
|
|
||||||
## Purpose
|
## Outputs and snapshots
|
||||||
|
|
||||||
`internal/module` defines the shared identifiers and data envelopes used for
|
Each `Output` has a module ID, stanza name, rich `Value`, and runtime-only
|
||||||
report modules. Report definitions use module IDs for composition, module
|
`PromptValue`. `DataPackageValue` returns the prompt value when present and
|
||||||
builders produce rich outputs with stanza names, prompt input packages consume
|
otherwise the rich value. This permits custom prompt exports without shrinking
|
||||||
runtime prompt export values, and Recent Changes compares snapshot stanzas.
|
the template and inspection value.
|
||||||
|
|
||||||
## Inputs And Outputs
|
`NewSnapshot` builds the ordered `weatherreporter.modules.v1` snapshot and
|
||||||
|
validates it. Snapshot JSON persists IDs, stanza names, and rich values only;
|
||||||
|
`PromptValue` is deliberately excluded. `StanzaValue` decodes a named rich
|
||||||
|
stanza into a caller-supplied type, reporting a missing stanza separately from
|
||||||
|
a decoding error.
|
||||||
|
|
||||||
Inputs:
|
Snapshots reject missing schema versions, empty IDs or stanza names, and
|
||||||
|
duplicate IDs or stanza names. Output order is caller-owned and preserved.
|
||||||
|
|
||||||
- ordered `module.ConfigItem` values from report definitions or config
|
## Registered IDs and default composition
|
||||||
overrides
|
|
||||||
- `module.Output` values produced by module builders
|
|
||||||
|
|
||||||
Outputs:
|
The registered IDs are `metadata`, `current_conditions`,
|
||||||
|
`narrative_forecast`, `hourly_forecast`, `derived_daily_summary`,
|
||||||
|
`derived_daypart_summaries`, `precip_timing`, `alert_digest`,
|
||||||
|
`spc_convective_outlooks`, `area_forecast_discussion`,
|
||||||
|
`spc_convective_discussion`, `weather_story`, `outdoor_windows`,
|
||||||
|
`today_planning`, `tomorrow_planning`, and `daily_planning`.
|
||||||
|
|
||||||
- stable `module.ID` constants
|
The registry declares these ordered default compositions:
|
||||||
- typed option structs for registered modules
|
|
||||||
- `module.Snapshot` with schema version `weatherreporter.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
|
| Report | Ordered modules |
|
||||||
|
| --- | --- |
|
||||||
|
| Daily | metadata, current conditions, narrative forecast, daily summary, daypart summaries, precipitation timing, alert digest, SPC outlooks, AFD (long term), SPC discussion, weather story, outdoor windows, daily planning, hourly forecast |
|
||||||
|
| Today | metadata, current conditions, narrative forecast, daily summary, daypart summaries, precipitation timing, alert digest, SPC outlooks, AFD, SPC discussion, weather story, outdoor windows, hourly forecast, today planning |
|
||||||
|
| Tomorrow | metadata, current conditions, narrative forecast, daily summary, daypart summaries, precipitation timing, alert digest, SPC outlooks, AFD, SPC discussion, weather story, outdoor windows, tomorrow planning, hourly forecast |
|
||||||
|
| Hourly | metadata, current conditions, hourly forecast, precipitation timing, alert digest, SPC outlooks, AFD (key messages and short term), SPC discussion, weather story |
|
||||||
|
| Three-day and Weekend | metadata, current conditions, daypart summaries, precipitation timing, alert digest, SPC outlooks, AFD, SPC discussion, weather story, outdoor windows |
|
||||||
|
| Storm | metadata, current conditions, precipitation timing, alert digest, SPC outlooks, AFD, SPC discussion, weather story |
|
||||||
|
|
||||||
Each `module.Output` has two value surfaces:
|
The only non-empty default option is the AFD section selection. It accepts a
|
||||||
|
`sections` list; omitted or empty selects all available sections. Report
|
||||||
|
definitions may narrow it as shown above. Option shape and report compatibility
|
||||||
|
are validated by the briefing registry.
|
||||||
|
|
||||||
- `Value`: the rich module value used by templates, module snapshots,
|
## Rich and prompt-facing values
|
||||||
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
|
Rich values remain available to snapshots, comparisons, and render contexts.
|
||||||
module snapshots keep only the rich `value` field so inspection and
|
Briefing attaches custom prompt exports only for current conditions, hourly
|
||||||
render-context reconstruction keep the full deterministic template surface.
|
forecast, and derived daypart summaries; all other current builders use
|
||||||
|
pass-through values. The prompt package owns how exported stanzas are grouped
|
||||||
|
and serialized; see [prompt input](prompt-input.md).
|
||||||
|
|
||||||
The `internal/briefing` module registry attaches prompt export values when it
|
## Verification and invariants
|
||||||
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_conditions`
|
Focused tests cover snapshot validation and order, typed stanza lookup, and
|
||||||
- `hourly_forecast`
|
prompt-value fallback:
|
||||||
- `derived_daypart_summaries`
|
|
||||||
|
|
||||||
Custom exporters remove template-only helpers or confusing duplicates from the
|
```sh
|
||||||
data package without shrinking the rich module structs used by templates.
|
go test ./internal/module
|
||||||
Exporter failures include module ID and stanza context.
|
|
||||||
|
|
||||||
## Registered Module IDs
|
|
||||||
|
|
||||||
The registry recognizes these IDs:
|
|
||||||
|
|
||||||
- `metadata`
|
|
||||||
- `current_conditions`
|
|
||||||
- `narrative_forecast`
|
|
||||||
- `hourly_forecast`
|
|
||||||
- `derived_daily_summary`
|
|
||||||
- `derived_daypart_summaries`
|
|
||||||
- `precip_timing`
|
|
||||||
- `alert_digest`
|
|
||||||
- `spc_convective_outlooks`
|
|
||||||
- `area_forecast_discussion`
|
|
||||||
- `spc_convective_discussion`
|
|
||||||
- `weather_story`
|
|
||||||
- `outdoor_windows`
|
|
||||||
- `today_planning`
|
|
||||||
- `tomorrow_planning`
|
|
||||||
- `daily_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:
|
|
||||||
|
|
||||||
1. `metadata`
|
|
||||||
2. `current_conditions`
|
|
||||||
3. `narrative_forecast`
|
|
||||||
4. `derived_daily_summary`
|
|
||||||
5. `derived_daypart_summaries`
|
|
||||||
6. `precip_timing`
|
|
||||||
7. `alert_digest`
|
|
||||||
8. `spc_convective_outlooks`
|
|
||||||
9. `area_forecast_discussion`
|
|
||||||
10. `spc_convective_discussion`
|
|
||||||
11. `weather_story`
|
|
||||||
12. `outdoor_windows`
|
|
||||||
13. `daily_planning`
|
|
||||||
14. `hourly_forecast`
|
|
||||||
|
|
||||||
The embedded Daily template uses selected deterministic fields from these
|
|
||||||
module outputs after GeneratedText validation. Its `area_forecast_discussion`
|
|
||||||
item is configured to include only `long_term`.
|
|
||||||
|
|
||||||
## Today Composition
|
|
||||||
|
|
||||||
The default Today Report module order is:
|
|
||||||
|
|
||||||
1. `metadata`
|
|
||||||
2. `current_conditions`
|
|
||||||
3. `narrative_forecast`
|
|
||||||
4. `derived_daily_summary`
|
|
||||||
5. `derived_daypart_summaries`
|
|
||||||
6. `precip_timing`
|
|
||||||
7. `alert_digest`
|
|
||||||
8. `spc_convective_outlooks`
|
|
||||||
9. `area_forecast_discussion`
|
|
||||||
10. `spc_convective_discussion`
|
|
||||||
11. `weather_story`
|
|
||||||
12. `outdoor_windows`
|
|
||||||
13. `hourly_forecast`
|
|
||||||
14. `today_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:
|
|
||||||
|
|
||||||
1. `metadata`
|
|
||||||
2. `current_conditions`
|
|
||||||
3. `narrative_forecast`
|
|
||||||
4. `derived_daily_summary`
|
|
||||||
5. `derived_daypart_summaries`
|
|
||||||
6. `precip_timing`
|
|
||||||
7. `alert_digest`
|
|
||||||
8. `spc_convective_outlooks`
|
|
||||||
9. `area_forecast_discussion`
|
|
||||||
10. `spc_convective_discussion`
|
|
||||||
11. `weather_story`
|
|
||||||
12. `outdoor_windows`
|
|
||||||
13. `tomorrow_planning`
|
|
||||||
14. `hourly_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_readiness`
|
|
||||||
- `commute_school_workday_concerns`
|
|
||||||
- `overnight_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_readiness`
|
|
||||||
- `commute_school_workday_concerns`
|
|
||||||
- `outdoor_planning`
|
|
||||||
- `late_day_change_watch`
|
|
||||||
|
|
||||||
The type is `briefing.TodayPlanningModule`; it is independent from
|
|
||||||
`briefing.TomorrowPlanningModule`.
|
|
||||||
|
|
||||||
## Hourly Composition
|
|
||||||
|
|
||||||
The default Hourly Report module order is:
|
|
||||||
|
|
||||||
1. `metadata`
|
|
||||||
2. `current_conditions`
|
|
||||||
3. `hourly_forecast`
|
|
||||||
4. `precip_timing`
|
|
||||||
5. `alert_digest`
|
|
||||||
6. `spc_convective_outlooks`
|
|
||||||
7. `area_forecast_discussion`
|
|
||||||
8. `spc_convective_discussion`
|
|
||||||
9. `weather_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:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
sections:
|
|
||||||
- product
|
|
||||||
- key_messages
|
|
||||||
- short_term
|
|
||||||
- long_term
|
|
||||||
```
|
```
|
||||||
|
|
||||||
An omitted or empty `sections` list includes all available discussion sections.
|
Module IDs and stanza names are stable, every emitted output has one of each,
|
||||||
Invalid option shapes fail during config normalization or composition
|
and this package never imports the report registry.
|
||||||
validation.
|
|
||||||
|
|
||||||
## SPC Convective Module Outputs
|
|
||||||
|
|
||||||
`spc_convective_outlooks` emits a risk-product stanza with:
|
|
||||||
|
|
||||||
- `checked`
|
|
||||||
- `as_of`
|
|
||||||
- `issued_at`
|
|
||||||
- `location_id`
|
|
||||||
- `location_name`
|
|
||||||
- `outlook_count`
|
|
||||||
- `outlooks`
|
|
||||||
- `risk_digest`
|
|
||||||
|
|
||||||
Each outlook entry may include `day`, `outlook_type`, `label`, `label_text`,
|
|
||||||
`background_definition`, `period_begins`, `period_ends`, `issued_at`,
|
|
||||||
`contains_location`, and `image_url`. `background_definition` is embedded
|
|
||||||
briefing reference content for known outlook type/label pairs and may include
|
|
||||||
`plain_language`, `official_description`, and `relative_level`. It omits GeoJSON
|
|
||||||
geometry, source URL, expiration time, and severity rank.
|
|
||||||
|
|
||||||
The optional `risk_digest` list is a curated report-rendering subset of
|
|
||||||
categorical outlooks that overlap the report period, contain the configured
|
|
||||||
location, and meet the minimum severity threshold. Entries include `label_text`,
|
|
||||||
`risk_label`, `period_begins`, and `period_ends`; they do not expose 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, collect 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=false` for missing stanzas.
|
|
||||||
- Typed stanza lookup wraps JSON marshal/decode failures with stanza context.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/module/module_test.go`
|
|
||||||
- `internal/briefing/modules_test.go`
|
|
||||||
- `internal/report/period_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- `internal/module` does not import `internal/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.
|
|
||||||
|
|||||||
@@ -1,177 +1,61 @@
|
|||||||
# Prompt Input Internals
|
# Prompt Input Internals
|
||||||
|
|
||||||
This document describes YAML prompt data package construction in
|
`internal/promptinput` converts report metadata, an ordered module snapshot,
|
||||||
`internal/promptinput`.
|
Recent Changes, and source warnings into the YAML `data_package` consumed by
|
||||||
|
Scriptorium. It owns this package's schema, grouping, serialization, loading,
|
||||||
|
and validation—not weather collection, module construction, path choice, or
|
||||||
|
subprocess execution.
|
||||||
|
|
||||||
## Purpose
|
## Package construction
|
||||||
|
|
||||||
`internal/promptinput` converts report metadata, ordered module outputs, Recent
|
`Build` produces `weatherreporter.data_package.v3`. It copies the run ID;
|
||||||
Changes, and source warnings into the `data_package` file passed to
|
report ID, variant, prompt ID, generation time, timezone, local current date,
|
||||||
Scriptorium.
|
and valid period; ordered briefing stanzas; Recent Changes; and source
|
||||||
|
warnings. A nil Recent Changes slice becomes an empty `items` list.
|
||||||
|
|
||||||
The persisted data package is YAML with schema version
|
Briefing starts as a flat snapshot order and stanza-value map. `Build` uses
|
||||||
`weatherreporter.data_package.v3`. It is separate from the JSON module snapshot
|
each output's `DataPackageValue`, so runtime prompt exports take precedence and
|
||||||
used for inspection and comparison. Data packages serialize each module
|
rich values are used only as a fallback. Prompt exports are selected by the
|
||||||
output's prompt export value, not necessarily the full rich module value saved
|
[briefing registry](briefing.md), while the rich-versus-prompt contract is in
|
||||||
in the module snapshot.
|
[module internals](module.md).
|
||||||
|
|
||||||
## Inputs And Outputs
|
## YAML ordering and grouping
|
||||||
|
|
||||||
Inputs:
|
Serialization keeps `metadata` directly under `briefing`. Every other known
|
||||||
|
stanza is placed in exactly one category, emitted in category order and in its
|
||||||
|
original snapshot order within that category:
|
||||||
|
|
||||||
- report metadata from app/state orchestration
|
| Category | Current stanzas |
|
||||||
- `module.Snapshot`
|
| --- | --- |
|
||||||
- optional `[]changes.Change`
|
| `applicable_risk_products` | alert digest, SPC convective outlooks |
|
||||||
|
| `derived_summaries` | deterministic summaries, precipitation timing, outdoor windows, and planning values |
|
||||||
|
| `narrative_products` | narrative forecast, discussions, and weather story |
|
||||||
|
| `raw_data` | current conditions and hourly forecast |
|
||||||
|
|
||||||
Outputs:
|
This YAML presentation does not alter the flat snapshot model. `LoadYAML`
|
||||||
|
accepts the same category layout and reconstructs flat `Order` and `Values`,
|
||||||
|
rejecting misplaced, duplicate, unknown, or uncategorized stanzas.
|
||||||
|
|
||||||
- `promptinput.Package` with schema version, RunID, report metadata, named
|
## Validation and persistence
|
||||||
module stanzas grouped for prompt presentation, Recent Changes, and source
|
|
||||||
warnings
|
|
||||||
- YAML bytes from `promptinput.MarshalYAML`
|
|
||||||
- YAML file written atomically by `promptinput.Save`
|
|
||||||
|
|
||||||
The YAML shape includes:
|
`Validate` requires the current schema version, run and report identifiers,
|
||||||
|
prompt ID, generation timestamp, timezone, current local date, valid period,
|
||||||
|
and at least one ordered briefing stanza. It rejects duplicate stanza names,
|
||||||
|
missing values, and a missing category for every non-metadata stanza.
|
||||||
|
|
||||||
```yaml
|
`MarshalYAML` and `LoadYAML` validate their result. `Save` writes the serialized
|
||||||
schema_version: weatherreporter.data_package.v3
|
YAML atomically; managed workspace paths are owned by [state internals](state.md).
|
||||||
run_id: <run_id>
|
Generated-text artifacts and template render contexts are later workflow
|
||||||
report:
|
artifacts, not members of this package.
|
||||||
id: <report_id>
|
|
||||||
prompt_id: <prompt_id>
|
## Verification and invariants
|
||||||
briefing:
|
|
||||||
metadata: {}
|
Focused tests cover construction, curated exports, category ordering, YAML
|
||||||
applicable_risk_products:
|
round trips, invalid layout, validation, and atomic saves:
|
||||||
alert_digest: {}
|
|
||||||
spc_convective_outlooks: {}
|
```sh
|
||||||
derived_summaries:
|
go test ./internal/promptinput
|
||||||
derived_daily_summary: {}
|
|
||||||
derived_daypart_summaries: {}
|
|
||||||
precip_timing: {}
|
|
||||||
outdoor_windows: {}
|
|
||||||
narrative_products:
|
|
||||||
narrative_forecast: {}
|
|
||||||
area_forecast_discussion: {}
|
|
||||||
spc_convective_discussion: {}
|
|
||||||
weather_story: {}
|
|
||||||
raw_data:
|
|
||||||
current_conditions: {}
|
|
||||||
hourly_forecast: {}
|
|
||||||
recent_changes:
|
|
||||||
items: []
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `briefing` mapping keeps `metadata` directly under `briefing` and groups
|
The package is narrower than a template render context and never infers changes
|
||||||
weather module stanzas under prompt-facing categories. This grouping is a YAML
|
from report prose.
|
||||||
presentation concern only: module snapshots remain flat, and loaded
|
|
||||||
`promptinput.Package` values expose flat stanza names in `Briefing.Values`.
|
|
||||||
Within each category, stanza order follows the module snapshot output order.
|
|
||||||
Prompt-facing module intervals use local `period_begins` and `period_ends`
|
|
||||||
labels; canonical report metadata and source timestamps remain structured
|
|
||||||
timestamps where applicable.
|
|
||||||
|
|
||||||
## Module Export Boundary
|
|
||||||
|
|
||||||
Data packages are curated prompt inputs. They are not full template render
|
|
||||||
contexts and should not be treated as a dump of every field available to Go
|
|
||||||
templates.
|
|
||||||
|
|
||||||
When module outputs are built by `internal/briefing`, the registry attaches a
|
|
||||||
runtime prompt export value. `internal/promptinput` serializes
|
|
||||||
`output.DataPackageValue()` for each stanza. That helper prefers the runtime
|
|
||||||
prompt export and falls back to the rich `Value` when no prompt export is set,
|
|
||||||
which keeps loaded snapshots and hand-built tests usable.
|
|
||||||
|
|
||||||
Modules without custom export policy use pass-through behavior. Modules with
|
|
||||||
custom exports currently include:
|
|
||||||
|
|
||||||
- `current_conditions`: omits lower-case condition text and duplicate
|
|
||||||
wind-direction text.
|
|
||||||
- `hourly_forecast`: omits hour labels, lower-case description text, and the
|
|
||||||
template precipitation-mention helper while keeping forecast facts.
|
|
||||||
- `derived_daypart_summaries`: omits deterministic sentence-construction
|
|
||||||
helpers while keeping daypart period, condition, temperature trend,
|
|
||||||
precipitation, wind, notable-condition, hazard, and alert-relevance facts.
|
|
||||||
|
|
||||||
The rich module snapshot and generated-template render context still contain
|
|
||||||
the helper fields used by deterministic Markdown templates.
|
|
||||||
|
|
||||||
Daily Report, Today Report, Tomorrow Report, and Hourly Report module snapshots
|
|
||||||
use the same package schema and categories when converted into prompt input.
|
|
||||||
The default hourly module list places
|
|
||||||
`precip_timing` under `derived_summaries`, alert and SPC outlooks under
|
|
||||||
`applicable_risk_products`, AFD/SPC discussion/weather story under
|
|
||||||
`narrative_products`, and current/hourly data under `raw_data`. It does not
|
|
||||||
include civil-day summary stanzas. Generated-text and render context artifacts
|
|
||||||
are produced later in app orchestration and are not part of the YAML data
|
|
||||||
package.
|
|
||||||
|
|
||||||
The default Daily, Today, and Tomorrow module lists include civil-day summary
|
|
||||||
stanzas, planning stanzas, and `hourly_forecast` in the data package before
|
|
||||||
structured GeneratedText is requested from Scriptorium. Daily uses
|
|
||||||
`daily_planning`, Today uses `today_planning`, and Tomorrow uses
|
|
||||||
`tomorrow_planning`.
|
|
||||||
|
|
||||||
Current categories are:
|
|
||||||
|
|
||||||
- `applicable_risk_products`: location-applicable alerts, warnings, outlooks,
|
|
||||||
and similar risk products. Current stanzas include `alert_digest` and
|
|
||||||
`spc_convective_outlooks`.
|
|
||||||
- `derived_summaries`: deterministic summaries and calculated report facts.
|
|
||||||
- `narrative_products`: official narrative text products and forecast stories.
|
|
||||||
Current stanzas include `narrative_forecast`,
|
|
||||||
`area_forecast_discussion`, `spc_convective_discussion`, and
|
|
||||||
`weather_story`.
|
|
||||||
- `raw_data`: minimally transformed underlying weather data.
|
|
||||||
|
|
||||||
## Boundaries
|
|
||||||
|
|
||||||
- This package owns prompt package schema, YAML marshaling, YAML loading, and
|
|
||||||
validation.
|
|
||||||
- It does not collect weather data, derive forecast summaries, execute modules,
|
|
||||||
choose module prompt export shapes, find prior snapshots, compare changes,
|
|
||||||
choose artifact paths, or invoke Scriptorium.
|
|
||||||
|
|
||||||
## Config Fields Used
|
|
||||||
|
|
||||||
None directly. Config-derived values such as timezone, units, and prompt
|
|
||||||
location are already present in report metadata and module stanzas before this
|
|
||||||
package runs.
|
|
||||||
|
|
||||||
## External Adapters Used
|
|
||||||
|
|
||||||
None.
|
|
||||||
|
|
||||||
## State Or Manifest Behavior
|
|
||||||
|
|
||||||
`promptinput.Save` writes YAML atomically. Managed workspace paths are owned by
|
|
||||||
`internal/state`.
|
|
||||||
|
|
||||||
## Skip And Resume Behavior
|
|
||||||
|
|
||||||
None. Recent Changes is always present as an `items` list and may be empty.
|
|
||||||
|
|
||||||
## Failure Behavior
|
|
||||||
|
|
||||||
Validation fails before render preflight when required top-level fields are
|
|
||||||
missing or inconsistent, when the valid period is invalid, or when no module
|
|
||||||
stanzas are present. Save failures include filesystem operation and path
|
|
||||||
context.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/promptinput/package_test.go`
|
|
||||||
- `internal/app/app_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- Scriptorium receives structured YAML through `--input data_package=<path>`.
|
|
||||||
- Module stanza order is deterministic within each prompt-facing category.
|
|
||||||
- Every non-metadata module stanza has exactly one prompt-input category.
|
|
||||||
- Data-package stanzas use curated module prompt exports when present and rich
|
|
||||||
values only as pass-through or fallback values.
|
|
||||||
- Data packages are narrower than generated-template render contexts.
|
|
||||||
- Recent Changes are provided by `internal/changes`; this package does not
|
|
||||||
infer changes from rendered report text.
|
|
||||||
|
|||||||
@@ -1,143 +1,76 @@
|
|||||||
# Report Registry Internals
|
# Report Registry Internals
|
||||||
|
|
||||||
This document describes report identity, valid-period resolution, output
|
`internal/report` owns the registry of report identities and the data declared
|
||||||
naming, artifact grouping, batch command names, and comparison declarations in
|
for each one: resolution, generation mode, prompt identity, comparison policy,
|
||||||
`internal/report`.
|
artifact group, output-copy name, default module composition, and Distributor
|
||||||
|
path declarations. The public command syntax is owned by the
|
||||||
|
[CLI reference](../cli.md); configuration aliases and overrides are owned by
|
||||||
|
the [configuration reference](../config.md).
|
||||||
|
|
||||||
## Purpose
|
## Definitions and resolution
|
||||||
|
|
||||||
`internal/report` is the canonical source for report definitions, public
|
Each `Definition` declares a stable ID and display name, prompt ID, generation
|
||||||
command names, config-key aliases, and batch command names. App, config, state,
|
mode, optional template and generated-text schema IDs, valid-period resolver,
|
||||||
module building, and CLI wiring consume report-owned helpers and resolved
|
comparison strategy, artifact group, batch-copy filename, Distributor path
|
||||||
definitions instead of owning report identity policy themselves.
|
templates, generation eligibility, compatible prior IDs, default modules, and
|
||||||
|
batch eligibility flags. `Resolved` combines that definition with the valid
|
||||||
|
period and run metadata for one invocation.
|
||||||
|
|
||||||
## Definition Fields
|
| Report ID | Mode | Period policy | Comparison | Registry batch flag | Output copy |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| `daily` | Generated text + template | Explicit local civil day | Same valid date | Dynamic Daily inclusion is app-owned | `daily.md` |
|
||||||
|
| `today` | Generated text + template | Selected or current local civil day | Same valid date | Morning | `today.md` |
|
||||||
|
| `tomorrow` | Generated text + template | Next local civil day | Same valid date | Evening | `tomorrow.md` |
|
||||||
|
| `hourly` | Generated text + template | Rolling six-hour interval | Rolling window | — | `hourly.md` |
|
||||||
|
| `three_day` | Scriptorium Markdown | Generation time through the third following local midnight | Same valid date | Morning | `three-day.md` |
|
||||||
|
| `weekend` | Scriptorium Markdown | Upcoming weekend window | Weekend window | Morning | `weekend.md` |
|
||||||
|
| `storm` | Scriptorium Markdown | Caller-supplied event window | Explicit window | — | `storm.md` |
|
||||||
|
|
||||||
Each report definition declares:
|
The four generated-text reports pair their report ID with matching template and
|
||||||
|
schema IDs. The three direct-Markdown reports leave both IDs empty. Exact
|
||||||
|
template fields and schema assets belong to [report templates](../templates.md)
|
||||||
|
and [generated-text internals](generatedtext.md).
|
||||||
|
|
||||||
- report ID and display name
|
All valid periods are half-open. Storm accepts local `YYYY-MM-DDTHH:MM` values
|
||||||
- Scriptorium prompt ID
|
in the effective report timezone or offset-bearing RFC3339 values; its end
|
||||||
- generation mode
|
must follow its start. Resolving Weekend directly on Sunday is rejected.
|
||||||
- valid-period resolver
|
|
||||||
- comparison strategy
|
|
||||||
- managed artifact group
|
|
||||||
- batch output copy filename
|
|
||||||
- generated-report eligibility
|
|
||||||
- prior-report compatibility list
|
|
||||||
- default ordered module composition
|
|
||||||
|
|
||||||
Report-owned helpers map public command names and config keys to report IDs.
|
## Registry collaborators
|
||||||
The generate command names are `daily`, `today`, `tomorrow`, `hourly`,
|
|
||||||
`three-day`, `weekend`, and `storm`. Config keys also accept selected
|
|
||||||
underscore and descriptive aliases such as `three_day_outlook`,
|
|
||||||
`weekend_outlook`, and `storm_report`.
|
|
||||||
|
|
||||||
`daily` resolves to the dated Daily Report ID `daily`. `today` resolves to the
|
`DefaultRegistry` is the only source of the seven report definitions.
|
||||||
independent Today report ID `today`. `reports.today` is not an alias for
|
`Lookup`, `Resolve`, and report-name helpers prevent callers from duplicating
|
||||||
`reports.daily`, and retired report keys are not supported.
|
report identity rules. Registry overrides clone a definition and replace its
|
||||||
|
module list only after the report ID is recognized.
|
||||||
|
|
||||||
Markdown report definitions use the `scriptorium_markdown` generation mode.
|
The definition's `DistributorPathTemplates` are internal declarations consumed
|
||||||
Their template and structured-text schema identifiers are empty. Daily Report,
|
by app orchestration. Their rendered external bundle paths and compatibility
|
||||||
Today Report, Tomorrow Report, and Hourly Report declare
|
contract are documented in the [Distributor bundle guide](../integrations/distributor/pkg-bundle.md), not repeated here.
|
||||||
`generated_text_template`; the app uses their template and schema identifiers
|
|
||||||
to validate generated text and render embedded Markdown templates.
|
|
||||||
|
|
||||||
## Reports
|
`morning` and `evening` are registry-owned batch names. Registry flags declare
|
||||||
|
fixed report eligibility; app orchestration determines data-dependent Daily
|
||||||
|
membership and produces the actual batch plan.
|
||||||
|
|
||||||
| Report | ID | Prompt | Generation mode | Artifact group | Batch copy | Prior compatibility |
|
## Module composition and failures
|
||||||
| --- | --- | --- | --- | --- | --- | --- |
|
|
||||||
| Daily Report | `daily` | `weather.daily_generated_text` | `generated_text_template` | `daily` | `daily.md` | Daily Report |
|
|
||||||
| Today Report | `today` | `weather.today_generated_text` | `generated_text_template` | `today` | `today.md` | Today Report |
|
|
||||||
| Tomorrow Report | `tomorrow` | `weather.tomorrow_generated_text` | `generated_text_template` | `tomorrow` | `tomorrow.md` | Tomorrow Report |
|
|
||||||
| Hourly Report | `hourly` | `weather.hourly_generated_text` | `generated_text_template` | `hourly` | `hourly.md` | Hourly Report |
|
|
||||||
| 3-Day Outlook | `three_day` | `weather.three_day_outlook` | `scriptorium_markdown` | `three-day` | `three-day.md` | 3-Day Outlook |
|
|
||||||
| Weekend Outlook | `weekend` | `weather.weekend_outlook` | `scriptorium_markdown` | `weekend` | `weekend.md` | Weekend Outlook |
|
|
||||||
| Storm Report | `storm` | `weather.storm_report` | `scriptorium_markdown` | `storm` | `storm.md` | Storm Report |
|
|
||||||
|
|
||||||
All report definitions are eligible for generation.
|
Each definition supplies an ordered `[]module.ConfigItem`; the complete
|
||||||
|
report-to-module mapping is maintained in [module internals](module.md).
|
||||||
|
`ArtifactGroup`, `BatchOutputName`, `Generated`, and comparison compatibility
|
||||||
|
are likewise consumed by state and orchestration rather than recomputed there.
|
||||||
|
|
||||||
## Valid Periods
|
Unknown report IDs or batch names, an invalid weekend resolution, and invalid
|
||||||
|
storm windows return errors. The registry never collects weather data, builds
|
||||||
|
modules, parses CLI flags, writes state, executes Scriptorium, or delivers a
|
||||||
|
report.
|
||||||
|
|
||||||
- Daily Report covers the selected local civil day and requires an explicit
|
## Verification and invariants
|
||||||
date.
|
|
||||||
- Today Report covers the selected local civil day, or the current local civil
|
|
||||||
day when no date override is supplied.
|
|
||||||
- Tomorrow Report covers the next local civil day from generation time.
|
|
||||||
- Hourly Report covers the half-open six-hour period from generation time in
|
|
||||||
the effective report timezone. The duration is an internal report constant,
|
|
||||||
not a configuration field.
|
|
||||||
- 3-Day Outlook covers the interval from generation time through local midnight
|
|
||||||
three days later.
|
|
||||||
- Weekend Outlook covers the upcoming weekend window.
|
|
||||||
- Storm Report covers an explicit event window supplied by the caller.
|
|
||||||
|
|
||||||
Storm event windows can be parsed from local `YYYY-MM-DDTHH:MM` timestamps in
|
Focused tests cover definition completeness, command and alias lookup, period
|
||||||
the configured timezone or RFC3339 timestamps with explicit offsets. End time
|
resolution, run IDs, path declarations, composition defaults, and override
|
||||||
must be after start time.
|
validation:
|
||||||
|
|
||||||
## Boundaries
|
```sh
|
||||||
|
go test ./internal/report
|
||||||
|
```
|
||||||
|
|
||||||
`internal/report` defines report metadata, public report names, batch command
|
All report selection goes through the registry, and the registry is the source
|
||||||
names, output naming, and time coverage. It does not collect weather data, plan
|
of truth for report identity—not rendered report text or app-local constants.
|
||||||
batch membership, build module values, compare snapshot contents, write state,
|
|
||||||
parse CLI flags, or invoke Scriptorium.
|
|
||||||
|
|
||||||
The CLI parses flags and command structure, then uses report-owned helpers for
|
|
||||||
report and batch command names. Config loading uses report-owned helpers for
|
|
||||||
report override keys.
|
|
||||||
|
|
||||||
## Config Fields Used
|
|
||||||
|
|
||||||
The app supplies `weather_api.timezone` as a loaded `time.Location`. Batch
|
|
||||||
output path copying uses batch output names from report definitions. Report
|
|
||||||
module overrides can use short keys such as `daily`, `today`, `tomorrow`, and
|
|
||||||
`hourly`, or descriptive names such as `three_day_outlook`.
|
|
||||||
|
|
||||||
## Batch Commands
|
|
||||||
|
|
||||||
`internal/report` owns the public batch command names `morning` and `evening`
|
|
||||||
and validates them through `BatchForCommandName`. Data-dependent batch
|
|
||||||
membership is owned by `internal/app`, because it depends on collected hourly
|
|
||||||
forecast coverage.
|
|
||||||
|
|
||||||
Report definitions still declare default batch output copy filenames. App
|
|
||||||
batch planning uses those filenames for fixed report entries and supplies
|
|
||||||
date-qualified names for dynamic Daily entries.
|
|
||||||
|
|
||||||
## State And App Usage
|
|
||||||
|
|
||||||
- State paths use `ArtifactGroup`.
|
|
||||||
- Batch output copies use `BatchOutputName`.
|
|
||||||
- Generation checks `Generated`.
|
|
||||||
- Module composition defaults use `Modules`.
|
|
||||||
- Prior lookup checks `CompatiblePriorIDs` and the comparison strategy.
|
|
||||||
- RunIDs include the resolved report ID.
|
|
||||||
|
|
||||||
## Failure Behavior
|
|
||||||
|
|
||||||
- Unknown report IDs and batch names return actionable errors.
|
|
||||||
- Weekend Outlook resolution returns an error when resolved directly on Sunday.
|
|
||||||
- Storm Report resolution requires start and end, with end after start.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/report/period_test.go`
|
|
||||||
- `internal/app/app_test.go`
|
|
||||||
- `internal/cli/root_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- Report selection goes through the registry.
|
|
||||||
- Public command names, config-key aliases, and batch command names are owned
|
|
||||||
by `internal/report`.
|
|
||||||
- Direct Markdown reports have empty template and generated-text schema IDs.
|
|
||||||
- Generated-text-template reports declare prompt, template, and schema IDs in
|
|
||||||
their report definition.
|
|
||||||
- Valid periods are half-open intervals independent of rendered report text.
|
|
||||||
- Artifact grouping, batch output filenames, generated-report eligibility,
|
|
||||||
default module composition, comparison compatibility, and comparison strategy
|
|
||||||
are declared by report definition.
|
|
||||||
- App-owned batch planning uses report definitions but does not live in the
|
|
||||||
report registry.
|
|
||||||
|
|||||||
@@ -1,128 +1,51 @@
|
|||||||
# Report Template Internals
|
# Report Template Internals
|
||||||
|
|
||||||
This document describes embedded Markdown templates and GeneratedText schemas
|
`internal/reporttemplate` embeds and renders the repository's native Markdown
|
||||||
in `internal/reporttemplate`.
|
templates and exposes their companion generated-text schemas. The current asset
|
||||||
|
IDs are `daily`, `today`, `tomorrow`, and `hourly`. The template files, partials,
|
||||||
|
and complete render-context field reference are maintained in
|
||||||
|
[report templates](../templates.md).
|
||||||
|
|
||||||
## Purpose
|
## Assets and lookup
|
||||||
|
|
||||||
`internal/reporttemplate` owns repository-native report templates and companion
|
The package embeds top-level templates, shared partials, and JSON schemas from
|
||||||
GeneratedText JSON schemas. The implemented template assets are Daily, Today,
|
its asset directories. `Template` and `Schema` return the requested embedded
|
||||||
Tomorrow, and Hourly.
|
asset and fail with the requested ID when it is unknown or unreadable.
|
||||||
|
|
||||||
The package embeds assets from:
|
Generated-text catalog handlers obtain schema bytes and template source through
|
||||||
|
these APIs. Prompt source files are repository assets for prompt registration;
|
||||||
|
they are not reporttemplate lookup assets. Report definitions select IDs, while
|
||||||
|
[generated-text internals](generatedtext.md) verifies the supported
|
||||||
|
schema/template pairing.
|
||||||
|
|
||||||
- `internal/reporttemplate/templates/*.md.tmpl`
|
## Rendering
|
||||||
- `internal/reporttemplate/templates/partials/*.md.tmpl`
|
|
||||||
- `internal/reporttemplate/schemas/*.schema.json`
|
|
||||||
|
|
||||||
Generated-text prompt source files live under
|
`Render` loads the top-level template, creates a `text/template` with helper
|
||||||
`internal/reporttemplate/prompts/`. They are repository assets for prompt
|
functions and `missingkey=error`, parses the template, parses every shared
|
||||||
registration, not embedded lookup APIs.
|
partial, and executes the result against the typed render context. This makes
|
||||||
|
missing context fields, bad template syntax, unreadable partials, and execution
|
||||||
|
failures actionable with template or partial context.
|
||||||
|
|
||||||
## Inputs And Outputs
|
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.
|
||||||
|
|
||||||
Inputs:
|
## Boundaries and verification
|
||||||
|
|
||||||
- template ID from a report definition
|
This package does not collect weather data, build modules, validate generated
|
||||||
- typed render context built by `internal/generatedtext`
|
text, construct contexts, resolve report definitions, write state, execute
|
||||||
|
Scriptorium, or upload reports. It produces Markdown bytes for application
|
||||||
|
orchestration to persist.
|
||||||
|
|
||||||
Outputs:
|
Focused tests cover asset lookup, schema availability, rendering, partial
|
||||||
|
behavior, missing keys, and malformed context:
|
||||||
|
|
||||||
- template source for inspection and tests
|
```sh
|
||||||
- GeneratedText schema bytes for prompt/schema configuration
|
go test ./internal/reporttemplate
|
||||||
- rendered Markdown bytes for app orchestration to persist
|
```
|
||||||
|
|
||||||
The implemented template IDs are `daily`, `today`, `tomorrow`, and `hourly`.
|
Embedded assets stay as separate files, shared fragments stay under the partial
|
||||||
The implemented schema IDs are also `daily`, `today`, `tomorrow`, and
|
directory, and generated-text schemas describe prose slots rather than
|
||||||
`hourly`, backed by matching `*.generated_text.schema.json` files.
|
deterministic weather facts.
|
||||||
|
|
||||||
Generated-text prompt sources are maintained under
|
|
||||||
`internal/reporttemplate/prompts/`, including Daily's
|
|
||||||
`daily.generated_text.md` source for prompt ID `weather.daily_generated_text`.
|
|
||||||
|
|
||||||
## Boundaries
|
|
||||||
|
|
||||||
This package owns embedded asset lookup, Go template parsing, and Markdown
|
|
||||||
template execution. It does not collect weather data, build module outputs,
|
|
||||||
validate GeneratedText, construct render contexts, choose report definitions,
|
|
||||||
write artifacts, invoke Scriptorium, or notify distributor.
|
|
||||||
|
|
||||||
GeneratedText validation is owned by `internal/generatedtext`. App
|
|
||||||
orchestration uses `internal/generatedtext` catalog lookup to connect
|
|
||||||
`internal/report` definition schema/template IDs to the matching validator,
|
|
||||||
render-context builder, and embedded assets.
|
|
||||||
|
|
||||||
## Template Contracts
|
|
||||||
|
|
||||||
Daily, Today, Tomorrow, and Hourly rendering use typed render contexts with:
|
|
||||||
|
|
||||||
- report metadata labels such as title, location, valid period, and generation
|
|
||||||
time
|
|
||||||
- validated GeneratedText prose slots
|
|
||||||
- deterministic labels derived from module outputs, including current
|
|
||||||
conditions, hourly forecast rows, precipitation timing, alerts, SPC outlooks,
|
|
||||||
forecast discussion, SPC discussion, and weather story
|
|
||||||
|
|
||||||
Daily, Today, and Tomorrow additionally expose forecast-date labels, ordered
|
|
||||||
daypart forecast rows, daily/daypart summaries, planning facts, and a
|
|
||||||
multi-paragraph forecast discussion generated-text slot. The ordered daypart
|
|
||||||
slice is built in Go so templates do not range over maps.
|
|
||||||
|
|
||||||
The Daily template asset uses the same Markdown structure as Tomorrow's
|
|
||||||
template and renders from `generatedtext.DailyRenderContext`.
|
|
||||||
|
|
||||||
Templates use `text/template` with `missingkey=error`, so missing context fields
|
|
||||||
fail rendering instead of producing incomplete Markdown.
|
|
||||||
|
|
||||||
Daily and Tomorrow call the shared `daypart_forecast` partial. Today calls
|
|
||||||
`today_daypart_forecast` so it can omit elapsed or missing dayparts. Daily,
|
|
||||||
Today, Tomorrow, and Hourly call the shared `alert_digest` and
|
|
||||||
`precipitation_timing` partials. Partial files are parsed with each top-level
|
|
||||||
template at render time and receive the same typed render context as the
|
|
||||||
caller. The `alert_digest` partial renders the combined Alerts and Risk
|
|
||||||
Products section from relevant NWS alerts and curated SPC outlook digest
|
|
||||||
records. Rendered NWS alert bullets include alert identity and timing but omit
|
|
||||||
instruction and description text. Rendered SPC outlook bullets start at
|
|
||||||
Enhanced Risk; lower-risk SPC entries may still exist in module snapshots and
|
|
||||||
data packages.
|
|
||||||
|
|
||||||
## Schema Contract
|
|
||||||
|
|
||||||
The GeneratedText schemas describe the structured prose Scriptorium is expected
|
|
||||||
to write for each generated-text prompt. Hourly requires:
|
|
||||||
|
|
||||||
- `summary`
|
|
||||||
- `forecast_discussion`
|
|
||||||
|
|
||||||
Daily, Today, and Tomorrow require `summary` and a nonempty
|
|
||||||
`forecast_discussion` array. All generated-text schemas allow optional
|
|
||||||
`precipitation_timing` and `confidence`, and reject additional properties.
|
|
||||||
Weather truth remains in module outputs; GeneratedText is limited to prose
|
|
||||||
slots consumed by the template.
|
|
||||||
|
|
||||||
## Failure Behavior
|
|
||||||
|
|
||||||
- Unknown template IDs return actionable lookup errors.
|
|
||||||
- Unknown schema IDs return actionable lookup errors.
|
|
||||||
- Template parse errors include the template ID.
|
|
||||||
- Partial read or parse errors include the partial path.
|
|
||||||
- Template execution errors include the template ID and usually identify the
|
|
||||||
missing context field.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
Inspect:
|
|
||||||
|
|
||||||
- `internal/reporttemplate/reporttemplate_test.go`
|
|
||||||
- `internal/generatedtext/render_context_test.go`
|
|
||||||
- `internal/app/app_test.go`
|
|
||||||
- `internal/cli/root_test.go`
|
|
||||||
|
|
||||||
## Invariants
|
|
||||||
|
|
||||||
- Embedded templates and schemas live as separate files, not inline Go strings.
|
|
||||||
- Shared Markdown partials live under `templates/partials/`.
|
|
||||||
- Report definitions select templates by ID.
|
|
||||||
- Templates render from curated render contexts, not raw data packages.
|
|
||||||
- GeneratedText schemas describe LLM prose slots, not deterministic weather
|
|
||||||
facts.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user