diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md new file mode 100644 index 0000000..bfe8445 --- /dev/null +++ b/docs/roadmap/implementation.md @@ -0,0 +1,601 @@ +# Today Report Implementation Roadmap + +## Purpose + +This roadmap defines the staged implementation plan for +`docs/roadmap/today.md`. It is written for an LLM coding agent that will +implement each stage in order. + +This is a planning document only. It may describe unimplemented behavior because +it lives under `docs/roadmap/`. + +## Source Roadmap + +`docs/roadmap/today.md` is the feature roadmap and target-state authority for +the Today report. This implementation plan provides the concrete sequence for +reaching that target. + +If this implementation plan and `today.md` conflict, update the feature roadmap +first so it remains the conceptual source of truth, then update this file. + +## Locked Decisions + +- `today` is a new independent generated-text-template report. +- `today` does not replace the existing `daily_today` report in this roadmap. +- `weatherreporter generate today` is a new public command. +- `weatherreporter generate daily` remains the existing daily command and must + not alias to Today. +- `reports.today` is a new independent config override key. +- `reports.daily` and `reports.daily_today` remain mapped to the existing daily + report while that report exists. +- Morning batch includes `today` in the position currently occupied by + `daily_today`. +- Morning batch should not include both `today` and `daily_today`. +- Evening batch remains `tomorrow`. +- New Today runtime identity uses report ID `today`, artifact group `today`, + batch output `today.md`, template ID `today`, generated-text schema ID + `today`, and prompt ID `weather.today_generated_text`. +- Historical `daily_today` workspace artifacts are not migrated. +- Today uses its own deterministic `today_planning` module. +- Today does not reuse Tomorrow's prompt, template, schema, report ID, artifact + group, or public planning stanza. +- Scriptorium registration remains out of band. Weatherreporter invokes + Scriptorium by prompt ID and passes the data package as it does for existing + generated-text reports. + +## Implementation Principles + +- Keep report identity and public name resolution in `internal/report`. +- Keep CLI parsing in `internal/cli`; do not move domain policy into CLI. +- Keep generated-text validation and render-context construction in + `internal/generatedtext`. +- Keep embedded schema/template assets in `internal/reporttemplate`. +- Keep module IDs in `internal/module` and module builders in + `internal/briefing`. +- Keep the app orchestration path shared with other generated-text-template + reports. +- Do not introduce a new workflow engine, CLI framework, plugin system, or + compatibility migration layer for old workspace artifacts. +- Do not make `daily` and `today` compatibility aliases. +- Preserve existing managed artifact layout conventions. + +## Stage 1: Today ID Scaffold And Planning Module + +Goal: add the internal Today report ID scaffold and Today planning module +without making Today public or changing batch behavior yet. + +This stage should compile and pass focused module/report tests while the +existing active `daily_today` report remains unchanged. + +### Implementation + +- In `internal/report/definition.go`, add `Today ID = "today"`. +- Do not remove or alter `DailyToday` in this stage. +- In `internal/module/module.go`, add: + - `TodayPlanning ID = "today_planning"`; + - `TodayPlanningOptions struct{}`. +- Add `internal/briefing/today_planning_module.go`. +- Add `TodayPlanningModule` with initial prompt-facing fields: + - `morning_readiness`; + - `commute_school_workday_concerns`; + - `outdoor_planning`; + - `late_day_change_watch`. +- Add a private deterministic helper, such as `buildTodayPlanning`, near the + existing planning summary helpers. +- Reuse private helper functions from Tomorrow planning only when the + underlying logic is identical. Do not expose or reuse `TomorrowPlanningModule` + or the `tomorrow_planning` stanza. +- Register `TodayPlanning` in `internal/briefing/modules.go` with: + - stanza name `today_planning`; + - supported reports `[]report.ID{report.Today}`; + - required derived facts matching the daily-summary/daypart facts it uses; + - `MissingDataEmpty` unless implementation discovers a stricter requirement + is needed. +- Add `report.Today` to module support lists where Today should be eligible: + - all-report modules; + - daypart modules; + - narrative forecast; + - hourly forecast; + - derived daily summary; + - derived daypart summaries. +- Keep existing `report.DailyToday` support unchanged. + +### Files To Inspect + +- `internal/report/definition.go` +- `internal/module/module.go` +- `internal/briefing/modules.go` +- `internal/briefing/tomorrow_planning_module.go` +- `internal/briefing/summary_helpers.go` +- `internal/briefing/derived_modules_test.go` +- `internal/briefing/modules_test.go` + +### Acceptance Criteria + +- `module.TodayPlanning` is registered and buildable for `report.Today`. +- `today_planning` is rejected for unsupported reports. +- The new module emits deterministic snake_case JSON fields. +- Existing Tomorrow planning behavior is unchanged. +- Existing Daily Today behavior is unchanged. + +### Tests + +Add or update tests for: + +- Today planning output shape. +- Today planning supported report validation. +- Unsupported report validation, including Tomorrow and Daily Today. +- Empty/fallback behavior when useful planning facts are missing. + +Run: + +```sh +go test ./internal/briefing ./internal/module ./internal/report +go test ./... +git diff --check +``` + +Stage size: suitable for one implementation prompt. + +## Stage 2: Today GeneratedText, Schema, Prompt, Template, And Render Context + +Goal: add Today generated-text assets and render-context support while keeping +the report inactive until Stage 3. + +### Implementation + +- Add `internal/generatedtext/today.go`. +- Add `generatedtext.Today` with fields: + - `Summary string`; + - `ForecastDiscussion []string`; + - `PrecipitationTiming string`; + - `Confidence string`. +- Add `ValidateToday` with Tomorrow-equivalent semantics: + - strict JSON; + - reject unknown fields; + - reject trailing JSON values; + - trim string fields; + - trim and drop blank discussion paragraphs; + - require nonblank `summary`; + - require at least one nonblank `forecast_discussion` paragraph; + - return canonical normalized JSON using the same public field names. +- Add `internal/reporttemplate/schemas/today.generated_text.schema.json`. +- Add `internal/reporttemplate/templates/today.md.tmpl`. +- Add `internal/reporttemplate/prompts/today.generated_text.md`. +- Add `TodayRenderContext`, `TodayReportContext`, `TodayTemplateModules`, and + `BuildTodayRenderContext` in `internal/generatedtext`. +- Today report context should include: + - `Title` exactly `Today's Weather`; + - `ForecastDate`; + - `ForecastDateLabel`; + - `ForecastDayName`; + - `GeneratedAt`; + - `GeneratedAtLabel`; + - `ValidPeriod`; + - `Timezone`. +- Today template modules should include at least: + - `Metadata`; + - `CurrentConditions`; + - `HourlyForecast`; + - `DerivedDailySummary`; + - `DerivedDaypartSummaries`; + - ordered daypart rows; + - `PrecipTiming`; + - `AlertDigest`; + - `SPCConvectiveOutlooks`; + - `AreaForecastDiscussion`; + - `SPCConvectiveDiscussion`; + - `WeatherStory`; + - `TodayPlanning`. +- Share private render-context helper mechanics with Tomorrow where appropriate, + such as snapshot lookup and daypart row ordering. +- Do not expose Tomorrow-specific types through the Today context. +- Register Today in the generated-text catalog with schema ID `today` and + template ID `today`. +- Add Today schema/template entries to `internal/reporttemplate` if explicit + asset maps are still used. +- The Today prompt asset should instruct the LLM to produce only the structured + JSON fields expected by the Today schema, using the data package as the only + weather source. + +### Files To Inspect + +- `internal/generatedtext/tomorrow.go` +- `internal/generatedtext/render_context.go` +- `internal/generatedtext/catalog.go` +- `internal/generatedtext/*_test.go` +- `internal/reporttemplate/reporttemplate.go` +- `internal/reporttemplate/templates/tomorrow.md.tmpl` +- `internal/reporttemplate/schemas/tomorrow.generated_text.schema.json` +- `internal/reporttemplate/prompts/tomorrow.generated_text.md` + +### Acceptance Criteria + +- Today generated-text validation mirrors Tomorrow behavior. +- Today schema accepts exactly the intended public fields. +- Today template renders from structured module data and generated text. +- Today render context uses Today-specific public types. +- Today generated-text catalog lookup works once a report definition references + schema/template ID `today`. +- Existing Hourly and Tomorrow generated-text behavior is unchanged. + +### Tests + +Add or update tests for: + +- `ValidateToday` success, missing required fields, unknown fields, trailing + JSON, malformed JSON, blank strings, paragraph trimming, and canonical JSON. +- Today JSON schema lookup. +- Today template lookup. +- Today render context labels, daypart ordering, populated modules, and nil + optional modules. +- Generated-text catalog completeness support for Today once the report + definition is active. If the report is not active until Stage 3, add this + assertion in Stage 3. + +Run: + +```sh +go test ./internal/generatedtext ./internal/reporttemplate ./internal/briefing +go test ./... +git diff --check +``` + +Stage size: suitable for one implementation prompt. + +## Stage 3: Today Report Definition And Batch Integration + +Goal: add Today as an active report and switch morning batch to Today without +aliasing or replacing the existing `daily` command/report. + +### Implementation + +- Add a Today definition, preferably in a new `internal/report/today_report.go` + file. +- The Today definition must use: + - `ID: report.Today`; + - `Name: "Today Report"` or equivalent user-facing report name; + - `PromptID: "weather.today_generated_text"`; + - `GenerationMode: report.GenerationModeGeneratedTextTemplate`; + - `TemplateID: "today"`; + - `GeneratedTextSchemaID: "today"`; + - `ComparisonStrategy: report.CompareSameValidDate`; + - `ArtifactGroup: "today"`; + - `BatchOutputName: "today.md"`; + - `Generated: true`; + - `CompatiblePriorIDs: []report.ID{report.Today}`; + - `Morning: true`; + - current-local-civil-day resolver. +- Keep the existing Daily Today definition and report ID unchanged. +- Today default modules must include, in this order unless implementation tests + justify a more useful order: + - `metadata`; + - `current_conditions`; + - `narrative_forecast`; + - `derived_daily_summary`; + - `derived_daypart_summaries`; + - `precip_timing`; + - `alert_digest`; + - `spc_convective_outlooks`; + - `area_forecast_discussion`; + - `spc_convective_discussion`; + - `weather_story`; + - `outdoor_windows`; + - `hourly_forecast`; + - `today_planning`. +- Update `internal/report/registry.go`: + - default registry includes both Daily Today and Today; + - `All()` includes both reports in a stable order, with Today near the other + current-day report. +- Update `internal/report/period.go`: + - morning batch resolves Today first; + - morning batch does not include Daily Today; + - morning Sunday skip behavior for Weekend is unchanged; + - evening batch remains Tomorrow. +- Update report name helpers in `internal/report/names.go`: + - add `CommandNameToday = "today"`; + - `IDForCommandName("today") == report.Today`; + - `IDForCommandName("daily")` remains the existing Daily Today report; + - `CommandNames()` includes both `today` and `daily` as distinct commands. +- Update config-key resolution: + - `IDForConfigKey("today") == report.Today`; + - `IDForConfigKey("daily")` remains the existing Daily Today report; + - `IDForConfigKey("daily_today")` remains the existing Daily Today report. +- Update structured Recent Changes dispatch so Today uses the daily comparison + logic currently used by Daily Today and Tomorrow. +- Update briefing/package variant logic so Today produces variant `today`. + +### Files To Inspect + +- `internal/report/definition.go` +- `internal/report/daily_report.go` +- `internal/report/registry.go` +- `internal/report/period.go` +- `internal/report/names.go` +- `internal/report/period_test.go` +- `internal/briefing/modules.go` +- `internal/briefing/package.go` +- `internal/app/app.go` +- `internal/config/reports.go` +- `internal/config/config_test.go` +- `internal/changes` + +### Acceptance Criteria + +- `report.DefaultRegistry()` has active definitions for both `today` and the + existing daily report. +- Morning batch report IDs are `today,three_day,weekend` when Weekend is + included. +- Sunday morning batch report IDs are `today,three_day`. +- `daily` and `today` command names resolve to different report IDs. +- `reports.today` and `reports.daily` / `reports.daily_today` resolve to + different report IDs. +- Today report metadata, RunID, artifact group, batch output name, data-package + path, report path, and distributor template values use `today`. +- Existing manual Daily, Tomorrow, Hourly, Three-Day, Weekend, and Storm + behavior is unchanged. + +### Tests + +Add or update tests for: + +- report registry membership and `All()` order; +- `IDForCommandName` for `today` and `daily`; +- `CommandNames()` stable order; +- `IDForConfigKey` for `today`, `daily`, and `daily_today`; +- proof that Today and Daily resolve to different report IDs; +- Today valid period with default current local date; +- Today valid period with explicit `--date` / request date; +- morning and Sunday morning batch order; +- Recent Changes dispatch for Today; +- module registry support for Today modules. + +Run: + +```sh +go test ./internal/report ./internal/config ./internal/briefing ./internal/changes +go test ./internal/app ./internal/cli +go test ./... +go run ./cmd/weatherreporter --help +git diff --check +``` + +Stage size: this is a broad but coherent report/batch integration stage. It is +suitable for one implementation prompt if the agent keeps the scope to report +identity and tests. + +## Stage 4: App, CLI, Config, And Workflow Integration + +Goal: make `generate today`, batches, artifacts, and distributor notification +work end-to-end through the existing app flow while keeping `generate daily` +separate. + +### Implementation + +- Add `app.ReportToday` if app keeps report-kind constants. +- Keep `app.ReportDaily` mapped to the existing daily command/report. +- Update CLI help text to show `generate today` as a distinct command. +- Keep `generate daily` help text separate. +- Parse `--date YYYY-MM-DD` for Today. + - If omitted, use current local date in the configured timezone. + - Keep existing `daily --date` behavior unchanged. +- Ensure app generation resolves: + - `today` to `report.Today`; + - `daily` to the existing daily report. +- Ensure Today generated-text-template flow persists: + - raw generated text; + - structured Scriptorium run result; + - normalized generated text; + - render context; + - rendered Markdown report; + - metadata; + - optional output copy. +- Ensure Today prompt invocation uses `weather.today_generated_text`. +- Ensure Scriptorium output path for Today generated text is a JSON artifact, + matching existing generated-text-template reports. +- Ensure state and metadata inspection work for Today run IDs. +- Ensure distributor notification uses the managed Today Markdown report path, + not optional output copies. +- Ensure distributor template variables resolve with: + - `report_id=today`; + - `artifact_group=today`; + - `batch_output_name=today.md`; + - valid-period variables based on the Today valid period. +- Update fake Scriptorium scripts in app/CLI tests to return valid Today JSON + when prompt ID is `weather.today_generated_text`. + +### Files To Inspect + +- `internal/app/app.go` +- `internal/app/app_test.go` +- `internal/cli/root.go` +- `internal/cli/root_test.go` +- `internal/state` +- `internal/adapters/scriptorium` +- `internal/adapters/distributor` +- `internal/config` +- `examples/config.yml` + +### Acceptance Criteria + +- `weatherreporter generate today` succeeds in tests through the generated-text + template path. +- `weatherreporter generate daily` still succeeds through the existing daily + path and does not produce Today identity artifacts. +- `weatherreporter generate today --date YYYY-MM-DD` resolves that local civil + day. +- Morning batch uses Today artifacts and `today.md` output copy names. +- Notification debug artifacts record Today report ID, pipeline ID, bundle ID, + and bundle paths. +- Optional `--out` and batch `--out-dir` behavior remains unchanged except for + the new Today output name in morning batch. +- No secret values appear in CLI output, metadata, or notification artifacts. + +### Tests + +Add or update tests for: + +- CLI parser support for `generate today`. +- CLI parser proof that `generate daily` remains separate. +- CLI `--date` support for Today. +- App workflow artifacts for Today. +- App output copy behavior for Today. +- App workflow proof that Daily still produces existing daily identity. +- Batch output directory using `today.md`. +- Distributor request values for Today. +- Inspect commands loading Today run metadata/modules/data package/sources. + +Run: + +```sh +go test ./internal/app ./internal/cli ./internal/state +go test ./internal/adapters/scriptorium ./internal/adapters/distributor +go test ./... +go run ./cmd/weatherreporter --help +git diff --check +``` + +Stage size: suitable for one implementation prompt. + +## Stage 5: Documentation And Examples + +Goal: update implemented docs and maintained examples after the code exists. + +### Implementation + +Update non-roadmap docs to describe implemented behavior only: + +- `docs/cli.md`: + - add `generate today`; + - keep `generate daily` documented as a separate command; + - document `--date` for Today generation; + - keep Daily docs accurate for the existing command. +- `docs/config.md`: + - document `reports.today`; + - keep `reports.daily` / `reports.daily_today` documentation separate while + the existing daily report remains implemented. +- `docs/operations.md`: + - update morning batch behavior; + - document Today artifact paths; + - update distributor identity examples if present. +- `docs/templates.md`: + - document Today template variables. +- `docs/internal/report-registry.md`: + - document Today report identity and its independence from Daily Today. +- `docs/internal/generatedtext.md`: + - document Today generated-text schema and validation. +- `docs/internal/reporttemplate.md`: + - document Today template/schema/prompt assets. +- `docs/internal/module.md`: + - document `today_planning`. +- `docs/internal/app-orchestration.md`: + - document Today only where the generic generated-text-template workflow does + not already cover it. +- `examples/config.yml`: + - add Today module override examples only if useful; + - keep existing daily examples accurate if they remain; + - keep no raw secrets. + +Roadmap docs: + +- Keep future Daily rewrite work only under `docs/roadmap/`. +- Do not document the future Daily rewrite outside roadmap docs. + +### Acceptance Criteria + +- Non-roadmap docs describe Today as implemented and distinct from Daily. +- Non-roadmap docs do not imply `today` and `daily` are aliases. +- Maintained examples load successfully. +- CLI examples match actual `--help` output and parser behavior. +- Documentation follows `docs/policy/documentation.md`. + +### Tests And Checks + +Run: + +```sh +go test ./internal/config ./internal/cli ./internal/app +go test ./... +go run ./cmd/weatherreporter --help +git diff --check +``` + +Manual checks: + +```sh +rg -n "today.*alias|daily.*alias|daily_today.*retired|replace.*daily_today" README.md docs examples internal +``` + +Expected remaining matches should be limited to roadmap discussion that clearly +states there is no aliasing in this feature. + +Stage size: suitable for one implementation prompt. + +## Stage 6: Final Validation And Stale-Symbol Sweep + +Goal: confirm Today is fully implemented as a separate report and no accidental +Daily/Today aliasing remains. + +### Required Validation + +Run: + +```sh +go test ./... +go run ./cmd/weatherreporter --help +git diff --check +``` + +Run focused package checks: + +```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/state ./internal/promptinput ./internal/changes +go test ./internal/adapters/distributor ./internal/adapters/scriptorium ./internal/adapters/weatherapi +``` + +Run stale/alias checks: + +```sh +rg -n "IDForCommandName\\(\"daily\"\\).*Today|IDForConfigKey\\(\"daily\"\\).*Today" internal +rg -n "weather.today_generated_text|today.md|report.Today" internal docs examples +``` + +Manual review: + +- `generate today` is listed in help and docs. +- `generate daily` remains listed separately. +- `generate daily` does not resolve to report ID `today`. +- `reports.daily` and `reports.today` are distinct config override keys. +- Morning batch output includes `today.md`. +- Today data package and metadata use report ID `today`. +- Distributor request values use `today`. +- Existing manual Daily behavior remains available. +- Existing Tomorrow behavior is unchanged. + +Stage size: suitable for one implementation prompt. + +## Deferred Work + +Do not include these in the Today implementation: + +- Rewriting the `daily` command/report in Today/Tomorrow style. +- Removing or retiring the existing `daily_today` report. +- Making `daily` an alias for `today`. +- Making `today` an alias for `daily`. +- Migrating historical `daily_today` workspace artifacts. +- Adding an inspection compatibility layer that rewrites old metadata IDs. +- Changing Tomorrow template/schema behavior except where shared helpers require + tests to be adjusted. +- Changing Distributor adapter behavior beyond Today template values. + +## Open Questions + +No open questions block implementation. + +The future relationship between `daily`, `daily_today`, and `today` is +explicitly deferred to the next Daily rewrite roadmap. For this implementation, +the required behavior is that Today and Daily remain separate commands and +separate report IDs. diff --git a/docs/roadmap/today.md b/docs/roadmap/today.md index 840cc72..52e1203 100644 --- a/docs/roadmap/today.md +++ b/docs/roadmap/today.md @@ -2,23 +2,49 @@ ## Purpose -This roadmap defines the work needed to add a new `today` report type. The -report is not implemented. Current report behavior is documented outside -`docs/roadmap/`. +This roadmap defines the target state and implementation work needed to add a +new independent generated-text-template `today` report. + +The report is not implemented yet. Current report behavior remains documented +outside `docs/roadmap/`. ## Intent Today should be an independent generated-text-template report focused on the current local civil day. It should mirror the implemented Tomorrow Report structure, but its valid period, identity, prompt, template, schema, workspace -paths, and distributor identity should use `today`. +paths, distributor identity, and deterministic planning module should use +`today`. -Today should not replace the existing Daily Today report in the same change. -Daily Today currently remains the direct-Markdown `daily` command and report ID -`daily_today`. The Today report should be added as a separate product so the -project can compare the generated-text-template version with the existing -direct-Markdown daily report before deciding whether to retire or rename either -one. +This is a clean, separate report addition: + +- `today` becomes a new canonical current-day generated-text report ID. +- The existing `daily_today` report remains independent for now. +- The existing public `daily` command remains independent for now. +- `weatherreporter generate today` and `weatherreporter generate daily` must + not be aliases for each other. +- Morning batch should use `today`, not `daily_today`. +- New Today artifacts use the `today` artifact group and report ID. +- Existing historical `daily_today` workspace artifacts do not need migration. + +The next planned feature will rewrite the `daily` command/report in the same +style as Today and Tomorrow. Do not pre-solve that future work in this roadmap. + +## Locked Decisions + +- `today` is independent of `daily_today`. +- `generate today` is independent of `generate daily`. +- No command compatibility aliases between `today` and `daily`. +- No config-key compatibility aliases between `reports.today` and + `reports.daily` / `reports.daily_today`. +- Morning batch includes `today`. +- Morning batch should not include `daily_today` once Today is implemented. +- `today` needs its own deterministic planning module analogous to + `TomorrowPlanning`. +- Add a new public `generate today` command. +- Do not reuse the Tomorrow prompt, template, schema, report ID, artifact group, + or planning stanza for Today. +- Do not attempt to migrate old workspace artifacts. ## Target Report Shape @@ -55,6 +81,8 @@ The precipitation section should render only when precipitation windows exist for the current-day valid period. The deterministic daypart forecast should follow the same module-driven presentation approach used by Tomorrow. +The title should be stable and explicit: `Today's Weather`. + ## Report Identity Add a report definition with: @@ -67,12 +95,44 @@ Add a report definition with: - generated-text schema ID: `today` - artifact group: `today` - batch output name: `today.md` -- prior compatibility: Today Report only -- comparison strategy: same valid date -- valid period: current local civil day in the effective report timezone +- prior compatibility: Today only +- comparison strategy: same valid local date +- valid period: current local civil day in the effective report timezone, + `[00:00, next 00:00)` -Do not change existing `daily`, `daily_today`, or morning batch behavior in the -same implementation unless a separate roadmap explicitly calls for that change. +Keep the existing `daily_today` report definition independent unless the future +Daily rewrite roadmap removes or replaces it. + +Command and config resolution must remain distinct: + +- `generate today` resolves to report ID `today`. +- `generate daily` resolves to the existing daily report ID. +- `reports.today` config overrides apply only to report ID `today`. +- `reports.daily` and `reports.daily_today` config overrides continue to apply + only to the existing daily report while that report exists. + +## Batch Behavior + +Morning batch should include Today in the position currently occupied by Daily +Today. + +Target morning order: + +1. `today` +2. `three_day` +3. `weekend`, when existing weekend rules include it + +Existing Sunday behavior should remain equivalent except with Today replacing +Daily Today in the batch: scheduled Sunday morning should include `today` and +`three_day`, and should skip `weekend`. + +Evening batch behavior is unchanged and should continue to include `tomorrow`. +Hourly remains excluded from scheduled batches unless a later roadmap changes +that. + +The existing `daily` command/report may remain available for manual generation, +but it is no longer the morning batch current-day product once Today is +implemented. ## GeneratedText Contract @@ -107,6 +167,15 @@ Validation should match Tomorrow semantics: - require at least one nonblank discussion paragraph - return canonical normalized JSON with the same public field names +Add a dedicated prompt asset for the source prompt text if prompt assets are +maintained locally: + +- `internal/reporttemplate/prompts/today.generated_text.md` + +Scriptorium registration remains out of band. Weatherreporter should invoke the +Today prompt by prompt ID and pass the data package as it does for other +generated-text reports. + ## Template Context Add dedicated Today types under `internal/generatedtext`, rather than reusing @@ -125,7 +194,7 @@ type TodayRenderContext struct { `TodayReportContext` should include: -- `Title`, for example `Today's Weather` +- `Title`, exactly `Today's Weather` - `ForecastDate` - `ForecastDateLabel`, for example `Friday, May 29, 2026` - `ForecastDayName`, for example `Friday` @@ -134,8 +203,7 @@ type TodayRenderContext struct { - `ValidPeriod` - `Timezone` -`TodayTemplateModules` should expose the same categories the Today template -needs: +`TodayTemplateModules` should expose the categories the Today template needs: - `Metadata` - `CurrentConditions` @@ -149,17 +217,21 @@ needs: - `AreaForecastDiscussion` - `SPCConvectiveDiscussion` - `WeatherStory` +- `TodayPlanning` -Add `TodayPlanning` only if deterministic today-specific planning facts are -introduced. Do not reuse `TomorrowPlanning` for Today. +Today may share private helper functions with Tomorrow render-context +construction when the helper represents identical mechanics, such as snapshot +lookup or daypart row ordering. Do not expose Tomorrow-specific types through +the Today template context. ## Module Composition The default module composition should mirror Tomorrow where the same facts are -useful for the current-day report: +useful for the current-day report, with a Today-specific planning module: - `metadata` - `current_conditions` +- `narrative_forecast` - `derived_daily_summary` - `derived_daypart_summaries` - `precip_timing` @@ -168,71 +240,130 @@ useful for the current-day report: - `area_forecast_discussion` - `spc_convective_discussion` - `weather_story` +- `outdoor_windows` - `hourly_forecast` +- `today_planning` Keep module outputs deterministic and prompt-facing. Do not add prose-only Go fields unless the template needs a structured fact that cannot be expressed from existing module data. +## Today Planning Module + +Add a Today-specific deterministic planning module: + +- module ID: `today_planning` +- stanza name: `today_planning` +- options type: `TodayPlanningOptions` +- output type: `TodayPlanningModule` +- supported report: `today` + +The module should be analogous to `TomorrowPlanning`, but current-day oriented. +It should not reuse the public `TomorrowPlanningModule` type or +`tomorrow_planning` stanza. + +Recommended initial fields: + +- `morning_readiness` +- `commute_school_workday_concerns` +- `outdoor_planning` +- `late_day_change_watch` + +The exact field names may be adjusted during implementation if tests and docs +make a better shape clear, but the module must remain deterministic and +current-day specific. Private helper functions may be shared with Tomorrow +planning when the underlying logic is truly identical. + ## Implementation Plan 1. Add Today report identity. - Add `report.Today`. - - Add command-name and config-key support for `today`. + - Keep the existing `report.DailyToday` active for now. + - Add command-name support for `today`. + - Do not change the `daily` command mapping in this roadmap. + - Add config-key support for `today`. + - Do not change `reports.daily` or `reports.daily_today` mapping in this + roadmap. - Add a report definition with generated-text-template identity fields. - - Add current-local-day valid-period resolution. - - Add report tests for ID, prompt ID, artifact group, command mapping, - config key mapping, and valid period. + - Add current-local-civil-day valid-period resolution. + - Update report tests for ID, prompt ID, artifact group, command mapping, + config key mapping, batch order, and valid period. -2. Add Today generated-text validation and schema. +2. Add Today planning module. + - Add `module.TodayPlanning`. + - Add `TodayPlanningOptions`. + - Add `TodayPlanningModule` and builder under `internal/briefing`. + - Register it in the default module registry for `report.Today`. + - Add tests for output shape, supported report, unsupported reports, and + empty/fallback behavior. + +3. Add Today generated-text validation and schema. - Add `generatedtext.Today`. - Add `ValidateToday`. - Add `today.generated_text.schema.json`. - Add generated-text validation tests matching Tomorrow coverage. -3. Add Today template and render context. +4. Add Today template and render context. - Add `today.md.tmpl`. - Add `TodayRenderContext`, `TodayReportContext`, and `TodayTemplateModules`. - Add `BuildTodayRenderContext`. - - Reuse the internal snapshot lookup helper for module extraction. + - Use the internal snapshot lookup helper for module extraction. - Add render-context and template tests for populated and omitted optional modules. -4. Register Today in the generated-text catalog and embedded asset lookups. +5. Register Today in generated-text and embedded asset catalogs. - Add a generated-text catalog entry. - - Add reporttemplate template/schema map entries. + - Add reporttemplate template/schema map entries if the current asset + lookup still uses explicit maps. - Extend catalog completeness tests. - Add unsupported schema/template combination coverage if needed. -5. Integrate app and CLI workflows. +6. Integrate app, CLI, config, batches, and distributor workflows. - Ensure `weatherreporter generate today` resolves and runs through the generated-text-template workflow. + - Ensure `weatherreporter generate daily` remains the existing daily + workflow and does not resolve to Today. + - Ensure morning batch uses `today` instead of `daily_today`. - Persist raw generated text, structured run result, normalized generated text, render context, Markdown report, metadata, and optional output copy. - Ensure distributor notification uses the managed Today Markdown report path and Today template values. + - Ensure report metadata, RunID, artifact paths, data-package paths, batch + output names, and distributor template variables use `today`. -6. Update current-behavior docs after implementation. +7. Update implemented documentation after code changes. - Update `docs/cli.md`, `docs/config.md`, `docs/operations.md`, `docs/templates.md`, `docs/internal/report-registry.md`, `docs/internal/generatedtext.md`, `docs/internal/reporttemplate.md`, - `docs/internal/app-orchestration.md`, and maintained examples as needed. - - Keep any unresolved Daily Today replacement decision only in roadmap docs. + `docs/internal/module.md`, `docs/internal/app-orchestration.md`, and + maintained examples as needed. + - Non-roadmap docs must describe only the implemented Today behavior after + the code changes land. + - Keep `daily` and `today` documented as distinct commands/reports. ## Test Plan Add or update tests for: -- report registry membership and command/config-key resolution +- report registry membership for both `today` and existing `daily_today` +- `today` command-name resolution to `today` +- `daily` command-name resolution remaining independent from `today` +- config-key resolution for `reports.today` +- config-key resolution for `reports.daily` and `reports.daily_today` + remaining independent from `reports.today` +- morning batch order with `today`, `three_day`, and conditional `weekend` +- Sunday morning batch skip behavior with `today` - current-day valid period in the configured timezone - generated-text unknown fields, trailing JSON, missing required fields, blank fields, paragraph trimming, and canonical output - generated-text catalog completeness - template/schema asset lookup -- render context labels, module extraction, nil optional modules, and daypart - ordering +- render context labels, module extraction, nil optional modules, Today + planning extraction, and daypart ordering +- Today planning module output and supported-report validation - app workflow artifacts for `generate today` +- `generate daily` remains separate from `generate today` - optional `--out` copy behavior - distributor template values and managed report notification source - CLI parser support for `generate today` @@ -242,20 +373,52 @@ Suggested validation: ```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 ./... go run ./cmd/weatherreporter --help git diff --check ``` +## Documentation Updates After Implementation + +Update implemented docs only after the code exists: + +- `docs/cli.md`: document `generate today` and keep `generate daily` + documented as a separate existing command. +- `docs/config.md`: document `reports.today` module overrides separately from + existing daily report overrides. +- `docs/operations.md`: document Today artifact paths, morning batch behavior, + and distributor upload identity. +- `docs/templates.md`: document Today template variables. +- `docs/internal/report-registry.md`: document Today report identity and its + independence from Daily Today. +- `docs/internal/generatedtext.md`: document Today generated-text schema and + validation behavior. +- `docs/internal/reporttemplate.md`: document Today template assets. +- `docs/internal/module.md`: document `today_planning`. +- `docs/internal/app-orchestration.md`: document Today workflow only if it + differs from the generic generated-text-template flow. + +## Ambiguities Addressed + +- Independence: `today` is separate from `daily_today`; it does not replace the + existing report definition in this roadmap. +- Command behavior: `generate today` and `generate daily` are not aliases. +- Config behavior: `reports.today` is not an alias for `reports.daily` or + `reports.daily_today`. +- Batch behavior: morning batch includes `today` instead of `daily_today`. +- Planning module: Today has its own deterministic planning module. +- Artifact identity: new Today artifacts and distributor values use `today`. +- Historical artifacts: old `daily_today` workspace files are not migrated. + ## Open Decisions -- Whether Today should eventually replace the existing Daily Today report. -- Whether morning batch should include Today, Daily Today, or both. -- Whether Today needs a dedicated deterministic planning module. -- Whether the public `daily` command should remain direct Markdown after Today - exists. +No open decisions remain that block implementation. -Do not resolve these decisions implicitly while adding the initial `today` -report. Keep the first implementation narrowly focused on a separate -current-day generated-text-template report. +Future decisions that should not be resolved in this roadmap: + +- How the future rewritten `daily` command/report should relate to `today`. +- Whether the future Daily rewrite removes or retires `daily_today`. +- Whether old `daily_today` workspace artifacts should ever receive a migration + or inspection compatibility layer.