Add staged implementation plan for the new today report type

This commit is contained in:
2026-06-15 08:48:04 -05:00
parent 7efd8b5855
commit 7b4c73d1e6
2 changed files with 809 additions and 45 deletions

View File

@@ -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.

View File

@@ -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.