From 1ddd88231aa877b4cb73f5017dba168d6e82fc95 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Tue, 9 Jun 2026 21:42:38 +0000 Subject: [PATCH] Clarify module package documentation --- docs/cli.md | 12 ++--- docs/config.md | 15 +++--- docs/integrations/weatherapi.md | 5 +- docs/internal/app-orchestration.md | 8 +-- docs/internal/briefing.md | 75 ++++++++++++++------------ docs/internal/changes.md | 3 +- docs/internal/facts.md | 2 +- docs/internal/module.md | 84 +++++++++++++++++++++++------- docs/internal/prompt-input.md | 63 +++++++++++++++------- docs/internal/report-registry.md | 12 ++--- docs/internal/state.md | 4 +- docs/operations.md | 28 +++++----- 12 files changed, 197 insertions(+), 114 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index d50cab3..1dfba72 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,7 +1,7 @@ # Weatherreporter CLI `weatherreporter` generates Markdown weather reports, runs scheduled report -batches, and inspects previously generated artifacts. +batches, and inspects stored artifacts. ## Shortest Useful Command @@ -34,11 +34,11 @@ weatherreporter inspect prior [--config PATH] RUN_ID weatherreporter inspect sources [--config PATH] RUN_ID ``` -`generate` commands write module snapshot, data package, preflight, -report, and metadata artifacts under the configured workspace. `--out` writes -an extra Markdown copy for the operator; distributor notification uses the -managed report path, not the extra copy. `generate storm` requires explicit -event-window bounds with `--start` and `--end`. +`generate` commands write a JSON module snapshot, YAML data package, preflight +artifact, managed Markdown report, and metadata under the configured workspace. +`--out` writes an extra Markdown copy for the operator; distributor +notification uses the managed report path, not the extra copy. `generate storm` +requires explicit event-window bounds with `--start` and `--end`. `run morning` generates Daily Today and the 3-Day Outlook, plus Weekend Outlook except on Sunday. `run evening` generates the Tomorrow Planning Brief. Batch diff --git a/docs/config.md b/docs/config.md index 88196cf..1fb05a3 100644 --- a/docs/config.md +++ b/docs/config.md @@ -16,9 +16,9 @@ Precedence is: 2. configuration file 3. built-in defaults -The implemented configuration overrides are `--units` and `--tz`. Output flags -control report copies for the current command but do not change configuration -files. Environment variables do not override configuration fields. +The CLI configuration overrides are `--units` and `--tz`. Output flags control +report copies for the current command but do not change configuration files. +Environment variables do not override configuration fields. ## Minimal Config @@ -177,8 +177,7 @@ snapshot exists and a threshold is crossed. ### `reports` `reports` optionally overrides the ordered deterministic modules declared by -built-in report definitions. Omit a report entry to use its built-in module -order. +report definitions. Omit a report entry to use its default module order. Supported report keys are `daily`, `tomorrow`, `three_day`, `weekend`, and `storm`. Canonical report IDs such as `daily_today` and `daily_tomorrow` are @@ -209,6 +208,10 @@ combinations, duplicate stanza names, and invalid options fail config loading. `key_messages`, `short_term`, and `long_term`. Empty or omitted `sections` includes all available AFD sections. +The module registry accepts all module IDs documented in +[Module Contract Internals](internal/module.md). Modules without builders are +valid in composition but do not emit YAML stanzas. + ## Secrets Configuration files should not contain raw secrets. Use `secrets.directory` to @@ -224,6 +227,6 @@ notification, this allows a file such as - [examples/minimal-config.yml](../examples/minimal-config.yml): smallest useful config for generation and fetching. - [examples/config.yml](../examples/config.yml): production-oriented config - covering implemented fields. + covering maintained fields. Both example files are loaded by the config test suite. diff --git a/docs/integrations/weatherapi.md b/docs/integrations/weatherapi.md index 27afda5..50a4fca 100644 --- a/docs/integrations/weatherapi.md +++ b/docs/integrations/weatherapi.md @@ -6,7 +6,7 @@ This document describes the external Weather API contract used by ## Purpose `weatherreporter` uses a configured Weather API base URL to fetch normalized -weather source data and assemble a `forecast.Bundle`. This is an integration +weather source data and assemble a `weatherdata.Bundle`. This is an integration contract for the project adapter, not a complete public API reference for the upstream service. @@ -45,8 +45,7 @@ they fail the fetch; optional malformed sources follow the missing-source policy The adapter sends these query parameters: -- `format`: from `weather_api.format`; the implemented configuration requires - `json` +- `format`: from `weather_api.format`; configuration validation requires `json` - `units`: from `weather_api.units` - `precision`: from `weather_api.precision` on observations, current conditions, hourly forecast, and narrative forecast requests diff --git a/docs/internal/app-orchestration.md b/docs/internal/app-orchestration.md index 3f9d93a..eb048ff 100644 --- a/docs/internal/app-orchestration.md +++ b/docs/internal/app-orchestration.md @@ -1,6 +1,6 @@ # App Orchestration Internals -This document describes the implemented workflow coordinator in `internal/app`. +This document describes the workflow coordinator in `internal/app`. ## Purpose @@ -26,9 +26,9 @@ Inputs: Outputs: -- generated report results with module snapshot, data package, preflight, report, - metadata, prior snapshot, Recent Changes, Scriptorium result details, and - notification result when attempted +- generated report results with JSON module snapshot, YAML data package, + preflight, report, metadata, prior snapshot, Recent Changes, Scriptorium + result details, and notification result when attempted - batch summaries with per-report status, artifact paths, error text, and notification outcome when attempted - saved Weather API bundle JSON for fetch workflows diff --git a/docs/internal/briefing.md b/docs/internal/briefing.md index 637b47d..df69c72 100644 --- a/docs/internal/briefing.md +++ b/docs/internal/briefing.md @@ -1,49 +1,60 @@ # Module Builder Internals -This document describes the implemented module builder boundary in -`internal/briefing`. +This document describes module builder behavior in `internal/briefing`. ## Purpose -`internal/briefing` builds prompt-facing module values from resolved report -metadata, collected weather data, and derived forecast facts. These values are -curated prompt inputs, not rendered report prose or durable report snapshots. +`internal/briefing` turns report metadata, collected weather data, and derived +forecast facts into prompt-facing module outputs. The package also owns the +module registry used to validate report composition and config overrides. + +Module outputs are structured prompt inputs. They are not rendered report prose +and they are not persisted by this package. ## Inputs And Outputs Inputs: - resolved report definition, generation time, timezone, and valid period -- `weatherdata.Bundle` with source provenance and warnings -- derived daily, period, or storm-window facts where required +- 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: -- module registry definitions for known module IDs, stanza names, option - shapes, fact requirements, report compatibility, and missing-data behavior -- source-oriented module outputs for `metadata`, `current_conditions`, - `alert_digest`, `area_forecast_discussion`, and `weather_story` -- derived module outputs such as daily summaries, daypart summaries, - precipitation timing, outdoor windows, and tomorrow planning -- optional current conditions and weather story module outputs when those - Weather API sources are available +- `ModuleDefinition` values with module ID, stanza name, option type, + supported reports, fact requirements, missing-data behavior, and builder +- `module.Output` values for source-oriented stanzas: + `metadata`, `current_conditions`, `alert_digest`, + `area_forecast_discussion`, and `weather_story` +- `module.Output` values for derived stanzas: + `derived_daily_summary`, `derived_daypart_summaries`, `precip_timing`, + `outdoor_windows`, and `tomorrow_planning` + +The registry also contains accepted composition entries for modules that do not +emit stanzas until a builder exists. App orchestration skips those entries when +constructing snapshots. ## Boundaries -- This package selects and shapes weather facts for prompts. -- It owns module registry validation and module builder behavior. -- It does not fetch weather data, compare prior snapshots, build - `data_package` files, invoke Scriptorium, or write workflow metadata. +- This package selects and shapes already-collected weather facts for prompts. +- It validates module composition against report compatibility and option + types. +- It does not fetch weather data, compare prior snapshots, write module + snapshots, build YAML data packages, invoke Scriptorium, or write workflow + metadata. ## Config Fields Used -The package receives configured units and timezone from the app layer. Daypart -configuration is consumed by `internal/facts` before module builders run. -Configured `location` values are prompt context only; Weather API +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. -Current conditions are copied from the normalized `/conditions/current` bundle -source only; observation station and timestamp fields remain provenance. + +`area_forecast_discussion` uses optional `sections` configuration to include a +subset of discussion fields. ## External Adapters Used @@ -51,13 +62,13 @@ None directly. ## State Or Manifest Behavior -None. Module snapshots and prompt input data packages are persisted by -`internal/state` and composed by `internal/app`. +None. `internal/app` collects module outputs into a `module.Snapshot`, and +`internal/state` persists that snapshot. ## Skip And Resume Behavior -None. Builders either return a module output, omit optional unavailable data, -or return an error for invalid required inputs. +None. Builders either emit a module output, omit optional unavailable data, or +return an error for invalid required inputs. ## Failure Behavior @@ -65,8 +76,9 @@ or return an error for invalid required inputs. available. - Module registry construction rejects duplicate module IDs and duplicate stanza names. -- Module composition validation rejects unknown modules, duplicate modules, - incompatible report/module combinations, and invalid typed options. +- 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 @@ -86,5 +98,4 @@ Inspect: - 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. -- LLM prompt input packaging and Scriptorium execution remain outside this - boundary. +- Prompt input packaging and Scriptorium execution remain outside this package. diff --git a/docs/internal/changes.md b/docs/internal/changes.md index cc48614..9c1dc76 100644 --- a/docs/internal/changes.md +++ b/docs/internal/changes.md @@ -56,8 +56,7 @@ empty Recent Changes list without calling a comparison function. `precip_timing` when present. - 3-Day comparison requires `derived_daypart_summaries`. - Weekend comparison requires `derived_daypart_summaries`. -- Storm Report currently has no comparison implementation, so the app leaves - Recent Changes empty for Storm reports. +- Storm Report comparison returns no changes. ## Tests diff --git a/docs/internal/facts.md b/docs/internal/facts.md index 3064caf..834d477 100644 --- a/docs/internal/facts.md +++ b/docs/internal/facts.md @@ -1,6 +1,6 @@ # Fact Contracts Internals -This document describes the implemented fact contract boundary. +This document describes the fact contract boundary. ## Purpose diff --git a/docs/internal/module.md b/docs/internal/module.md index f7d619e..79920a7 100644 --- a/docs/internal/module.md +++ b/docs/internal/module.md @@ -1,46 +1,90 @@ # Module Contract Internals -This document describes the implemented module contract boundary. +This document describes the module contract in `internal/module`. ## Purpose -`internal/module` defines stable module IDs, typed configuration items, module -outputs, and module snapshots. It is a shared contract imported by report -definitions and module registry code. +`internal/module` defines the shared identifiers and data envelopes used for +prompt-facing modules. Report definitions use module IDs for composition, +module builders produce outputs with stanza names, prompt input packages consume +snapshots, and Recent Changes compares snapshot stanzas. ## Inputs And Outputs Inputs: -- ordered `module.ConfigItem` values from report definitions -- `module.Output` values assembled by callers +- ordered `module.ConfigItem` values from report definitions or config + overrides +- `module.Output` values produced by module builders Outputs: - stable `module.ID` constants -- typed option structs for known modules -- `module.Snapshot` with ordered outputs and schema version +- 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 - typed stanza lookup through `module.StanzaValue` +## Registered Module IDs + +The registry recognizes these IDs: + +- `metadata` +- `current_conditions` +- `derived_daily_summary` +- `derived_daypart_summaries` +- `hourly_table` +- `precip_timing` +- `alert_digest` +- `area_forecast_discussion` +- `weather_story` +- `forecast_delta` +- `outdoor_windows` +- `tomorrow_planning` +- `weekend_planning` +- `storm_window_summary` + +Modules with builders emit stanzas into module snapshots. Registered modules +without builders are valid composition entries but do not emit snapshot stanzas. +That keeps report composition declarations centralized while limiting prompt +packages to data the application builds. + +## Options + +Most modules use an empty options struct. `area_forecast_discussion` accepts: + +```yaml +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. + ## Boundaries -- This package owns shared module identifiers and output envelope contracts. -- It does not define report IDs, build prompt stanzas, fetch weather data, - derive facts, write state, or invoke Scriptorium. +- 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` uses schema version `weatherreporter.modules.v1`. Snapshot -validation rejects duplicate module outputs and duplicate stanza names while -preserving output order. +`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. ## Failure Behavior -- Snapshot validation fails when schema version, module ID, or stanza name is - missing. -- Snapshot validation fails on duplicate module IDs or duplicate stanza names. -- Typed stanza lookup returns `found=false` for missing stanzas and wraps JSON - marshal/decode failures with stanza context. +- 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 @@ -54,5 +98,5 @@ Inspect: - `internal/module` does not import `internal/report`. - Module IDs are stable strings. -- Each module output has exactly one stanza name and one typed value. +- Each emitted module output has exactly one stanza name and one typed value. - Snapshot output order is caller-owned and preserved. diff --git a/docs/internal/prompt-input.md b/docs/internal/prompt-input.md index 69d5924..4e3bb5f 100644 --- a/docs/internal/prompt-input.md +++ b/docs/internal/prompt-input.md @@ -1,38 +1,63 @@ # Prompt Input Internals -This document describes prompt input data package construction. +This document describes YAML prompt data package construction in +`internal/promptinput`. ## Purpose -`internal/promptinput` converts report metadata, module snapshots, and optional -Recent Changes into the YAML `data_package` passed to Scriptorium prompts. +`internal/promptinput` converts report metadata, an ordered module snapshot, +Recent Changes, and source warnings into the `data_package` file passed to +Scriptorium. + +The persisted data package is YAML with schema version +`weatherreporter.data_package.v2`. It is separate from the JSON module snapshot +used for inspection and comparison. ## Inputs And Outputs Inputs: -- report metadata +- report metadata from app/state orchestration - `module.Snapshot` - optional `[]changes.Change` Outputs: -- `promptinput.Package` containing schema version, RunID, report metadata, - named module stanzas under `briefing`, Recent Changes, and source warnings. -- report metadata includes `currentLocalDate`, the generation date formatted as - `YYYY-MM-DD` in the effective report timezone. -- optional YAML file written by `promptinput.Save` +- `promptinput.Package` with schema version, RunID, report metadata, named + module stanzas, Recent Changes, and source warnings +- YAML bytes from `promptinput.MarshalYAML` +- YAML file written atomically by `promptinput.Save` + +The YAML shape includes: + +```yaml +schema_version: weatherreporter.data_package.v2 +run_id: +report: + id: + prompt_id: +briefing: + metadata: {} + current_conditions: {} +recent_changes: + items: [] +``` + +The `briefing` mapping contains named module stanzas. Stanza order follows the +module snapshot output order. ## Boundaries -- This package owns the prompt input schema and validation. -- It does not fetch weather data, derive forecast summaries, find prior - snapshots, compare changes, or invoke Scriptorium. +- This package owns prompt package schema, YAML marshaling, YAML loading, and + validation. +- It does not fetch weather data, derive forecast summaries, execute modules, + find prior snapshots, compare changes, choose artifact paths, or invoke + Scriptorium. ## Config Fields Used -None directly. Config-derived values, including timezone and prompt location -context, are already present in report metadata and module stanzas before this +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 @@ -51,8 +76,9 @@ 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, or when no named module stanzas are present. Save -failures include filesystem operation and path context. +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 @@ -63,6 +89,7 @@ Inspect: ## Invariants -- Scriptorium receives structured `data_package` YAML. +- Scriptorium receives structured YAML through `--input data_package=`. - Module stanza order is deterministic for generated snapshots. -- Recent Changes are not inferred from rendered report text. +- Recent Changes are provided by `internal/changes`; this package does not + infer changes from rendered report text. diff --git a/docs/internal/report-registry.md b/docs/internal/report-registry.md index c5645bd..aef7c1f 100644 --- a/docs/internal/report-registry.md +++ b/docs/internal/report-registry.md @@ -7,8 +7,8 @@ membership, output naming, artifact grouping, and comparison declarations in ## Purpose `internal/report` is the canonical source for report definitions. App, state, -module building, and CLI wiring consume resolved definitions instead of owning report -identity policy themselves. +module building, and CLI wiring consume resolved definitions instead of owning +report identity policy themselves. ## Definition Fields @@ -25,7 +25,7 @@ Each report definition declares: - morning or evening batch membership - default ordered module composition -## Implemented Reports +## Reports | Report | ID | Prompt | Artifact group | Batch copy | Prior compatibility | | --- | --- | --- | --- | --- | --- | @@ -35,7 +35,7 @@ Each report definition declares: | Weekend Outlook | `weekend` | `weather.weekend_outlook` | `weekend` | `weekend.md` | Weekend Outlook | | Storm Report | `storm` | `weather.storm_report` | `storm` | `storm.md` | Storm Report | -All implemented report definitions are eligible for generation. +All report definitions are eligible for generation. ## Valid Periods @@ -55,8 +55,8 @@ must be after start time. ## Boundaries `internal/report` defines report metadata and time coverage. It does not fetch -weather data, build module values, compare snapshot contents, write state, parse CLI -flags, or invoke Scriptorium. +weather data, build module values, compare snapshot contents, write state, +parse CLI flags, or invoke Scriptorium. The CLI owns public command names. The app maps those command names to report IDs, then uses the registry for report policy. diff --git a/docs/internal/state.md b/docs/internal/state.md index 7fe6054..ebd94af 100644 --- a/docs/internal/state.md +++ b/docs/internal/state.md @@ -84,8 +84,8 @@ current report definition. date. - Weekend Outlook compares with prior Weekend snapshots for the same weekend window. -- Storm Report currently has no prior lookup because explicit event-window - comparison is not searched by the filesystem store. +- Storm Report has no prior lookup because explicit event-window comparison is + not searched by the filesystem store. ## Writes And Inspection diff --git a/docs/operations.md b/docs/operations.md index 25afb43..96665e2 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -1,12 +1,12 @@ # Weatherreporter Operations This guide covers normal operation, generated artifacts, inspection, recovery, -and current operational caveats. For symptom-specific diagnosis, see +and operational caveats. For symptom-specific diagnosis, see [Troubleshooting](troubleshooting.md). ## Normal Workflow -Implemented generation commands: +Generation commands: ```text weatherreporter generate daily --date 2026-05-29 @@ -16,16 +16,16 @@ weatherreporter generate weekend weatherreporter generate storm --start 2026-05-29T18:00 --end 2026-05-30T06:00 ``` -Each command resolves a report period, fetches a Weather API bundle, builds -module snapshots, builds a YAML prompt input data package, runs -`scriptorium render`, runs `scriptorium run`, and writes managed artifacts -under the configured workspace. +Each command resolves a report period, fetches a Weather API bundle, builds a +JSON module snapshot, builds a YAML prompt input data package, runs +`scriptorium render`, runs `scriptorium run`, and writes managed artifacts under +the configured workspace. When distributor notification is enabled, weatherreporter uploads the managed Markdown report after `scriptorium run` succeeds and final metadata is saved. `--out PATH` writes an extra Markdown copy for the current generated report; it is not used as the distributor upload source. -Implemented batch commands: +Batch commands: ```text weatherreporter run morning @@ -186,7 +186,7 @@ constructing a source bundle, and submitting it to the configured distributor HTTP endpoint. Distributor remains responsible for destination routing, publication, and any downstream Markdown-to-HTML transformation. Distributor leaves destination files alone when they are not tracked by a newly uploaded -bundle, so previously uploaded dated report paths can remain available. +bundle, so existing uploaded dated report paths can remain available. ## Inspection @@ -202,12 +202,12 @@ weatherreporter inspect prior RUN_ID weatherreporter inspect sources RUN_ID ``` -Use `inspect reports` to find recent RunIDs and artifact paths. Use +Use `inspect reports` to find RunIDs and artifact paths. Use `inspect metadata` to see the artifact links recorded for a run. Use `inspect modules` to review the persisted ordered module snapshot, and -`inspect data-package` to review the current structured prompt package used for -rendering. Use `inspect prior` to see the prior comparable snapshot selected -for Recent Changes, or `null` when none exists. Use `inspect sources` to review +`inspect data-package` to review the structured prompt package used for +rendering. Use `inspect prior` to see the prior comparable snapshot selected for +Recent Changes, or `null` when none exists. Use `inspect sources` to review source provenance and warnings without dumping full weather payloads. ## Recent Changes @@ -218,8 +218,8 @@ Markdown or YAML text. Daily Today and Daily Tomorrow can compare with each other when they cover the same valid local date. 3-Day Outlook compares with prior compatible 3-Day snapshots for the same valid local date. Weekend Outlook compares with prior -compatible Weekend snapshots for the same weekend window. Storm Report currently -leaves Recent Changes empty. +compatible Weekend snapshots for the same weekend window. Storm Report leaves +Recent Changes empty. When no prior comparable snapshot exists, or no configured threshold is crossed, `recentChanges.items` is empty.