Add staged implementation plan for the new today report type
This commit is contained in:
601
docs/roadmap/implementation.md
Normal file
601
docs/roadmap/implementation.md
Normal 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.
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user