# Near-Term Report Implementation Roadmap ## Purpose This roadmap defines the concrete implementation sequence for `docs/roadmap/near-term.md`. It is written for an LLM coding agent that will implement each stage in order. This is a future-work roadmap. Until a stage is implemented, non-roadmap docs must not describe `near_term` behavior as available. ## Source Feature Roadmap Use `docs/roadmap/near-term.md` as the authoritative feature roadmap for user intent, target behavior, and policy choices. This document is the implementation plan. If the target behavior changes, update `near-term.md` first, then update this roadmap. ## Locked Implementation Decisions - Add report ID `near_term` and Go constant `report.NearTerm`. - Add CLI command `weatherreporter generate near-term`. - Do not add `--date`, `--start`, `--end`, or duration flags for this report. - Do not add `near_term` to morning or evening batches in the first implementation. - Define the valid-period duration with a package-owned constant, initially `6` hours. - Resolve the valid period as `[generation_time, generation_time + 6h)` in the effective report timezone. - Use prompt ID `weather.near_term_report`. - Use artifact group `near-term` and batch output name `near-term.md`. - Add comparison strategy constant `CompareRollingWindow = "rolling_window"`. - Declare `CompatiblePriorIDs: []report.ID{report.NearTerm}`, but do not emit Recent Changes for `near_term` in the first implementation. - Keep state prior lookup returning `nil` for rolling-window reports until a future comparison algorithm is designed. - Default module order is: 1. `metadata` 2. `current_conditions` 3. `hourly_forecast` 4. `precip_timing` 5. `alert_digest` 6. `spc_convective_outlooks` 7. `area_forecast_discussion` 8. `spc_convective_discussion` 9. `weather_story` - Configure the near-term `area_forecast_discussion` module with only `key_messages` and `short_term` sections. - Do not include daily/daypart modules in the default near-term composition. - Alert and SPC modules must use existing valid-period overlap behavior. - Preserve existing public behavior for all current report types. ## Stage 1: Report Identity And Period Resolution Goal: add the `near_term` report definition, constants, registry entry, and rolling six-hour valid-period resolver. Files to inspect: - `internal/report/definition.go` - `internal/report/registry.go` - `internal/report/period.go` - `internal/report/daily_report.go` - `internal/report/period_test.go` - `internal/state/filesystem.go` Implementation: - Add `NearTerm ID = "near_term"` in `internal/report/definition.go`. - Add `CompareRollingWindow ComparisonStrategy = "rolling_window"`. - Add `internal/report/near_term_report.go`. - Define a package-local duration constant in that file, for example: ```go const nearTermHours = 6 ``` - Add `nearTermDefinition()` returning: - `ID: NearTerm` - `Name: "Near-Term Report"` - `PromptID: "weather.near_term_report"` - `ComparisonStrategy: CompareRollingWindow` - `ArtifactGroup: "near-term"` - `BatchOutputName: "near-term.md"` - `Generated: true` - `CompatiblePriorIDs: []ID{NearTerm}` - `Modules: nearTermModules()` - no `Morning` or `Evening` membership - `resolve: resolveNearTerm` - Implement `resolveNearTerm` as generation-time anchored: ```go localNow := req.Now.In(req.Location) return timeutil.Period{ Start: localNow, End: localNow.Add(nearTermHours * time.Hour), }, nil ``` - Add `nearTermDefinition()` to `DefaultRegistry()`. - Add `NearTerm` to `Registry.All()` in a stable order after `DailyTomorrow` and before `ThreeDay`. - Do not change `BatchReports`. - Leave `state.FindPriorSnapshot` behavior unchanged for `CompareRollingWindow`; it should return `nil` because it only supports same-date and weekend lookup. Tests: - Add report period tests for: - lookup succeeds for `NearTerm`; - `Registry.All()` includes `NearTerm`; - fixed generation time resolves to exactly six hours; - timezone-aware start and end use the effective location; - valid period is not civil-day truncated; - metadata RunID includes `near_term`; - batch membership remains unchanged. - Update registry metadata/path tests to include: - artifact group `near-term`; - batch output name `near-term.md`; - generated `true`; - compatible prior IDs `[]ID{NearTerm}`; - comparison strategy `CompareRollingWindow`. Validation: ```bash go test ./internal/report ./internal/state ``` This stage is small enough for one implementation prompt. ## Stage 2: Module Compatibility And Default Composition Goal: make existing modules compatible with `near_term` where appropriate and declare the default module composition. Files to inspect: - `internal/report/near_term_report.go` - `internal/briefing/modules.go` - `internal/module/module.go` - `internal/briefing/modules_test.go` - `internal/briefing/base_modules_test.go` - `internal/briefing/derived_modules_test.go` Implementation: - Add `nearTermModules()` in `internal/report/near_term_report.go`. - Use explicit module items in this order: - `module.Metadata` - `module.CurrentConditions` - `module.HourlyForecast` - `module.PrecipTiming` - `module.AlertDigest` - `module.SPCConvectiveOutlooks` - `module.AreaForecastDiscussion` with options: ```go module.AreaForecastDiscussionOptions{ Sections: []string{"key_messages", "short_term"}, } ``` - `module.SPCConvectiveDiscussion` - `module.WeatherStory` - Expand module `SupportedReports` in `internal/briefing/modules.go`: - include `report.NearTerm` in `allReports`; - include `report.NearTerm` for `HourlyForecast`; - do not include `report.NearTerm` for `NarrativeForecast`; - do not include `report.NearTerm` in `daypartReports`; - do not include `report.NearTerm` for `DerivedDailySummary`, `DerivedDaypartSummaries`, `OutdoorWindows`, or `TomorrowPlanning`. - Keep `PrecipTiming`, `AlertDigest`, `SPCConvectiveOutlooks`, `AreaForecastDiscussion`, `SPCConvectiveDiscussion`, and `WeatherStory` compatible through `allReports`. - Do not add a new module ID in this stage. Tests: - Add or update module registry tests proving: - default near-term composition validates; - all default near-term modules have builders; - daily/daypart-only modules reject `report.NearTerm`; - `HourlyForecast` builds for `report.NearTerm`; - AFD options for the near-term default include only key messages and short term. - Add a focused AFD module test that near-term options omit long term when the source provides it. Validation: ```bash go test ./internal/report ./internal/briefing ./internal/module ``` This stage is small enough for one implementation prompt. ## Stage 3: Derived Facts For Rolling Windows Goal: teach `internal/facts` to build the facts needed by the near-term module set without requiring daily summaries or daypart summaries. Files to inspect: - `internal/facts/facts.go` - `internal/facts/facts_test.go` - `internal/forecast` - `internal/timeutil` - `internal/briefing/modules.go` Implementation: - Add `report.NearTerm` handling in `facts.BuildDerived`. - For near-term: - populate `ValidPeriodHourlyPeriods` from the resolved six-hour valid period; - populate `ValidPeriodNarrativePeriods` if the existing generic selection already does so, but do not require it for default near-term modules; - build `PrecipTiming` from `ValidPeriodHourlyPeriods`; - select alert overlaps using the near-term valid period; - select SPC outlooks and discussions using the near-term valid period; - do not build or require `DailySummaries`; - do not build or require `DaypartSummaries`; - do not build `StormWindowSummary`. - Preserve existing daily, tomorrow, three-day, weekend, and storm derivation. - If any existing helper assumes civil-day coverage, keep near-term on the generic valid-period hourly path instead of reusing that helper. Tests: - Add facts tests for: - valid-period hourly selection over a rolling six-hour window; - precipitation timing based only on the near-term hourly slice; - alert overlap inclusion/exclusion by near-term period; - SPC outlook inclusion/exclusion by near-term period; - SPC discussion records retained only for retained overlapping SPC days; - no daily/daypart facts required. - Add a regression test that an unsupported future report still returns an actionable derivation error. Validation: ```bash go test ./internal/facts ./internal/forecast ./internal/timeutil ``` This stage is small enough for one implementation prompt. ## Stage 4: App Report Mapping And CLI Command Goal: add explicit `generate near-term` support while preserving existing CLI syntax and app behavior. Files to inspect: - `internal/app/app.go` - `internal/app/app_test.go` - `internal/cli/root.go` - `internal/cli/root_test.go` - `cmd/weatherreporter/main.go` Implementation: - Add app report kind: ```go ReportNearTerm ReportKind = "near-term" ``` - Map `ReportNearTerm` to `report.NearTerm` in `reportIDForCommand`. - Add `near-term` to CLI generate report parsing. - Add help usage line: ```text weatherreporter generate near-term [--config PATH] [--units VALUE] [--tz NAME] [--out PATH] ``` - Reuse existing generate command flags: - allow `--config`; - allow `--units`; - allow `--tz`; - allow `--out`; - do not allow or require `--date`; - do not allow or require storm `--start` / `--end`. - Ensure the CLI returns an actionable error for unknown report names as today. - Do not change batch commands. Tests: - Add CLI parser tests for: - `generate near-term`; - `generate near-term --config PATH`; - `generate near-term --units us --tz America/Chicago --out PATH`; - rejected `generate near-term --date YYYY-MM-DD`; - rejected storm-only `--start` / `--end` on near-term if current parser behavior supports this distinction. - Add app resolution tests proving `ReportNearTerm` resolves `report.NearTerm`. - Update help tests to assert `generate near-term` appears. - Existing generate and run command tests must remain unchanged. Validation: ```bash go test ./internal/app ./internal/cli go run ./cmd/weatherreporter --help ``` This stage is small enough for one implementation prompt. ## Stage 5: End-To-End Generation And Artifact Behavior Goal: prove a near-term report can run through the app workflow and persist the expected artifacts. Files to inspect: - `internal/app/app_test.go` - `internal/state` - `internal/promptinput` - Weather API fixture server helpers in app tests - distributor notification tests if report paths are asserted Implementation: - Add an app-level test that generates `ReportNearTerm` with fixture weather data and fake Scriptorium. - Assert: - `ReportResult.Metadata.ReportID == report.NearTerm`; - prompt ID is `weather.near_term_report`; - managed report path uses artifact group `near-term`; - data package path uses artifact group `near-term`; - module snapshot contains the near-term module list in order; - data package categories are unchanged; - `hourly_forecast` contains only periods overlapping the six-hour window; - `precip_timing` reflects only the six-hour window; - `alert_digest` and SPC stanzas respect overlap behavior; - AFD includes key messages and short term but not long term; - `recent_changes.items` is empty when no rolling-window comparison exists. - Add an app-level case for distributor notification only if existing tests assert report-specific path rendering. The expected distributor templates should work through existing `{artifact_group}`, `{report_id}`, `{valid_start_date}`, and `{valid_start_time}` values without special near-term behavior. - Do not add `near_term` to scheduled batch tests. Tests: - Add stale-key checks if generated YAML is inspected: - module intervals use `period_begins` / `period_ends`; - top-level metadata keeps canonical `valid_period`. - Ensure optional output copy via `--out` continues to use existing app copy behavior for generated reports. Validation: ```bash go test ./internal/app ./internal/state ./internal/promptinput ``` This stage is small enough for one implementation prompt. ## Stage 6: Config Overrides And Examples Goal: allow configured module overrides for `near_term` while keeping maintained examples valid. Files to inspect: - `internal/config/reports.go` - `internal/config/config_test.go` - `docs/config.md` after implementation - `examples/config.yml` Implementation: - Add report config key aliases: - `near_term` - `near-term` - Map both aliases to `report.NearTerm`. - Validate near-term module overrides through the existing module registry. - Ensure incompatible modules fail clearly, for example `derived_daily_summary` should not be compatible with `near_term`. - Update config tests for: - successful `reports.near_term.deterministic_modules`; - successful `reports.near-term.deterministic_modules`; - duplicate canonical near-term aliases rejected if both are present; - incompatible daily-only module rejected. - Update `examples/config.yml` only if it enumerates all report module overrides. If it does not need a near-term override, do not add one just to demonstrate the feature. Validation: ```bash go test ./internal/config ./internal/report ./internal/briefing ``` This stage is small enough for one implementation prompt. ## Stage 7: Implemented Documentation Goal: update non-roadmap documentation after the feature exists. Files to inspect and update: - `docs/cli.md` - `docs/config.md` - `docs/operations.md` - `docs/internal/report-registry.md` - `docs/internal/module.md` - `docs/internal/facts.md` - `docs/internal/briefing.md` - `docs/internal/prompt-input.md` - `examples/config.yml`, only if changed in Stage 6 Documentation requirements: - Describe `generate near-term` in CLI docs after implementation. - Document that the first version is explicit generation only and is not part of scheduled batches. - Document the six-hour rolling valid period and that the duration is an internal constant, not a config field. - Document near-term report identity, artifact group, batch output name, prompt ID, and module composition in internal docs. - Document near-term config override keys only if Stage 6 implements them. - Keep deferred items under roadmap docs only: - configurable duration; - batch membership; - dedicated `derived_near_term_summary`; - near-term Recent Changes comparison output. Acceptance criteria: - Non-roadmap docs describe only implemented behavior. - Docs do not imply a duration config field or scheduled batch behavior. - Maintained examples load. Validation: ```bash go test ./internal/config git diff --check ``` This stage is small enough for one implementation prompt. ## Stage 8: Final Validation Goal: run the complete project validation after implementation and docs are updated. Commands: ```bash go test ./... go run ./cmd/weatherreporter --help git diff --check ``` Manual checks: - `weatherreporter --help` lists `generate near-term`. - No existing command syntax changed. - `near_term` is absent from morning and evening batch membership. - No non-roadmap docs describe unimplemented deferred near-term work. - No config examples include secrets or invalid module IDs. - Distributor bundle path rendering remains template-driven and does not need report-specific branching. This stage is small enough for one implementation prompt. ## Deferred Work Do not include these in the first implementation: - user-configurable near-term duration; - scheduled near-term batch membership or a new high-frequency batch command; - dedicated `derived_near_term_summary`; - narrative forecast periods in the default near-term module list; - separate AFD section modules; - rolling-window Recent Changes comparison output; - custom CLI duration flags; - distributor-specific behavior for near-term reports. ## Open Questions None block implementation. Recommendation: keep the first version explicit and narrow: `generate near-term`, six-hour constant, no batch membership, no Recent Changes output. This fits the existing registry/module architecture and lets prompt quality be tested before adding scheduler or comparison complexity. Viable alternative: implement rolling-window Recent Changes immediately by finding the most recent prior `near_term` report with an overlapping or adjacent window. That could be useful later, but it needs a well-defined comparison contract and should not block the first report implementation.