diff --git a/docs/config.md b/docs/config.md index b296689..dc29db8 100644 --- a/docs/config.md +++ b/docs/config.md @@ -22,6 +22,8 @@ files. Environment-variable configuration is not implemented. ## Minimal Config +See [examples/minimal-config.yml](../examples/minimal-config.yml). + ```yaml weather_api: base_url: https://weather.api.example.com/ @@ -102,3 +104,12 @@ snapshot exists and a threshold is crossed. Configuration files should not contain secrets. The current Weather API and Scriptorium integration settings do not require secret fields. + +## Maintained Examples + +- [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. + +Both example files are loaded by the config test suite. diff --git a/docs/roadmap/documentation.md b/docs/roadmap/documentation.md index 2627aea..b58660d 100644 --- a/docs/roadmap/documentation.md +++ b/docs/roadmap/documentation.md @@ -66,10 +66,8 @@ unimplemented work belongs only under `docs/roadmap/`. the canonical contributor workflow document. - `docs/policy/documentation.md` - keep. It is the controlling documentation policy for this migration. -- `docs/roadmap/initial.md` - split and delete or replace. Much of it now - describes completed implementation work; extract only still-future content - into a future-only roadmap and remove this stale initial roadmap from the - current documentation map. +- `docs/roadmap/future.md` - keep as the future-only project roadmap. The stale + implementation roadmap was removed after deferred work was extracted. - `examples/config.yml` - keep and lightly update. It is a maintained production-oriented example config and should be validated against the implemented config loader. @@ -97,8 +95,7 @@ Documents that are stale or in the wrong canonical home: - `docs/policy/development.md` contains proposed layout, MVP wording, and future design notes that should live in roadmap docs or be removed once implemented. -- `docs/roadmap/initial.md` should not be treated as a current implementation - guide. It mixes completed MVP planning with deferred work. +- `docs/roadmap/future.md` is the current home for deferred project work. - `README.md` links to the implementation roadmap. The README should link to current user/operator/developer docs and, if useful, a future-work roadmap that is clearly labeled as such. @@ -125,7 +122,8 @@ Examples: Links likely needing verification: -- README links to `docs/roadmap/initial.md`. +- README should link only to current user/operator/developer docs unless a + clearly labeled future-work link is needed. - Internal docs should link to canonical integration docs instead of repeating Scriptorium or Weather API details. - Operations and troubleshooting should link to CLI and config reference rather @@ -380,7 +378,8 @@ Links likely needing verification: - Purpose: future-only project work extracted from stale roadmap material. - Canonical scope: deferred features such as automatic storm monitoring, if still desired. -- Source-of-truth areas: `docs/roadmap/initial.md` and current code boundaries. +- Source-of-truth areas: current code boundaries and deferred work already + extracted into this file. - Acceptance criteria: no completed MVP tasks; no claims of current behavior; each item is clearly labeled proposed, accepted, deferred, or rejected. @@ -436,9 +435,8 @@ Links likely needing verification: current project behavior. - `docs/integrations/scriptorium.md`: keep `--input data_package=` as the documented input contract. Do not reintroduce `--vars-file` or `promptvars`. -- `docs/roadmap/initial.md`: do not update it as current docs. Extract - still-future work into `docs/roadmap/future.md`, then delete or replace the - stale file. +- `docs/roadmap/future.md`: keep only deferred work and avoid completed + implementation history. - `examples/config.yml`: keep as production-oriented config. Validate it with config-loading tests or an equivalent non-secret check. - `examples/minimal-config.yml`: add only if the implementation agent also adds @@ -729,11 +727,11 @@ archive, remote storage, or resume behavior because those are not implemented. - Goal: validate examples and ensure roadmap docs contain only future/planned material. - Files to create/update/delete/move: update `examples/config.yml`; optionally - create `examples/minimal-config.yml` with validation coverage; extract - future-only content from `docs/roadmap/initial.md` into - `docs/roadmap/future.md`; delete or replace `docs/roadmap/initial.md`. + create `examples/minimal-config.yml` with validation coverage; keep + `docs/roadmap/future.md` as the future-only roadmap after removing stale + implementation-history material. - Repository areas to inspect: `internal/config/*`, config tests, - `docs/roadmap/initial.md`, current implemented feature set. + roadmap docs, current implemented feature set. - Acceptance criteria: examples load successfully; roadmap files are clearly future-only; no completed MVP stage plan is linked as current docs. - Suggested validation commands: config example loading test, `go test ./...`, @@ -800,7 +798,5 @@ Manual review items: No questions block a correct documentation roadmap or migration. -Recommendation: during the migration, delete or replace -`docs/roadmap/initial.md` after extracting any still-valid future work into a -future-only roadmap. Do not treat `docs/roadmap/initial.md` as current project -documentation. +Recommendation: keep `docs/roadmap/future.md` future-only. Do not reintroduce +completed implementation-history material as current project documentation. diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md new file mode 100644 index 0000000..957ac66 --- /dev/null +++ b/docs/roadmap/future.md @@ -0,0 +1,51 @@ +# Future Roadmap + +This roadmap contains project work that is not implemented. Current behavior is +documented outside `docs/roadmap/`. + +## Deferred: Automatic Storm Monitoring + +Manual Storm Report generation is implemented through +`weatherreporter generate storm --start TIME --end TIME`. Automatic storm-event +evaluation remains deferred. + +Proposed direction: + +1. detect candidate events deterministically from alerts, forecast discussion, + weather story context when available, hourly thresholds, and material + forecast changes; +2. evaluate candidates through Scriptorium or another narrow evaluator adapter; +3. persist storm lifecycle state; +4. generate or update Storm Reports only when a meaningful event is present; +5. suppress ordinary low-impact thunder or rain chances. + +Possible lifecycle states: + +- `none` +- `monitoring` +- `active_report` +- `escalated` +- `deescalating` +- `resolved` + +Acceptance criteria before implementation: + +- scheduled reports and manual Storm Reports remain stable; +- candidate detection has fixture coverage; +- evaluator failures are inspectable and do not create noisy report output; +- manual Storm Report generation remains available. + +## Deferred: Alternate Runtime Integrations + +These ideas are not current behavior: + +- native LLM client inside `weatherreporter`; +- database-backed state; +- public HTTP API; +- multi-location selection; +- daemon mode; +- multi-user authorization; +- plugin system. + +Each item needs its own design note before implementation. Non-roadmap docs +must not describe these as available behavior. diff --git a/docs/roadmap/initial.md b/docs/roadmap/initial.md deleted file mode 100644 index 5b35389..0000000 --- a/docs/roadmap/initial.md +++ /dev/null @@ -1,1002 +0,0 @@ -# Weatherreporter Implementation Roadmap - -This roadmap defines a staged implementation plan for `weatherreporter`, a Go application that prepares human-facing weather reports from normalized weather data collected by `weatherfeeder` and rendered through `scriptorium`. - -The goal is to build the application in stable layers. Each stage should leave the repository in a working, testable state. Early stages should prioritize inspectable intermediate artifacts over complete automation. - -## Guiding Implementation Principles - -- Build deterministic data preparation before LLM rendering. -- Keep CLI, adapters, domain logic, state, and prompt input construction separate. -- Use fixture-driven tests for forecast processing and briefing builders. -- Persist intermediate artifacts so failed or low-quality reports can be inspected. -- Add one report type fully before generalizing to all report types. -- Treat `scriptorium` as an external adapter during the prototype. -- Do not build the storm-monitoring agent until scheduled report generation is reliable. -- Do not support multiple weatherreporter locations in the MVP; use one configured Weather API endpoint. - -## MVP Decisions Locked - -- Use one configured Weather API endpoint; do not expose MVP location selection. -- Use the Go standard library for CLI parsing. -- Use `gopkg.in/yaml.v3` for YAML configuration. -- Default Weather API query values are `format=json`, `units=us`, and `tz=Chicago`. -- Default missing-source policy is `warn`. -- Fetch full `/forecast/hourly` and `/forecast/narrative` products; Go owns report-period selection. -- Require hourly forecast data for normal scheduled reports. -- Use `scriptorium render` as an always-on preflight before `scriptorium run` for generated reports. -- Pass prompt input to `scriptorium` with `--input data_package=`. -- Identify source payloads with SHA-256 over canonical/minified raw `data` JSON. - -## Stage 0: Repository Skeleton and Architecture Baseline - -### Goal - -Create the project skeleton, commit the architecture documents, and establish the package boundaries before adding substantial logic. - -### Packages Introduced - -- `cmd/weatherreporter` -- `internal/cli` -- `internal/app` -- `internal/config` - -### Work Items - -1. Initialize the Go module. -2. Add the architecture policy document. -3. Add the package layout document. -4. Add this implementation roadmap. -5. Create minimal package directories and placeholder files where useful. -6. Add basic build/test tooling. -7. Add a minimal `weatherreporter --help` command using the Go standard library. - -### Deliverables - -- Go module builds successfully. -- `go test ./...` passes. -- Basic CLI entrypoint exists. -- Documentation is present under the appropriate docs directory. - -### Done Criteria - -- The repository has a clear skeleton matching the intended architecture. -- The binary can be built. -- The CLI can display help without loading external services. - -## Stage 1: Configuration and CLI Foundation - -### Goal - -Implement configuration loading and a stable command shape before integrating external systems. - -### Packages Introduced or Expanded - -- `internal/config` -- `internal/cli` -- `internal/app` -- `internal/timeutil` - -### Work Items - -1. Define configuration structs for: - - Weather API base URL, timeout, precision, units, and timezone. - - Missing-source behavior, with a global default and optional per-source overrides. - - `scriptorium` settings. - - Workspace paths. - - Report output paths. - - Daypart definitions. - - Recent-change thresholds. -2. Implement built-in defaults in `internal/config/defaults.go`: - - `units=us` - - `tz=Chicago` - - `format=json` - - missing-source policy `warn` -3. Implement YAML config loading from: - - `/usr/local/etc/weatherreporter/config.yml` - - CLI override via `--config` -4. Use `gopkg.in/yaml.v3` for YAML parsing. -5. Implement config validation. -6. Implement basic command structure with the Go standard library: - - `generate daily` - - `generate tomorrow` - - `generate three-day` - - `generate weekend` - - `generate storm` - - `run morning` - - `run evening` -7. Add CLI flag parsing for: - - `--config` - - `--units` - - `--tz` - - `--out` - - optional `--date` for Daily Today, accepting `YYYY-MM-DD` and defaulting to the current local date in the configured timezone - - `--start` and `--end` for manual Storm Reports -8. Commands may initially return "not implemented" after config and request resolution. -9. Add time-zone and clock helpers. - -### Deliverables - -- Config can be loaded, validated, and inspected in tests. -- CLI commands parse expected flags without a CLI framework dependency. -- App-layer request structs exist for report generation and scheduled batches. - -### Tests - -- Config defaults load successfully, including `units=us`, `tz=Chicago`, and missing-source policy `warn`. -- Example config file load test. -- Invalid config produces actionable errors. -- CLI parser tests for major commands and shared flags. -- Storm `--start`/`--end` parsing tests. -- Time-zone resolution tests. - -### Done Criteria - -- CLI request handling is stable enough that later stages can attach real behavior without reshaping commands. -- Configuration can represent the single Weather API endpoint, default units/timezone, default daypart set, and missing-source policy. - -## Stage 2: Weather API Adapter and Forecast Bundle - -### Goal - -Fetch normalized weather data from the internal weather API and represent it as a stable forecast bundle inside the application. - -### Key References - -- `docs/integrations/weatherapi.md` describes the weatherapi public API. -- The local API endpoint is available at `https://weather.api.rakestrawhome.com/` and will return live data. - -### Packages Introduced or Expanded - -- `internal/adapters/weatherapi` -- `internal/forecast` -- `internal/app` - -### Work Items - -1. Define the internal `forecast.Bundle` type. -2. Define source substructures for: - - Latest observation. - - Current conditions. - - Hourly forecast data. - - NWS narrative forecast periods. - - NWS alerts. - - NWS forecast discussion. - - Daily forecast data as a stub source slot until upstream support exists. - - NWS weather story as a stub source slot until upstream support exists. -3. Implement the weather API client as a fan-out adapter that assembles one bundle from multiple endpoints. -4. Fetch full `/forecast/hourly` and `/forecast/narrative` products, not day-slice endpoints, so Go domain code owns report-period selection. -5. Apply configured query defaults to requests: - - `format=json` - - `units=us`, unless overridden - - `tz=Chicago`, unless overridden on endpoints that support timezone -6. Add context-aware HTTP calls and timeouts. -7. Add source provenance to the bundle: - - endpoint - - query - - fetched time - - issued/updated time when available - - SHA-256 over canonical/minified raw `data` JSON - - warnings -8. Represent source warnings as first-class records with source name, code, severity, message, endpoint, and completeness impact. -9. Require hourly forecast data for normal scheduled reports. -10. Apply configured missing-source policy to missing observations, current conditions, alerts, discussion, daily forecast stub, weather story stub, and malformed non-required source sections: - - `error`: fail the bundle fetch - - `warn`: include a source warning and continue - - `none`: omit the warning and continue -11. Add actionable errors for failed API calls and decode failures. -12. Add fixture support for tests. -13. Add a debug command or app method to fetch and save the raw normalized bundle for fixture capture and inspection. - -### Deliverables - -- Weather API adapter can fetch and assemble a bundle from the configured endpoint. -- Forecast bundle type is available to downstream packages. -- Bundle source provenance and warnings are inspectable. -- Tests can use fixtures without real API calls. - -### Tests - -- Decode representative API fixtures into `forecast.Bundle`. -- Fan-out success across source endpoints. -- HTTP error handling. -- Timeout/cancellation behavior. -- `data:null` behavior under `error`, `warn`, and `none`. -- Missing or malformed source sections. -- Query construction for `units=us` and `tz=Chicago`. -- Full-product forecast endpoint selection. -- Required hourly forecast behavior. -- SHA-256 source identity behavior. - -### Done Criteria - -- The app can fetch current weather data and save or log a concise confirmation. -- No report generation is required yet. - -## Stage 3: Forecast Derivation and Daypart Processing - -### Goal - -Implement deterministic forecast processing needed by the Daily Report. - -### Packages Introduced or Expanded - -- `internal/forecast` -- `internal/timeutil` - -### Work Items - -1. Implement configurable daypart definitions. -2. Implement daypart overlap logic, including overnight periods. -3. Group hourly forecast records into dayparts. -4. Compute daypart summaries: - - Temperature range. - - Apparent-temperature range, if available. - - Max precipitation probability and associated hour. - - Peak wind speed. - - Peak wind gust. - - Dominant or notable conditions. - - Thunder, snow, ice, fog, heat, cold, or wind indicators where supported by source data. -5. Implement alert overlap with report periods and dayparts. -6. Implement basic threshold helpers. -7. Implement source selection helpers for NWS narrative periods and broader context. - -### Deliverables - -- A deterministic Daily Report forecast summary can be built from a fixture bundle. -- Daypart outputs are inspectable as JSON. - -### Tests - -- Morning/midday/afternoon/evening grouping. -- Overnight grouping across midnight. -- Missing hourly data behavior. -- Boundary timestamps at daypart edges. -- Max/min and threshold calculations. -- Alert-period overlap behavior. - -### Done Criteria - -- Forecast derivation is reliable enough to support a first report briefing package. -- No LLM or `scriptorium` integration is required yet. - -## Stage 4: Report Registry and Valid-Period Resolution - -### Goal - -Centralize report definitions, compatible comparison strategies, and valid-period behavior before building report-specific briefings. - -### Packages Introduced or Expanded - -- `internal/report` -- `internal/timeutil` -- `internal/app` - -### Work Items - -1. Define report IDs and variants: - - `daily_today` - - `daily_tomorrow` - - `three_day` - - `weekend` - - `storm` -2. Define report metadata structures. -3. Define a report `Definition` contract. -4. Implement a registry. -5. Implement valid-period resolvers using the configured local timezone, default `Chicago`, and half-open `[start,end)` intervals: - - Today Daily Report: current local civil day, `[00:00, next 00:00)`. - - Tomorrow Planning Brief: next local civil day. - - 3-Day Outlook: generation time through local midnight after the second following local civil day. - - Weekend Outlook: Monday through Thursday covers Saturday 00:00 to Monday 00:00; Friday and Saturday cover `max(generation time, Friday 18:00)` to Monday 00:00; scheduled Sunday morning skips Weekend Outlook. - - Storm Report: explicit `--start` and `--end`. -6. Parse manual storm period bounds from `YYYY-MM-DDTHH:MM` in the configured timezone or RFC3339 timestamps with explicit offsets. -7. Define default prompt IDs: - - `weather.daily_report` - - `weather.daily_report` for `daily_tomorrow`; this prompt covers one civil day. - - `weather.three_day_outlook` - - `weather.weekend_outlook` - - `weather.storm_report` -8. Define Recent Changes matching strategies in report definitions: - - Daily Today, Daily Tomorrow, and compatible date slices from multi-day reports may compare by same valid local date when marked compatible. - - Weekend compares by same weekend window. - - Storm compares by explicit event window. -9. Implement batch membership rules: - - Morning batch: Daily Today, 3-Day Outlook, Weekend Outlook except Sunday. - - Evening batch: Daily Tomorrow. - -### Deliverables - -- App layer can resolve which reports should run for a command. -- Each report has a valid period independent of generation time. -- Report definitions map to prompt IDs and comparison strategies. - -### Tests - -- Daily valid period for different generation times. -- Tomorrow valid period from evening generation. -- 3-Day period calculation from generation time. -- Weekend period calculation on Monday, Friday, Saturday, and Sunday. -- Storm manual period parsing and validation. -- Morning batch skips Weekend Outlook on Sunday. -- Registry lookup errors are actionable. - -### Done Criteria - -- Report identity, period behavior, and compatible comparison rules are stable. -- Later stages can add builders without changing CLI semantics. - -## Stage 5: Daily Briefing Builder - -### Goal - -Build the first complete report-specific briefing package without invoking the LLM. - -### Packages Introduced or Expanded - -- `internal/briefing` -- `internal/report` -- `internal/forecast` -- `internal/app` - -### Work Items - -1. Define common briefing metadata: - - Schema version. - - RunID. - - Report type. - - Variant. - - Generation time. - - Configured units and timezone. - - Valid start/end. - - Source location ID/name when provided by upstream. - - Source timestamps, SHA-256 hashes, and source warnings. -2. Define the Daily Report briefing schema. -3. Build Daily Report briefing content: - - Bottom-line inputs. - - Daypart summaries. - - Active or relevant alerts. - - Best/worst outdoor window inputs, if derivable. - - NWS narrative periods relevant to the day. - - Forecast discussion summary or selected text from the API data. - - Weather story summary or selected text when upstream support exists. -4. Add JSON output for the briefing package. -5. Add an app workflow that can generate the Daily briefing and write it to disk for inspection. - -### Deliverables - -- `weatherreporter generate daily` can produce a Daily briefing JSON artifact without calling `scriptorium`. -- Fixture-based output is stable enough for review. - -### Tests - -- Daily briefing from representative fixture. -- Alerts included/excluded correctly. -- Source context selection. -- Source warnings included correctly. -- RunID included correctly. -- Empty or quiet-weather behavior. -- Snapshot metadata completeness. - -### Done Criteria - -- The Daily briefing package is useful as prompt input. -- The app can produce the briefing artifact from real or fixture data. - -## Stage 6: Prompt Input Package and Scriptorium Render Preflight - -### Goal - -Convert a briefing package into the structured `data_package` input expected by `scriptorium` prompts and validate prompt wiring without LLM generation. - -### Key References - -- `docs/integrations/scriptorium.md` describes the CLI contract for `scriptorium render`. - -### Packages Introduced or Expanded - -- `internal/promptinput` -- `internal/briefing` -- `internal/report` -- `internal/adapters/scriptorium` -- `internal/app` - -### Work Items - -1. Define prompt input data package schema structures. -2. Build `data_package` JSON from report metadata, briefing content, source warnings, RunID, and an initially empty Recent Changes section. -3. Validate required data package fields before rendering. -4. Write data package JSON to the workspace. -5. Implement `scriptorium render` support in the adapter. -6. Invoke preflight as: - -```text -scriptorium render \ - --prompt \ - --input data_package= \ - --format json -``` - -7. Capture stdout and stderr separately. -8. Persist render/preflight output for inspection. -9. Treat render preflight as always-on before `scriptorium run` for MVP generated reports. - -### Deliverables - -- Daily Report data package can be generated and written to a file. -- The data package is suitable for `scriptorium render --input data_package=`. -- Prompt/input wiring can be checked without LLM execution. - -### Tests - -- Data package generated from Daily briefing fixture. -- Missing required fields fail validation. -- JSON output is deterministic where practical. -- Adapter command construction for `scriptorium render`. -- Nonzero render exit handling. -- Always-on preflight behavior in the generation workflow. - -### Done Criteria - -- The app can prepare and preflight a complete data package for a Daily Report. -- LLM rendering is the only missing step for the first end-to-end report. - -## Stage 7: Filesystem State Store and Metadata Baseline - -### Goal - -Persist report artifacts and metadata in a durable, inspectable structure before the first LLM-generated report. - -### Packages Introduced or Expanded - -- `internal/state` -- `internal/app` - -### Work Items - -1. Define state store interface. -2. Implement filesystem-backed store. -3. Persist briefing snapshots. -4. Persist prompt input data package files. -5. Persist `scriptorium render` preflight output. -6. Persist report metadata. -7. Add RunID as an explicit metadata concept based on generation timestamp plus report ID. -8. Name managed report files with the generation timestamp to avoid overwriting previous runs for the same valid period. -9. Link valid period, RunID, briefing snapshot, data package, preflight output, rendered report, source warnings, and source hashes in metadata. -10. Use atomic writes where practical. -11. Implement lookup for prior comparable Daily snapshots. -12. Keep paths narrow and predictable. - -### Deliverables - -- Each Daily preflight run has associated metadata, RunID, briefing snapshot, data package, and render output. -- Prior comparable snapshot lookup works for Daily Reports. - -### Tests - -- Atomic write behavior where feasible. -- Metadata round-trip. -- Snapshot path generation. -- Data package path generation. -- Preflight output path generation. -- Timestamped managed report path generation. -- RunID metadata behavior. -- Prior snapshot lookup. -- Narrow-path safety behavior. - -### Done Criteria - -- Daily report preparation leaves enough state for inspection and future Recent Changes. -- State layout is predictable and documented. - -## Stage 8: Scriptorium Run Adapter and First End-to-End Daily Report - -### Goal - -Invoke `scriptorium run` as a subprocess and produce the first rendered Markdown report. - -### Key References - -- `docs/integrations/scriptorium.md` describes the CLI contract for running `scriptorium` as a subprocess. - -### Packages Introduced or Expanded - -- `internal/adapters/scriptorium` -- `internal/app` -- `internal/state` - -### Work Items - -1. Define `scriptorium.Run` request/result types or extend the runner interface introduced for render preflight. -2. Implement subprocess execution with `exec.CommandContext`. -3. Pass arguments without shell interpolation. -4. Pass the prompt input data package with `--input data_package=`. -5. Invoke generation as: - -```text -scriptorium run \ - --prompt \ - --input data_package= \ - --out -``` - -6. Capture stderr and stdout with reasonable limits. -7. Apply timeout and cancellation. -8. Return actionable errors for nonzero exits, including exit code `2`, which can still produce output. -9. Wire Daily Report generation end-to-end: - - Fetch bundle. - - Build briefing. - - Build data package. - - Run render preflight. - - Run `scriptorium`. - - Write Markdown report. - - Persist metadata and snapshots. - -### Deliverables - -- `weatherreporter generate daily --out ./daily.md` produces a Markdown report. -- Failures include useful context. -- The first end-to-end report already has durable briefing, data package, metadata, and source provenance. - -### Tests - -- Adapter command construction using a fake command runner or fake executable. -- Nonzero exit handling. -- Exit code `2` handling. -- Timeout behavior. -- Always-on preflight before run. -- App workflow test using fake weather client and fake `scriptorium` runner. - -### Done Criteria - -- The first report can be generated end-to-end. -- `scriptorium` is isolated behind the adapter package. - -## Stage 9: Recent Changes for Daily Reports - -### Goal - -Add structured comparison of Daily Report briefing snapshots and include meaningful changes in prompt input data packages. - -### Packages Introduced or Expanded - -- `internal/changes` -- `internal/state` -- `internal/promptinput` -- `internal/app` - -### Work Items - -1. Define change summary structures. -2. Define threshold configuration. -3. Implement Daily briefing comparison. -4. Compare current snapshot to prior comparable snapshot. -5. Detect meaningful changes, such as: - - Temperature shifts. - - Precipitation timing shifts. - - Precipitation probability category changes. - - Alert changes. - - Wind gust changes. - - Snow/ice/thunder risk changes. -6. Add Recent Changes to the data package. -7. Omit or minimize Recent Changes when no meaningful changes exist. - -### Deliverables - -- Daily Report data packages include Recent Changes when appropriate. -- Daily Report generation persists current snapshot after comparison. - -### Tests - -- No prior snapshot behavior. -- No meaningful changes behavior. -- Temperature threshold crossing. -- Precipitation timing shift. -- Alert added/removed behavior. -- Comparison uses valid period and compatible strategy, not just generation time. - -### Done Criteria - -- The Daily Report can say what changed relative to a prior compatible report covering the same forecast period. -- Markdown report text is not used as the comparison source. - -## Stage 10: Tomorrow Planning Brief - -### Goal - -Add the evening Tomorrow Planning Brief using the Daily Report machinery where practical. - -### Packages Introduced or Expanded - -- `internal/report` -- `internal/briefing` -- `internal/changes` -- `internal/app` - -### Work Items - -1. Implement the `daily_tomorrow` report definition fully. -2. Reuse or specialize the Daily briefing builder for tomorrow's valid date. -3. Add any tomorrow-specific planning fields, such as: - - Morning readiness note inputs. - - Commute/school/workday concerns. - - What may change overnight. -4. Ensure comparison can find a prior compatible report covering the same valid local date. -5. Implement `run evening` as Daily Tomorrow. - -### Deliverables - -- `weatherreporter generate tomorrow` works end-to-end. -- `weatherreporter run evening` works. - -### Tests - -- Tomorrow valid-period calculation. -- Tomorrow briefing uses the correct date. -- Recent Changes can compare against a compatible prior Tomorrow, Daily, or 3-Day snapshot when configured by the registry. -- Evening batch includes only the expected report. - -### Done Criteria - -- Evening look-ahead generation is reliable. -- Daily Today and Daily Tomorrow share logic without muddling their identities. - -## Stage 11: 3-Day Outlook - -### Goal - -Add the 3-Day Outlook report using the same architecture. - -### Packages Introduced or Expanded - -- `internal/report` -- `internal/briefing` -- `internal/forecast` -- `internal/changes` -- `internal/app` - -### Work Items - -1. Implement 3-Day valid-period resolution. -2. Build a 3-Day briefing package. -3. Summarize each day or partial day: - - Overall character. - - Temperature range. - - Precipitation/storm/winter/heat/wind risks. - - Best/worst windows if derivable. - - Relevant alerts. -4. Attach broader NWS context, especially forecast discussion and weather story inputs when available. -5. Implement 3-Day Recent Changes strategy. -6. Add end-to-end generation. - -### Deliverables - -- `weatherreporter generate three-day` produces Markdown. -- Morning batch can include the 3-Day Outlook. - -### Tests - -- Three-day valid period from generation time. -- Daily aggregation across the 3-Day window. -- Alert overlap across multi-day period. -- Recent Changes across multi-day snapshots. -- Quiet-weather behavior. - -### Done Criteria - -- The 3-Day Outlook is generated using the same registry, briefing, data package, state, and rendering pipeline as the Daily Report. - -## Stage 12: Weekend Outlook - -### Goal - -Add the Weekend Outlook with day-of-week-sensitive period behavior. - -### Packages Introduced or Expanded - -- `internal/report` -- `internal/briefing` -- `internal/forecast` -- `internal/changes` -- `internal/app` - -### Work Items - -1. Implement Weekend valid-period resolution: - - Monday through Thursday: upcoming Saturday 00:00 through Monday 00:00. - - Friday: `max(generation time, Friday 18:00)` through Monday 00:00. - - Saturday: generation time through Monday 00:00. - - Sunday: normally not generated by the scheduled morning batch. -2. Build Weekend briefing package. -3. Emphasize planning fields: - - Best outdoor windows. - - Worst weather windows. - - Rain/storm timing. - - Heat/cold/wind comfort. - - Confidence and uncertainty inputs. -4. Implement Weekend Recent Changes strategy. -5. Add morning batch inclusion except Sunday. - -### Deliverables - -- `weatherreporter generate weekend` produces Markdown. -- `weatherreporter run morning` includes Weekend Outlook except Sunday. - -### Tests - -- Weekend period on each day of the week. -- Saturday remaining-weekend behavior. -- Sunday skip behavior in morning batch. -- Recent Changes across narrowed valid periods. -- Outdoor-window derivation behavior. - -### Done Criteria - -- Weekend Outlook works end-to-end and follows expected scheduling behavior. - -## Stage 13: Morning and Evening Batch Hardening - -### Goal - -Make scheduled workflows reliable enough for unattended execution by cron, systemd timers, or another orchestrator. - -### Packages Introduced or Expanded - -- `internal/app` -- `internal/cli` -- `internal/state` -- `internal/config` - -### Work Items - -1. Finalize `run morning` workflow. -2. Finalize `run evening` workflow. -3. Continue remaining independent reports after one report fails. -4. Return nonzero from the CLI if any report failed. -5. Add structured aggregate run summaries. -6. Ensure each report run records enough metadata for troubleshooting. -7. Add CLI flags for output directory and optional dry-run/data-package-only mode if desired. -8. Add logging suitable for scheduled execution. - -### Deliverables - -- Morning batch can generate Daily, 3-Day, and Weekend reports. -- Evening batch can generate Tomorrow Planning Brief. -- Failures are understandable from logs, metadata, and aggregate summaries. - -### Tests - -- Morning batch report selection. -- Evening batch report selection. -- Partial failure continues independent reports. -- Aggregate nonzero exit behavior. -- Output path behavior. -- Dry-run or data-package-only behavior, if implemented. - -### Done Criteria - -- The scheduled report system is ready for real daily use. - -## Stage 14: Manual Storm Report - -### Goal - -Add manual Storm Report generation without building the automatic monitoring agent yet. - -### Packages Introduced or Expanded - -- `internal/report` -- `internal/briefing` -- `internal/forecast` -- `internal/app` -- `internal/changes`, if needed - -### Work Items - -1. Implement Storm Report definition. -2. Require explicit storm valid-period bounds via `--start` and `--end`. -3. Build storm briefing package from: - - Active alerts. - - Forecast discussion. - - Weather story when available. - - Relevant hourly/daily periods. - - NWS narrative periods. -4. Include storm-specific fields: - - Event headline inputs. - - Timing window. - - Hazards. - - Most likely scenario inputs. - - Reasonable worst-case inputs, if supported by source context. - - Confidence and uncertainty inputs. - - What to watch next. -5. Add manual command: - - `weatherreporter generate storm --start