diff --git a/docs/roadmap/data-package-exports.md b/docs/roadmap/data-package-exports.md new file mode 100644 index 0000000..db42745 --- /dev/null +++ b/docs/roadmap/data-package-exports.md @@ -0,0 +1,360 @@ +# Data Package Export Roadmap + +## Purpose + +This roadmap defines the target state for cleaning up module fields exposed in +YAML data packages. The goal is to keep report templates composable while making +LLM prompt inputs concise, readable, and free of template-only helper fields. + +This feature is not implemented yet. Current data-package behavior remains +documented outside `docs/roadmap/`. + +## Problem + +Module output structs currently serve two different consumers: + +- deterministic report templates, which benefit from presentation helpers such + as lower-case text, display labels, trend phrases, and hour labels; +- Scriptorium data packages, which should expose the clearest useful weather + facts to the LLM with minimal redundancy. + +Those consumers now need different surfaces. Examples include: + +- `current_conditions` exposes both `condition_text` and + `condition_text_lower`, plus both abbreviated and long-form wind-direction + fields. +- `hourly_forecast.periods[]` exposes both `period_begins` and `hour_label`, + and both `text_description` and `text_description_lower`. +- `derived_daypart_summaries` exposes numerous temperature and condition phrase + fields that are useful for deterministic template wording but noisy in the + prompt data package. + +The cleanup should not weaken template composability. Templates should still be +able to use rich module values and helper fields. + +The cleanup applies to every report that consumes these modules, including the +generated-template `today`, `tomorrow`, and `daily` reports. The same +`derived_daypart_summaries` prompt export should serve all three reports while +their templates continue to use rich daypart helper fields. + +## Intent + +Data packages should be curated prompt inputs, not a raw dump of every field +available to Go templates. + +The intended architecture is: + +- module builders produce rich internal/template module values; +- each module may define a prompt-facing export value for data-package use; +- prompt input construction serializes the prompt-facing export value; +- template rendering continues to use the full rich module value. + +The result should let `weatherreporter` optimize separately for: + +- precise deterministic Markdown rendering; +- compact, readable LLM input; +- stable internal module contracts. + +## Locked Decisions + +- Do not make the existing module structs smaller solely to clean up data + packages. +- Do not use per-module string field allowlists as the primary mechanism. +- Do not rely on reflection-heavy field filtering for nested module shapes. +- Do not use `json:"-"` or `yaml:"-"` on rich template fields as the main + boundary. +- Keep rich module outputs available for template rendering, inspection, tests, + and internal use. +- Add an explicit prompt/data-package export layer for module outputs. +- Simple modules may use default pass-through export behavior. +- No compatibility aliases are needed for removed prompt-facing fields because + the prompt schema is still pre-release. +- Bump the data-package schema version when implementing this change. +- Compute prompt export values during module snapshot construction and store the + runtime-only prompt value on `module.Output` alongside the rich `Value`. +- Do not persist prompt export values in module snapshot JSON; module snapshots + should continue to preserve rich module values. + +## Target Architecture + +Each module definition should be able to declare how its output is represented +in prompt data packages. + +A possible shape is: + +```go +type ModuleDefinition struct { + // existing fields... + PromptExporter ModulePromptExporter +} + +type ModulePromptExporter func(value any) (any, error) +``` + +The exact API may differ if implementation discovers a cleaner fit, but the +contract should preserve these properties: + +- the exporter is owned near the module definition or module builder; +- the exporter receives the rich module value and returns a prompt-facing value; +- missing exporters default to pass-through for modules whose rich value is + already prompt-appropriate; +- exporter errors include module ID and stanza context; +- promptinput uses exported prompt values instead of rich values; +- render contexts and templates continue using rich values. + +The preferred implementation should avoid making `internal/promptinput` import +`internal/briefing` directly. If prompt export needs registry knowledge, either: + +- record the prompt-facing value in `module.Output` when the module snapshot is + built; or +- pass an explicit export map/registry into prompt-input construction without + creating a package cycle. + +The implementation should keep package boundaries consistent with existing +architecture: module output policy belongs with module definitions, and data +package serialization belongs in `internal/promptinput`. + +## Prompt Export Contract + +A module prompt export should be: + +- **curated:** include fields useful to the LLM, omit fields used only for + deterministic sentence construction; +- **typed:** use small prompt-facing structs for modules that need reshaping; +- **stable:** keep field names intentional and avoid duplicating equivalent + facts under multiple names; +- **readable:** prefer fields that explain themselves in YAML; +- **loss-aware:** do not omit facts that the LLM needs to reason about timing, + severity, uncertainty, or practical impact; +- **module-owned:** keep each module responsible for its own prompt-facing + contract. + +Prompt-facing structs may live next to the module that owns them, for example: + +```go +type CurrentConditionsPromptExport struct { + ConditionText string `json:"condition_text,omitempty"` + TemperatureF *int `json:"temperature_f,omitempty"` + ApparentTemperatureF *int `json:"apparent_temperature_f,omitempty"` + RelativeHumidityPercent *int `json:"relative_humidity_percent,omitempty"` + WindSpeedMph *int `json:"wind_speed_mph,omitempty"` + WindDirection string `json:"wind_direction,omitempty"` +} +``` + +The names do not need to include `PromptExport` if implementation finds a +clearer convention, but they should distinguish data-package shape from +template-rendering shape. + +## Initial Cleanup Targets + +### Current Conditions + +Keep prompt-facing fields that express current observed conditions directly: + +- `condition_text` +- `is_day` +- temperature fields +- apparent temperature fields +- dewpoint fields +- relative humidity +- wind speed +- one wind direction field + +Remove prompt-facing fields that are template-only duplicates: + +- `condition_text_lower` +- duplicate wind-direction text when an equivalent `wind_direction` field is + present + +The template surface may keep those helper fields. + +### Hourly Forecast + +Keep prompt-facing period fields that carry facts: + +- `period_begins` +- `period_ends` +- `name` +- `is_day` +- condition code, if useful +- `text_description` +- temperature fields +- dewpoint, apparent temperature, humidity, wind, gust, pressure, visibility, + cloud cover, precipitation probability, precipitation amount, snowfall depth, + and UV index when provided by upstream data + +Remove prompt-facing fields that duplicate or encode template logic: + +- `hour_label`, because `period_begins` already gives the time in a friendly + local label; +- `text_description_lower`, because the LLM can interpret + `text_description`; +- `mention_precipitation`, because it is a template threshold helper when the + underlying precipitation probability is present. + +The template surface may keep these helper fields. + +### Derived Daypart Summaries + +Keep prompt-facing fields that describe the daypart: + +- `date` +- `display_name` +- `period_begins` +- `period_ends` +- temperature range or the best single temperature phrase +- apparent temperature range when useful +- maximum precipitation probability and time +- maximum wind gust and time +- dominant condition +- temperature trend +- notable conditions +- weather indicator booleans +- relevant alert count + +Remove prompt-facing fields that mainly support deterministic sentence +construction: + +- duplicate lower-case/display variants of the same dominant condition; +- multiple temperature phrase fragments when a smaller set can express the same + trend; +- duplicate time labels where one friendly time field is enough. + +The exact retained daypart temperature fields should be chosen during +implementation with template needs and LLM readability in mind. The prompt +export should preserve the facts needed to understand whether temperatures are +rising, falling, peaking, or steady, but it does not need every phrase fragment +used by the Markdown template. + +### Other Modules + +Most existing modules may initially use pass-through export unless they expose +clear template-only helpers. During implementation, review at least: + +- `narrative_forecast` +- `precip_timing` +- `outdoor_windows` +- `alert_digest` +- `spc_convective_outlooks` +- `spc_convective_discussion` +- `area_forecast_discussion` +- `weather_story` +- planning modules + +Do not remove fields merely because they are verbose. Remove or reshape fields +when they are redundant, template-specific, or confusing in the context of LLM +input. + +## Data Package Behavior + +After implementation: + +- saved YAML data packages should use prompt-facing module exports; +- saved module snapshots should continue preserving rich module output values; +- generated-text render contexts should continue preserving rich module values; +- Recent Changes should continue using structured module snapshots unless a + specific comparison should intentionally move to prompt-facing fields; +- inspection commands should make clear whether they are showing rich module + snapshots or prompt data packages. +- generated-template reports, including `today`, `tomorrow`, and `daily`, should + continue rendering from rich module values. + +This roadmap does not require changing source warnings, report metadata, +collected facts, derived facts, or generated report artifacts. + +## Schema And Versioning + +This is a prompt-input schema cleanup. Because the project is pre-release, the +implementation may make a clean break in data-package field names without +compatibility aliases. + +The data-package schema version should be bumped when this feature is +implemented because persisted data-package fields will be removed or renamed. +This makes artifact shape changes explicit and helps inspection tooling +distinguish old and new data packages. + +## Documentation Guidance + +After implementation, update implemented documentation only: + +- `docs/internal/module.md`: describe the distinction between rich module output + and prompt-facing export values. +- `docs/internal/prompt-input.md`: document that data packages use curated + prompt exports, not full template module structs. +- `docs/templates.md`: clarify that templates may have richer fields than the + data package. +- Any module field examples in implemented docs should match the new + prompt-facing data package shape. + +Do not document future module fields or unimplemented exporters outside +`docs/roadmap/`. + +## Acceptance Criteria + +The feature is complete when: + +- prompt data packages serialize curated module exports instead of blindly + serializing rich module values; +- templates still render from rich module values without losing helper fields; +- `current_conditions` no longer exposes lower-case condition text or duplicate + wind-direction fields in data packages; +- `hourly_forecast.periods[]` no longer exposes `hour_label`, + `text_description_lower`, or `mention_precipitation` in data packages; +- `derived_daypart_summaries` no longer exposes redundant condition and + temperature phrase variants in data packages; +- `today`, `tomorrow`, and `daily` rendered reports continue to have access to + rich daypart helper fields for deterministic template wording; +- simple modules that do not need cleanup still export correctly through default + pass-through behavior; +- exporter errors include module/stanza context; +- YAML category ordering remains unchanged; +- module snapshot artifacts remain rich enough for templates, inspection, and + regression diagnosis; +- tests prove that removed prompt-facing fields are absent from saved YAML data + packages and still available to templates where needed. + +## Testing Expectations + +Implementation should add or update focused tests for: + +- module registry validation for prompt exporters, if exporters are registered + there; +- promptinput construction using exported prompt values; +- pass-through behavior for simple modules; +- custom exports for current conditions, hourly forecast, and daypart summaries; +- data-package YAML output rejecting stale fields; +- template render tests proving template-only helper fields remain available for + `today`, `tomorrow`, and `daily`; +- app workflow tests proving saved data packages use curated exports while + render contexts keep rich values. + +Suggested validation after implementation: + +```sh +go test ./internal/module ./internal/briefing ./internal/promptinput +go test ./internal/generatedtext ./internal/reporttemplate ./internal/app +go test ./... +go run ./cmd/weatherreporter --help +git diff --check +``` + +## Deferred Work + +Do not include these in the initial cleanup unless implementation reveals they +are necessary: + +- user-configurable data-package field selection; +- per-prompt custom field profiles; +- reflection-based generic include/exclude lists; +- automatic schema generation for data-package exports; +- changing collected facts or derived facts contracts; +- changing Scriptorium invocation behavior; +- changing generated Markdown templates beyond preserving their current output. + +## Open Questions + +No open questions block implementation. + +The implementation plan in `docs/roadmap/implementation.md` is the sequencing +authority for this feature. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 087485e..e4087fd 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,690 +1,657 @@ -# Daily Report Implementation Roadmap +# Data Package Export Implementation Roadmap ## Purpose This roadmap defines the staged implementation plan for -`docs/roadmap/daily.md`. It is written for an LLM coding agent that will -implement the new generated-text-template `daily` report in order. +`docs/roadmap/data-package-exports.md`. It is written for an LLM coding agent +that will implement the curated data-package export feature in order. -The target feature is a clean replacement of the existing active Daily path: -`weatherreporter generate daily` should run a new independent `daily` report -that requires `--date YYYY-MM-DD`, uses generated structured text plus a -Markdown template, and initially renders the same report shape as `tomorrow`. +The goal is to separate rich module values used by templates from curated +prompt-facing values serialized into Scriptorium data packages. The change +should make YAML data packages smaller and clearer without reducing deterministic +template composability. -This file is planning-only. Non-roadmap documentation should be updated only in -the implementation stage after the behavior exists. +This is a planning document only. It may describe unimplemented behavior because +it lives under `docs/roadmap/`. ## Source Roadmap -Use `docs/roadmap/daily.md` as the feature roadmap and source of user intent. -That document defines the target state, report identity, command behavior, -module composition, generated-text contract, and replacement policy for the -legacy `daily_today` report. +Use `docs/roadmap/data-package-exports.md` as the feature roadmap and target +state authority. That document defines the user intent, module/export boundary, +initial cleanup targets, and non-goals. + +If this implementation plan and the feature roadmap conflict, update the feature +roadmap first so it remains the conceptual source of truth, then update this +file. ## Locked Decisions -- `daily` is a separate report ID, not an alias for `today`, `tomorrow`, or - legacy `daily_today`. -- `weatherreporter generate daily` remains the public command, but it must run - the new generated-text-template Daily report. -- `weatherreporter generate daily` requires `--date YYYY-MM-DD`. -- The supplied date is interpreted as a local civil date in the effective - report timezone after config and `--tz` overrides. -- The valid period is `[00:00, next 00:00)` for the selected local civil day. -- Daily is manually targeted and is not added to morning or evening batches. -- Daily uses prompt ID `weather.daily_generated_text`. -- Daily uses template ID `daily` and generated-text schema ID `daily`. -- Daily uses artifact group `daily` and batch output name `daily.md`. -- Daily has its own generated-text type, schema, prompt asset, Markdown - template, render-context type, and planning module. -- Daily may share private helpers with Tomorrow when mechanics are identical, - but it must not expose Tomorrow-specific public types or stanzas. -- Remove active `daily_today` report definition and `reports.daily_today` - config-key support. -- Historical workspace artifacts with `daily_today` metadata are not migrated. +- Keep rich module values available for templates, module snapshots, inspection, + Recent Changes, and render contexts. +- Serialize curated prompt-facing module values into data packages. +- Store prompt-facing values on `module.Output` as runtime-only values. +- Do not persist prompt-facing values in module snapshot JSON. +- Keep `internal/promptinput` independent from `internal/briefing`. +- Add prompt export behavior to the module registry/definition path where module + output policy already lives. +- Default modules without custom exporters to pass-through prompt values. +- Bump the data-package schema version from `weatherreporter.data_package.v2` to + `weatherreporter.data_package.v3`. +- No compatibility aliases are required for removed prompt-facing fields. +- Do not add user-configurable field selection, field allowlists, reflection + filters, or prompt-specific field profiles in this implementation. ## Implementation Principles -- Preserve public CLI syntax except for the intentional breaking change that - `generate daily` now requires `--date`. -- Keep report identity, prompt IDs, generation mode, module order, artifact - groups, batch membership, and compatibility policy centralized in - `internal/report`. -- Keep CLI parsing in `internal/cli`; enforce the missing-date policy in both - CLI parsing and the report resolver so non-CLI callers cannot accidentally - generate an undated Daily report. -- Keep generated-text schema validation in `internal/generatedtext`. -- Keep embedded schemas, prompts, and templates as separate files under - `internal/reporttemplate`. -- Keep deterministic module output in `internal/briefing` and module IDs/options - in `internal/module`. -- Do not add compatibility aliases for `daily_today`. -- Update implemented documentation only after the code behavior exists. +- Preserve existing generated Markdown output. +- Preserve existing template render-context richness. +- Preserve existing module snapshot richness and JSON shape except for any + unavoidable schema-version-only change. The preferred approach is to omit + prompt values from module snapshot JSON entirely. +- Keep exporter code near the module that owns the shape. +- Use typed prompt-facing structs for modules that need reshaping. +- Keep simple modules on default pass-through behavior. +- Make exporter errors actionable and include module ID/stanza context. +- Keep YAML category ordering unchanged. +- Treat generated-template `today`, `tomorrow`, and `daily` reports as equal + consumers of rich template module values. +- Update implemented docs only after code behavior exists. -## Stage 1: Daily Planning Module +## Stage 1: Runtime Prompt Value Contract ### Goal -Add the Daily-specific planning module before activating the new report. This -keeps module and report work separable and makes the eventual Daily default -composition explicit. +Add a runtime-only prompt value to module outputs while preserving rich module +snapshot persistence. ### Files To Inspect - `internal/module/module.go` -- `internal/briefing/tomorrow_planning_module.go` -- `internal/briefing/today_planning_module.go` -- `internal/briefing/modules.go` -- `internal/briefing/derived_modules_test.go` -- `docs/roadmap/daily.md` +- `internal/module/module_test.go` +- `internal/state/filesystem.go` +- `internal/state/filesystem_test.go` +- `internal/app/app.go` +- `internal/app/app_test.go` ### Implementation -- Add `module.DailyPlanning` with value `daily_planning`. -- Add `module.DailyPlanningOptions struct{}`. -- Add `internal/briefing/daily_planning_module.go`. -- Add `DailyPlanningModule` with the initial fields: - - `morning_readiness` - - `commute_school_workday_concerns` - - `overnight_change_watch` -- Build the Daily planning module from the same underlying summary inputs as - Tomorrow planning, but do not reuse the public `TomorrowPlanningModule` type. -- Share private helper functions with Tomorrow only when the helper expresses - report-neutral mechanics. -- Register `daily_planning` in the default module registry with: - - stanza name `daily_planning` - - default options `module.DailyPlanningOptions{}` - - supported reports `[]report.ID{report.Daily}` after `report.Daily` exists - in Stage 3; if Stage 1 is implemented before `report.Daily`, add the module - ID/options now and wire report support in Stage 3. +- Add a runtime-only field to `module.Output`, for example: + +```go +type Output struct { + ID ID `json:"id"` + StanzaName string `json:"stanzaName"` + Value any `json:"value"` + PromptValue any `json:"-"` +} +``` + +- Add a small helper in `internal/module`, for example: + +```go +func (o Output) DataPackageValue() any +``` + +The helper should return `PromptValue` when non-nil and fall back to `Value` +otherwise. This fallback keeps tests and any manually built snapshots simple. + +- Do not require `PromptValue` in `Snapshot.Validate`. +- Do not persist `PromptValue` to module snapshot JSON. +- Do not change `StanzaValue`; it should continue decoding rich `Value`. ### Acceptance Criteria -- `daily_planning` is a distinct module ID and stanza. -- No Daily path emits `tomorrow_planning`. -- No public Daily type aliases or embeds `TomorrowPlanningModule`. -- Unsupported reports receive an actionable unsupported-module error. +- Module snapshots still serialize rich module values under `value`. +- Module snapshots do not serialize `promptValue` or any equivalent field. +- Existing rich-module snapshot lookup and `StanzaValue` behavior remain + unchanged. +- Code has a single helper for choosing the data-package value from an output. ### Tests -- Add or update module tests for: - - output shape; - - missing-summary fallback behavior; - - supported Daily report; - - unsupported Today, Tomorrow, Hourly, Three-Day, Weekend, and Storm reports. -- Suggested focused command after this stage: +- Add module tests proving: + - `DataPackageValue` uses `PromptValue` when set; + - `DataPackageValue` falls back to `Value`; + - marshaled snapshot JSON omits `PromptValue`; + - `StanzaValue` continues decoding rich `Value`. + +Suggested focused command: ```sh -go test ./internal/module ./internal/briefing +go test ./internal/module ./internal/state ``` ### Prompt Size Small enough for one implementation prompt. -## Stage 2: Daily GeneratedText Contract And Assets +## Stage 2: Module Registry Prompt Exporters ### Goal -Add Daily generated-text validation and embedded assets while keeping the active -report registry unchanged until Stage 3. +Teach the module registry to attach prompt-facing values to outputs as modules +are built. ### Files To Inspect -- `internal/generatedtext/tomorrow.go` -- `internal/generatedtext/today.go` -- `internal/generatedtext/catalog.go` -- `internal/generatedtext/*_test.go` -- `internal/reporttemplate/reporttemplate.go` +- `internal/briefing/modules.go` +- `internal/briefing/modules_test.go` +- `internal/briefing/*_module.go` +- `internal/module/module.go` + +### Implementation + +- Add a prompt exporter type in `internal/briefing`, for example: + +```go +type ModulePromptExporter func(value any) (any, error) +``` + +- Add `PromptExporter ModulePromptExporter` to `ModuleDefinition`. +- In `ModuleRegistry.BuildModule`, after builder output ID and stanza validation: + - if `PromptExporter` is nil, set `output.PromptValue = output.Value`; + - if `PromptExporter` is present, call it with `output.Value`; + - set `output.PromptValue` to the returned value; + - wrap exporter errors with module ID and stanza context. +- Add a typed exporter helper if it keeps module exporters concise, for example: + +```go +func promptExporter[T any](fn func(T) (any, error)) ModulePromptExporter +``` + +The helper should convert `any` through JSON marshal/unmarshal or direct type +assertion only if it meaningfully reduces boilerplate without hiding errors. + +- Do not make `internal/promptinput` import `internal/briefing`. +- Do not move module-specific export policy into `internal/promptinput`. + +### Acceptance Criteria + +- Every built module output has a non-nil data-package value. +- Modules without custom exporters pass through rich values. +- Custom exporter errors identify the module and stanza. +- Registry validation remains focused on definitions, duplicate IDs/stanzas, + supported reports, options, builders, and missing-data policy. + +### Tests + +- Add or update module registry tests for: + - default pass-through prompt values; + - custom exporter prompt values; + - exporter error wrapping; + - output ID/stanza validation still runs before or around export behavior; + - output `PromptValue` is not persisted in snapshot JSON. + +Suggested focused command: + +```sh +go test ./internal/briefing ./internal/module +``` + +### Prompt Size + +Small enough for one implementation prompt. + +## Stage 3: Promptinput Uses Exported Values And Schema V3 + +### Goal + +Make data-package construction serialize prompt-facing values and bump the data +package schema version. + +### Files To Inspect + +- `internal/promptinput/package.go` +- `internal/promptinput/package_test.go` +- `internal/state/filesystem_test.go` +- `internal/app/app.go` +- `internal/app/app_test.go` +- `docs/roadmap/data-package-exports.md` + +### Implementation + +- Change `promptinput.SchemaVersion` to: + +```go +const SchemaVersion = "weatherreporter.data_package.v3" +``` + +- Update `stanzasFromSnapshot` to use `output.DataPackageValue()` rather than + `output.Value`. +- Keep `BriefingStanzas` category grouping and ordering unchanged. +- Keep `LoadYAML` validation strict for the current schema version. +- Update tests and fixtures that assert `weatherreporter.data_package.v2`. + +### Acceptance Criteria + +- Saved data packages use schema version `weatherreporter.data_package.v3`. +- Data package stanzas use `PromptValue` when present. +- Data package stanzas fall back to rich `Value` when `PromptValue` is absent, + which keeps hand-built test snapshots and loaded rich snapshots usable. +- YAML category ordering remains unchanged. +- Module snapshots remain rich and unaffected by prompt export serialization. + +### Tests + +- Update promptinput tests for: + - schema version `v3`; + - prompt value preferred over rich value; + - fallback to rich value; + - deterministic categorized YAML output unchanged apart from stanza values and + schema version; + - unknown/uncategorized stanza behavior unchanged. +- Update state tests that load data packages. + +Suggested focused command: + +```sh +go test ./internal/promptinput ./internal/state +``` + +### Prompt Size + +Small enough for one implementation prompt. + +## Stage 4: Current Conditions And Hourly Forecast Exports + +### Goal + +Add custom prompt exports for the clearest noisy raw-data modules: +`current_conditions` and `hourly_forecast`. + +### Files To Inspect + +- `internal/briefing/current_conditions_module.go` +- `internal/briefing/hourly_forecast_module.go` +- `internal/briefing/base_modules_test.go` +- `internal/generatedtext/render_context.go` +- `internal/reporttemplate/templates/*.md.tmpl` +- `internal/app/app_test.go` + +### Current Conditions Export Shape + +The prompt-facing `current_conditions` export should keep: + +- `condition_text` +- `is_day` +- `temperature_c` +- `temperature_f` +- `apparent_temperature_c` +- `apparent_temperature_f` +- `dewpoint_c` +- `dewpoint_f` +- `relative_humidity_percent` +- `wind_speed_kmh` +- `wind_speed_mph` +- `wind_direction` + +It should remove: + +- `condition_text_lower` +- `wind_direction_text` + +The rich `CurrentConditionsModule` should keep those helper fields for +templates. + +### Hourly Forecast Export Shape + +The prompt-facing `hourly_forecast` export should keep module-level fields: + +- `product` +- `issued_at` +- `updated_at` +- `source_location` +- `source_location_id` +- `periods` + +Each prompt-facing hourly period should keep: + +- `period_begins` +- `period_ends` +- `name` +- `is_day` +- `condition_code` +- `text_description` +- temperature fields +- dewpoint fields +- wind speed and gust fields +- `wind_direction` +- pressure fields +- visibility fields +- apparent temperature fields +- `cloud_cover_percent` +- `probability_of_precipitation_percent` +- precipitation amount fields +- snowfall depth fields +- `uv_index` +- `relative_humidity_percent` + +Each prompt-facing hourly period should remove: + +- `hour_label` +- `text_description_lower` +- `mention_precipitation` + +The rich `HourlyForecastPeriod` should keep those helper fields for templates. + +### Implementation + +- Add prompt export structs near each module. +- Add exporter functions near each module. +- Register exporters in the default module definitions. +- Prefer straightforward field copying over reflection. +- Preserve `omitempty` behavior. + +### Acceptance Criteria + +- Saved data packages no longer include removed fields for current conditions or + hourly forecast. +- Rich module snapshots and render contexts still include template helper + fields. +- Existing hourly, today, tomorrow, and daily template output remains unchanged + wherever those templates consume current conditions or hourly forecast values. + +### Tests + +- Update module tests to prove prompt exports omit stale fields and keep + expected factual fields. +- Update template/render-context tests to prove helper fields remain available + to templates. +- Update app workflow tests to inspect saved YAML and reject: + - `condition_text_lower`; + - `wind_direction_text`; + - `hour_label`; + - `text_description_lower`; + - `mention_precipitation`. + +Suggested focused command: + +```sh +go test ./internal/briefing ./internal/generatedtext ./internal/reporttemplate ./internal/app +``` + +### Prompt Size + +Medium. Suitable for one implementation prompt. + +## Stage 5: Derived Daypart Summary Export + +### Goal + +Add a curated prompt export for `derived_daypart_summaries` while preserving the +rich daypart fields used by Daily, Today, and Tomorrow templates. + +### Files To Inspect + +- `internal/briefing/derived_daypart_summaries_module.go` +- `internal/briefing/derived_modules_test.go` +- `internal/generatedtext/render_context.go` +- `internal/reporttemplate/templates/daily.md.tmpl` +- `internal/reporttemplate/templates/today.md.tmpl` - `internal/reporttemplate/templates/tomorrow.md.tmpl` -- `internal/reporttemplate/prompts/tomorrow.generated_text.md` -- `internal/reporttemplate/schemas/tomorrow.generated_text.schema.json` +- `internal/reporttemplate/reporttemplate_test.go` +- `internal/app/app_test.go` + +### Export Shape + +For each daypart, the prompt-facing export should keep: + +- `date` +- `display_name` +- `period_begins` +- `period_ends` +- `temp_range_f` +- `apparent_temp_range_f` +- `max_pop_percent` +- `max_pop_time` +- `mention_precipitation` +- `max_wind_gust_mph` +- `max_wind_gust_time` +- `dominant_condition` +- `temperature_trend` +- `temperature_start_phrase_f` +- `temperature_end_phrase_f` +- `temperature_peak_phrase_f` +- `temperature_steady_phrase_f` +- `notable_conditions` +- `snow` +- `ice` +- `fog` +- `heat` +- `cold` +- `wind` +- `relevant_alert_count` + +The prompt-facing export should remove: + +- `temperature_phrase_f` +- `dominant_condition_lower` +- `dominant_condition_display` +- `max_pop_time_label` + +For `max_pop_time`, use the most readable existing time label. Prefer +`MaxPopTimeLabel` when present, falling back to `MaxPopTime`, while keeping the +prompt-facing field name `max_pop_time`. + +Keep the temperature trend phrase fields even though only some are populated for +each trend. They are not duplicates when used according to the trend: + +- rising/falling use start and end phrases; +- peaking uses peak phrase; +- steady uses steady phrase. + +### Implementation + +- Add prompt export structs near the daypart module. +- Add an exporter for the `map[string]DerivedDaypartSummaryModule` value. +- Preserve map keys and values for all emitted dayparts. +- Register the exporter in the default module definitions. +- Do not alter rich `DerivedDaypartSummaryModule` fields used by templates. + +### Acceptance Criteria + +- Saved data packages no longer include the removed daypart fields. +- The prompt-facing daypart export still gives the LLM enough information to + understand condition, temperature trend, precipitation, wind, notable + conditions, and alert relevance. +- Daily, Today, and Tomorrow template output remains unchanged. +- Render contexts still expose rich daypart helper fields. + +### Tests + +- Update daypart module tests for: + - prompt export field presence; + - removed field absence; + - rising, falling, peaking, and steady trend values; + - max PoP time using the friendly label under the stable `max_pop_time` key. +- Update template tests to prove rich helper fields still render Daily, Today, + and Tomorrow daypart wording. +- Update app data-package tests to reject stale daypart fields. + +Suggested focused command: + +```sh +go test ./internal/briefing ./internal/generatedtext ./internal/reporttemplate ./internal/app +``` + +### Prompt Size + +Medium. Suitable for one implementation prompt. + +## Stage 6: Pass-Through Review And Workflow Regression Tests + +### Goal + +Confirm all other modules export correctly through pass-through behavior and add +workflow-level coverage proving the new boundary. + +### Files To Inspect + +- `internal/briefing/*_module.go` +- `internal/briefing/modules.go` +- `internal/promptinput/package_test.go` +- `internal/app/app_test.go` +- `internal/generatedtext/render_context_test.go` - `internal/reporttemplate/reporttemplate_test.go` ### Implementation -- Add `internal/generatedtext/daily.go`. -- Add `type Daily struct` with the same public JSON shape as Tomorrow: - - `summary` required string - - `forecast_discussion` required `[]string` - - `precipitation_timing` optional string - - `confidence` optional string -- Add `ValidateDaily`. -- Match Tomorrow validation semantics: - - reject malformed JSON; - - reject unknown fields; - - reject trailing values; - - trim string fields; - - trim each forecast-discussion paragraph; - - drop blank forecast-discussion paragraphs; - - require nonblank summary; - - require at least one nonblank forecast-discussion paragraph; - - return canonical normalized JSON. -- Add `internal/reporttemplate/schemas/daily.generated_text.schema.json`. -- Add `internal/reporttemplate/prompts/daily.generated_text.md`. -- Add `internal/reporttemplate/templates/daily.md.tmpl`, initially matching the - Tomorrow rendered Markdown structure while referencing Daily render-context - fields. -- Register Daily in the generated-text catalog with schema ID `daily`. -- Register the Daily schema and template asset lookup in `internal/reporttemplate`. - -### Acceptance Criteria - -- Daily generated text validates independently from Tomorrow. -- The Daily schema and template can be looked up by ID `daily`. -- The Daily prompt asset exists as maintained source material for out-of-band - Scriptorium registration. -- No report registry behavior changes yet unless Stage 2 and Stage 3 are - intentionally implemented together. - -### Tests - -- Add generated-text tests for: - - valid Daily JSON; - - missing `summary`; - - missing or blank `forecast_discussion`; - - unknown fields; - - trailing JSON; - - trimming and canonical output. -- Add catalog tests proving schema ID `daily` maps to `ValidateDaily`. -- Add reporttemplate tests for Daily schema lookup, template lookup, and basic - render behavior. -- Suggested focused command: - -```sh -go test ./internal/generatedtext ./internal/reporttemplate -``` - -### Prompt Size - -Small enough for one implementation prompt. - -## Stage 3: Daily Render Context - -### Goal - -Add a dedicated Daily template context that mirrors Tomorrow mechanics without -exposing Tomorrow public types. - -### Files To Inspect - -- `internal/generatedtext/render_context.go` -- `internal/generatedtext/render_context_test.go` -- `internal/briefing/*_module.go` -- `internal/module/module.go` -- `internal/facts` -- `internal/reporttemplate/templates/tomorrow.md.tmpl` - -### Implementation - -- Add: - -```go -type DailyRenderContext struct { - Report DailyReportContext - GeneratedText Daily - Modules DailyTemplateModules - Collected facts.CollectedFacts - Derived facts.DerivedFacts -} -``` - -- Add `DailyReportContext` with: - - `Title` - - `ForecastDate` - - `ForecastDateLabel` - - `ForecastDayName` - - `GeneratedAt` - - `GeneratedAtLabel` - - `ValidPeriod` - - `Timezone` -- Add `DailyTemplateModules` with the Daily template surfaces defined in - `docs/roadmap/daily.md`, including `DailyPlanning`. -- Add a Daily daypart context if the Tomorrow daypart context is not already - generic enough to use privately. -- Add `BuildDailyRenderContext`. -- Generate `Title` as `'s Weather`, for example `Monday's Weather`. -- Build `ForecastDateLabel` from the valid-period start in the effective - timezone. -- Reuse private module snapshot lookup and ordered-daypart helpers where useful, - but keep Daily's exported types distinct. - -### Acceptance Criteria - -- Daily render context is independent and template-friendly. -- Optional modules are nil when omitted by missing-data policy. -- Ordered dayparts use the same ordering and omission behavior as Tomorrow. -- Daily planning is available as `.Modules.DailyPlanning`. -- The render context exposes `Collected` and `Derived` for advanced template - use, consistent with current generated-text-template reports. - -### Tests - -- Add render-context tests for: - - title and forecast date label; - - generated-at label; - - valid period and timezone; - - Daily planning extraction; - - omitted optional modules; - - daypart ordering; - - collected and derived facts propagation. -- Suggested focused command: - -```sh -go test ./internal/generatedtext ./internal/reporttemplate -``` - -### Prompt Size - -Small enough for one implementation prompt. - -## Stage 4: Report Registry Cutover - -### Goal - -Replace the active legacy `daily_today` report definition with the new generated -text-template `daily` report. - -### Files To Inspect - -- `internal/report/definition.go` -- `internal/report/daily_report.go` -- `internal/report/today_report.go` -- `internal/report/tomorrow_report.go` -- `internal/report/names.go` -- `internal/report/period.go` -- `internal/report/period_test.go` -- `internal/briefing/modules.go` -- `internal/app/app.go` -- `internal/changes` - -### Implementation - -- Add or change the active Daily report ID to: - -```go -Daily ID = "daily" -``` - -- Remove active use of `DailyToday`. - - Prefer removing the exported `DailyToday` constant entirely if no active - code needs it. - - If temporary compile sequencing requires keeping it during this stage, - remove it before the stage is complete. -- Replace `dailyTodayDefinition` with `dailyDefinition`. -- Daily definition values: - - ID `Daily` - - name `Daily Report` - - prompt ID `weather.daily_generated_text` - - generation mode `GenerationModeGeneratedTextTemplate` - - template ID `daily` - - generated-text schema ID `daily` - - artifact group `daily` - - batch output name `daily.md` - - generated `true` - - compatible prior IDs `[]ID{Daily}` - - comparison strategy same valid local date - - no morning batch membership - - no evening batch membership -- Add `dailyModules()` with the module order from `docs/roadmap/daily.md`: +- Review remaining modules: - `metadata` - - `current_conditions` - `narrative_forecast` - `derived_daily_summary` - - `derived_daypart_summaries` - `precip_timing` + - `outdoor_windows` - `alert_digest` - `spc_convective_outlooks` - - `area_forecast_discussion` - `spc_convective_discussion` + - `area_forecast_discussion` - `weather_story` - - `outdoor_windows` - - `daily_planning` - - `hourly_forecast` -- Add `resolveDaily` requiring `ResolveRequest.Date`. - - Return an actionable error when `Date` is zero. - - Resolve the date as a local civil day in `ResolveRequest.Location`. -- Update report name/config resolution: - - `IDForCommandName("daily")` returns `Daily`. - - `IDForConfigKey("daily")` returns `Daily`. - - `IDForConfigKey("daily_today")` returns an unknown config-key error. -- Update module registry supported-report lists: - - replace `report.DailyToday` with `report.Daily` for shared Daily-compatible - modules; - - add `report.Daily` to Daily planning support. -- Update Recent Changes dispatch where it currently groups daily-style reports, - replacing `DailyToday` with `Daily`. -- Ensure `BatchReports` continues to include Today in the morning batch and - Tomorrow in the evening batch, with no Daily membership. + - planning modules +- Keep pass-through behavior for modules that are already prompt-appropriate. +- Add custom exporters only if a module contains clear template-only helpers or + confusing duplicate fields. +- Do not broaden this stage into a general prompt-schema redesign. +- Add workflow assertions that: + - module snapshots contain rich values; + - render contexts contain rich values; + - data packages contain curated values; + - Scriptorium receives the curated data package path exactly as before. +- Include workflow coverage for generated-template `today`, `tomorrow`, and + `daily` reports when asserting daypart and render-context behavior. ### Acceptance Criteria -- `report.DefaultRegistry()` includes `daily` and not `daily_today`. -- `weatherreporter generate daily` resolves to report ID `daily`. -- `reports.daily` config overrides apply to Daily. -- `reports.daily_today` is rejected. -- Daily uses generated-text-template mode. -- Daily metadata, RunID, artifact paths, distributor variables, and report - output all use report ID/artifact group `daily`. -- Scheduled batches do not include Daily. +- Every default module either has a custom exporter or intentionally uses + pass-through. +- App workflow tests prove saved data packages omit the cleaned fields. +- App workflow tests prove rich helper fields remain available where templates + use them. +- App workflow or render-context tests include `daily` alongside `today` and + `tomorrow` for daypart helper coverage. +- Existing report generation behavior remains unchanged except for data-package + YAML content and schema version. ### Tests -- Update report tests for: - - registry membership; - - command-name resolution; - - config-key resolution; - - generated-text-template metadata; - - explicit-date valid period; - - missing-date resolver error; - - batch membership. -- Update module registry tests to prove every default Daily module is buildable. -- Update Recent Changes tests to use Daily snapshots instead of legacy - `daily_today` snapshots where applicable. -- Suggested focused command: +Suggested focused command: ```sh -go test ./internal/report ./internal/briefing ./internal/changes +go test ./internal/briefing ./internal/promptinput ./internal/generatedtext ./internal/reporttemplate ./internal/app ``` ### Prompt Size -This is the first larger cutover stage. It is still suitable for one -implementation prompt if the agent works package by package and keeps tests -focused. If compile errors spread widely, split into: +Small to medium. Suitable for one implementation prompt. -1. report ID/name/config resolution; -2. module registry and Recent Changes updates; -3. report tests and stale-symbol cleanup. - -## Stage 5: CLI And App Workflow Integration +## Stage 7: Documentation And Final Validation ### Goal -Make the public command `weatherreporter generate daily --date YYYY-MM-DD` -execute the full generated-text-template workflow and reject missing dates. +Update implemented documentation after the code exists and run full validation. ### Files To Inspect -- `internal/cli/root.go` -- `internal/cli/root_test.go` -- `internal/app/app.go` -- `internal/app/app_test.go` -- `internal/state` -- `internal/adapters/scriptorium` -- `internal/adapters/distributor` -- `examples/config.yml` - -### Implementation - -- Update CLI date policy: - - `generate daily` requires `--date YYYY-MM-DD`; - - missing `--date` returns a concise actionable error; - - malformed `--date` remains an error; - - `generate today` keeps its current behavior; - - `generate tomorrow` remains date-free. -- Ensure `--config`, `--units`, `--tz`, `--out`, and distributor notification - behavior continue to work as they do for other generated-text-template - reports. -- Update app generated-text dispatch so Daily uses: - - prompt ID `weather.daily_generated_text`; - - schema ID `daily`; - - template ID `daily`; - - `BuildDailyRenderContext`. -- Ensure persisted artifacts include: - - raw generated text JSON; - - generated-text run result; - - normalized generated text; - - render context; - - rendered Markdown; - - metadata; - - optional output copy. -- Ensure distributor upload, when enabled, uses the managed Daily Markdown - report path and Daily template variables. - -### Acceptance Criteria - -- `weatherreporter generate daily --date YYYY-MM-DD` runs through the - generated-text-template path. -- `weatherreporter generate daily` without `--date` fails before generation. -- `weatherreporter generate daily --date bad-date` fails before generation. -- Existing Today, Tomorrow, Hourly, Three-Day, Weekend, and Storm commands keep - their current syntax. -- Daily app workflow saves the same classes of artifacts as Today/Tomorrow. -- Daily optional `--out` copy behavior remains separate from the managed report - path. - -### Tests - -- Update CLI parser tests for: - - required Daily date; - - malformed Daily date; - - valid Daily date; - - Today and Tomorrow date behavior unchanged. -- Add or update app workflow tests for: - - Daily generated-text Scriptorium request; - - Daily schema validation; - - Daily render context persistence; - - Daily rendered report path; - - Daily optional output copy; - - Daily distributor request values when notification is enabled. -- Suggested focused command: - -```sh -go test ./internal/cli ./internal/app ./internal/state -``` - -### Prompt Size - -Medium. Suitable for one implementation prompt after Stages 1-4 compile. - -## Stage 6: Legacy DailyToday Sweep - -### Goal - -Remove stale active-code references to the legacy `daily_today` report after the -new Daily path is working. - -### Files To Inspect - -- `internal/report` -- `internal/briefing` -- `internal/config` -- `internal/app` -- `internal/changes` -- `internal/promptinput` -- `internal/state` -- `internal/generatedtext` -- `internal/reporttemplate` -- package tests - -### Implementation - -- Remove remaining production-code references to: - - `DailyToday`; - - `daily_today`; - - `weather.daily_report` on the active Daily path. -- Update test fixtures and helper names that represent the active Daily report. -- Keep references only when intentionally describing historical artifacts in - roadmap text. -- Do not add migration logic for old workspace files. -- Do not keep `daily_today` as a hidden alias. - -### Acceptance Criteria - -- `rg -n "DailyToday|daily_today|weather.daily_report" internal examples docs` - has no production-code or implemented-doc matches, except future/historical - roadmap references if intentionally retained. -- All report and module defaults refer to active report IDs. -- Tests no longer assume `daily` resolves to `daily_today`. - -### Tests - -- Run: - -```sh -rg -n "DailyToday|daily_today|weather.daily_report" internal examples docs -go test ./internal/... -``` - -### Prompt Size - -Small to medium. This can be combined with Stage 5 only if the agent has enough -context and compile errors are already localized. - -## Stage 7: Documentation And Examples - -### Goal - -Update implemented documentation and maintained examples after the Daily feature -exists. Keep planned or deferred behavior only under `docs/roadmap/`. - -### Files To Inspect - -- `README.md` -- `docs/cli.md` -- `docs/config.md` -- `docs/operations.md` -- `docs/templates.md` -- `docs/troubleshooting.md` -- `docs/internal/report-registry.md` -- `docs/internal/generatedtext.md` -- `docs/internal/reporttemplate.md` - `docs/internal/module.md` -- `docs/internal/app-orchestration.md` -- `examples/config.yml` -- tests that load examples +- `docs/internal/prompt-input.md` +- `docs/templates.md` +- `docs/operations.md` +- `docs/troubleshooting.md` +- `docs/roadmap/data-package-exports.md` +- tests that assert documentation examples or data-package snippets ### Implementation -- Update `docs/cli.md`: - - document `weatherreporter generate daily --date YYYY-MM-DD`; - - describe missing date as an error; - - keep Today and Tomorrow documented as separate commands. -- Update `docs/config.md`: - - document `reports.daily` module overrides; - - remove active `reports.daily_today` references. -- Update `docs/operations.md`: - - document Daily as manually targeted by date; - - document Daily artifact paths and managed-report behavior. -- Update `docs/templates.md`: - - document Daily template variables and generated-text fields. -- Update internal docs: - - report registry Daily identity; - - generated-text Daily validation; - - reporttemplate Daily assets; - - `daily_planning` module; - - app orchestration only where Daily differs from generic - generated-text-template flow. -- Update `examples/config.yml` only if it includes report module override - examples that should reference `daily`. -- Do not describe scheduled Daily behavior, old artifact migration, or future - template divergence as implemented behavior. +- Update `docs/internal/module.md` to describe: + - rich module output; + - runtime prompt export values; + - pass-through exporters; + - module-owned prompt export policy. +- Update `docs/internal/prompt-input.md` to document: + - schema version `weatherreporter.data_package.v3`; + - curated module export behavior; + - category ordering unchanged; + - data packages are not full template render contexts. +- Update `docs/templates.md` to clarify that templates can use richer fields + than the data package exposes. +- Update any Daily template-variable documentation alongside Today and Tomorrow + references where the same module fields are discussed. +- Update any implemented docs containing stale examples of removed data-package + fields. +- Do not document deferred configurable field profiles or reflection filters as + implemented behavior. ### Acceptance Criteria -- Non-roadmap docs describe only implemented Daily behavior. -- No implemented docs describe `daily_today` as an active report. -- Examples use implemented report config keys only. -- README remains concise and links to canonical docs instead of duplicating - reference material. +- Non-roadmap docs describe only implemented data-package export behavior. +- Docs do not imply data packages contain template-only helper fields. +- Examples and snippets use schema version `v3` when they show data packages. -### Tests And Checks +### Validation Commands ```sh -go test ./internal/config ./internal/cli -git diff --check -rg -n "daily_today|weather.daily_report|DailyToday" README.md docs examples -``` - -Review any remaining matches manually. Roadmap references may remain only when -they are clearly historical or future planning context. - -### Prompt Size - -Medium. Suitable for one implementation prompt after code behavior exists. - -## Stage 8: Final Validation - -### Goal - -Verify the complete Daily cutover and catch stale references or documentation -drift. - -### Required Commands - -```sh -go test ./internal/report ./internal/generatedtext ./internal/reporttemplate -go test ./internal/briefing ./internal/module -go test ./internal/app ./internal/cli ./internal/config +go test ./internal/module ./internal/briefing ./internal/promptinput +go test ./internal/generatedtext ./internal/reporttemplate ./internal/app go test ./... go run ./cmd/weatherreporter --help git diff --check ``` -### Stale Reference Checks +### Stale Field Greps + +Run focused checks against docs and expected saved data-package fixtures/snippets: ```sh -rg -n "DailyToday|daily_today|weather.daily_report" internal examples README.md docs -rg -n "reports\\.daily_today|weatherreporter generate daily(?!.*--date)" docs examples +rg -n "condition_text_lower|wind_direction_text|hour_label|text_description_lower|mention_precipitation|dominant_condition_lower|dominant_condition_display|max_pop_time_label|temperature_phrase_f" docs internal/*/*_test.go ``` -The second command uses a regex feature that may not be supported by every -`rg` build. If it fails, use simpler searches: +Review matches manually. Some matches should remain in rich module structs, +template tests, and render-context tests; they should not remain as expected +data-package fields. -```sh -rg -n "reports\\.daily_today|weatherreporter generate daily" docs examples -``` +### Prompt Size -Review remaining matches manually. - -### Manual Review Items - -- Confirm `weatherreporter --help` lists `daily`, `today`, and `tomorrow` - distinctly. -- Confirm `generate daily` help or parser behavior makes `--date` required. -- Confirm morning and evening batch definitions did not change except where - tests explicitly prove intended behavior. -- Confirm distributor template variables for Daily use report ID/artifact group - `daily`. -- Confirm old workspace artifacts are not migrated or rewritten. +Medium. Suitable for one implementation prompt. ## Deferred Work -Do not include these in the Daily replacement implementation: +Do not include these in this implementation sequence: -- scheduling Daily in morning or evening batches; -- migration of old `daily_today` workspace artifacts; -- compatibility alias support for `daily_today`; -- changing Today or Tomorrow semantics; -- adding a generic report-template inheritance system; -- consolidating Daily and Tomorrow public generated-text types; -- making Daily default to today or tomorrow when `--date` is omitted; -- changing Scriptorium prompt registration behavior, which remains out of band. +- user-configurable data-package field selection; +- per-prompt custom field profiles; +- reflection-based generic include/exclude lists; +- automatic schema generation for data-package exports; +- changing collected facts or derived facts contracts; +- changing Scriptorium invocation behavior; +- changing generated Markdown templates beyond preserving their output; +- migrating old workspace data-package artifacts. ## Open Questions No open questions block implementation. -The roadmap intentionally chooses the clean-break option for all previously -ambiguous areas: `daily_today` is removed from active behavior, `--date` is -required, Daily is not scheduled, and Daily owns separate template/schema/prompt -and planning-module surfaces even when they initially match Tomorrow. +The implementation plan intentionally locks in the recommended choices from the +feature roadmap: schema version bump to `weatherreporter.data_package.v3`, and +runtime-only prompt export values stored on `module.Output`. ## Global Validation Checklist - `go test ./...` passes. - `go run ./cmd/weatherreporter --help` is accurate. - `git diff --check` passes. -- `weatherreporter generate daily --date YYYY-MM-DD` is the only valid Daily - generation form. -- `weatherreporter generate daily` without `--date` fails. -- `reports.daily` is accepted. -- `reports.daily_today` is rejected. -- No active code path uses `daily_today`. -- Daily generated reports use `weather.daily_generated_text`. -- Daily rendered Markdown uses the Daily template. -- Daily generated-text JSON uses the Daily schema. -- Daily data packages include `daily_planning`, not `tomorrow_planning`. -- Daily is absent from morning and evening scheduled batches. -- Non-roadmap documentation describes only implemented behavior. +- Saved data packages use schema version `weatherreporter.data_package.v3`. +- Saved data packages serialize prompt-facing module exports. +- Saved module snapshots serialize rich module values and do not persist + prompt-facing values. +- Render contexts continue to expose rich module values. +- Hourly, Today, Tomorrow, and Daily templates continue to render the same + Markdown output. +- YAML briefing category order remains unchanged. +- `current_conditions` data packages omit `condition_text_lower` and + `wind_direction_text`. +- `hourly_forecast.periods[]` data packages omit `hour_label`, + `text_description_lower`, and `mention_precipitation`. +- `derived_daypart_summaries` data packages omit `temperature_phrase_f`, + `dominant_condition_lower`, `dominant_condition_display`, and + `max_pop_time_label`. +- Non-roadmap docs describe only implemented behavior.