Remove completed roadmap cleanup plans
This commit is contained in:
@@ -1,441 +0,0 @@
|
||||
# Tomorrow Report Implementation Roadmap
|
||||
|
||||
## Purpose
|
||||
|
||||
This roadmap defines the staged implementation plan for
|
||||
`docs/roadmap/tomorrow.md`. It is written for an LLM coding agent that will
|
||||
implement each stage in order. The conceptual target state, user intent, and
|
||||
locked product decisions live in `docs/roadmap/tomorrow.md`; this file defines
|
||||
the concrete implementation sequence.
|
||||
|
||||
This is future-work planning. Do not treat the behavior described here as
|
||||
implemented until the corresponding code, tests, examples, and non-roadmap docs
|
||||
are updated.
|
||||
|
||||
## Implementation Guardrails
|
||||
|
||||
- Preserve public CLI syntax: `weatherreporter generate tomorrow`.
|
||||
- Make a clean pre-release break from report ID `daily_tomorrow`; do not add
|
||||
compatibility aliases.
|
||||
- Keep report identity, prompt IDs, template IDs, artifact groups, output names,
|
||||
and comparison policy centralized in `internal/report`.
|
||||
- Reuse the existing `generated_text_template` workflow implemented for Hourly.
|
||||
- Keep Scriptorium details behind the existing adapter boundary.
|
||||
- Keep Go responsible for deterministic facts, valid periods, module snapshots,
|
||||
structured generated-text validation, and final Markdown template rendering.
|
||||
- Keep templates responsible for wording and layout.
|
||||
- Keep generated JSON schemas and Markdown templates as embedded asset files,
|
||||
not inline Go strings.
|
||||
- Preserve current managed artifact behavior except where report identity
|
||||
intentionally changes from `daily_tomorrow` to `tomorrow`.
|
||||
|
||||
## Stage 1: Report Identity Split
|
||||
|
||||
Goal: make Tomorrow an independent report ID and artifact identity while
|
||||
preserving the public `generate tomorrow` command.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Replace `report.DailyTomorrow` with `report.Tomorrow` whose value is
|
||||
`"tomorrow"`.
|
||||
- Rename report-definition helpers and resolvers around the new identity:
|
||||
`dailyTomorrowDefinition` to `tomorrowDefinition`,
|
||||
`dailyTomorrowModules` to `tomorrowModules`, and
|
||||
`resolveDailyTomorrow` to `resolveTomorrow`.
|
||||
- Update `report.DefaultRegistry`, `Registry.All`, batch resolution, and tests
|
||||
so the built-in report order contains `tomorrow` instead of
|
||||
`daily_tomorrow`.
|
||||
- Update `internal/app` so `app.ReportTomorrow` resolves to `report.Tomorrow`.
|
||||
- Keep the valid period as the next local civil day.
|
||||
- Keep evening batch behavior: `run evening` should still generate the Tomorrow
|
||||
report.
|
||||
- Change Tomorrow definition identity fields to:
|
||||
- `ID: report.Tomorrow`
|
||||
- `Name: "Tomorrow Report"`
|
||||
- `ArtifactGroup: "tomorrow"`
|
||||
- `BatchOutputName: "tomorrow.md"`
|
||||
- `Generated: true`
|
||||
- `CompatiblePriorIDs: []report.ID{report.Tomorrow}`
|
||||
- `ComparisonStrategy: report.CompareSameValidDate`
|
||||
- Keep the current Tomorrow module composition initially, renamed to
|
||||
`tomorrowModules`, so the prompt data package continues to include the
|
||||
daypart, precipitation, alert, SPC, AFD, weather story, tomorrow planning,
|
||||
and hourly facts already available.
|
||||
- Update all code and tests that assert `daily_tomorrow` paths, metadata,
|
||||
RunIDs, prior compatibility, or registry IDs.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- No production-code references to `report.DailyTomorrow` or report ID
|
||||
`daily_tomorrow` remain.
|
||||
- `weatherreporter generate tomorrow` still parses and resolves successfully.
|
||||
- Evening batch contains `tomorrow`.
|
||||
- Managed workspace artifact paths and distributor identity values now use
|
||||
`tomorrow`.
|
||||
|
||||
Suggested validation:
|
||||
|
||||
```bash
|
||||
go test ./internal/report ./internal/app ./internal/cli ./internal/state
|
||||
```
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Stage 2: Tomorrow GeneratedText Contract
|
||||
|
||||
Goal: add structured Tomorrow LLM output validation and schema assets.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Add `internal/generatedtext/tomorrow.go` with:
|
||||
|
||||
```go
|
||||
type Tomorrow struct {
|
||||
Summary string `json:"summary"`
|
||||
ForecastDiscussion []string `json:"forecast_discussion"`
|
||||
PrecipitationTiming string `json:"precipitation_timing,omitempty"`
|
||||
Confidence string `json:"confidence,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
- Add `generatedtext.ValidateTomorrow`.
|
||||
- Use `json.Decoder.DisallowUnknownFields`.
|
||||
- Reject multiple JSON values.
|
||||
- Trim `Summary`, `PrecipitationTiming`, `Confidence`, and each
|
||||
`ForecastDiscussion` paragraph.
|
||||
- Drop blank discussion paragraphs after trimming, then require at least one
|
||||
remaining paragraph.
|
||||
- Reject blank `Summary`.
|
||||
- Return normalized JSON with the same public field names.
|
||||
- Add `internal/reporttemplate/schemas/tomorrow.generated_text.schema.json`.
|
||||
The schema should:
|
||||
- require `summary`;
|
||||
- require `forecast_discussion`;
|
||||
- define `forecast_discussion` as an array of strings with at least one item;
|
||||
- allow optional `precipitation_timing` and `confidence`;
|
||||
- reject additional properties.
|
||||
- Add `internal/reporttemplate/prompts/tomorrow.generated_text.md` as the
|
||||
maintained Scriptorium prompt source asset. This file is a source contract for
|
||||
out-of-band Scriptorium prompt registration; weatherreporter does not need to
|
||||
load prompt Markdown at runtime.
|
||||
- Add Tomorrow to `internal/reporttemplate` schema lookup.
|
||||
- Update app generated-text validation dispatch so it can return either
|
||||
`generatedtext.Hourly` or `generatedtext.Tomorrow`. Prefer a small generic
|
||||
dispatch shape such as:
|
||||
|
||||
```go
|
||||
func validateGeneratedText(def report.Definition, data []byte) (any, []byte, error)
|
||||
```
|
||||
|
||||
Then type-check the returned value in render-context dispatch.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Tomorrow generated text rejects unknown fields, missing required fields,
|
||||
blank summary, and no usable forecast discussion paragraphs.
|
||||
- Optional `precipitation_timing` and `confidence` are trimmed and omitted from
|
||||
normalized JSON when empty.
|
||||
- Hourly generated text behavior is unchanged.
|
||||
|
||||
Suggested validation:
|
||||
|
||||
```bash
|
||||
go test ./internal/generatedtext ./internal/reporttemplate ./internal/app
|
||||
```
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Stage 3: Daypart Presentation Fields
|
||||
|
||||
Goal: add only the daypart fields needed to keep the Tomorrow template
|
||||
composable without moving prose construction into Go.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Extend the `derived_daypart_summaries` module output with presentation
|
||||
helpers that are facts, not complete sentences:
|
||||
- `display_name`, for example `Morning`;
|
||||
- `dominant_condition_lower`, for inline template text;
|
||||
- `temperature_phrase_f`, such as `low 70s`, `upper 60s`, or
|
||||
`upper 60s to mid-70s`;
|
||||
- `mention_precipitation`, true when max PoP is at or above the existing
|
||||
hourly forecast precipitation mention threshold, currently 20%;
|
||||
- `max_pop_time_label`, using friendly local hour format such as `8:00 AM`
|
||||
when max PoP time exists.
|
||||
- Reuse the existing hourly forecast precipitation mention threshold constant
|
||||
rather than adding a user config field in this change.
|
||||
- Keep existing structured numeric fields in the module output.
|
||||
- Do not add a prewritten `daypart_line` string.
|
||||
- Do not add wind prose in this stage unless tests show the initial template
|
||||
needs a specific structured wind fact. If wind wording is needed, add a
|
||||
small structured wind field, not a full sentence.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Daypart module output has enough structured fields for a readable Tomorrow
|
||||
template.
|
||||
- The output remains useful for YAML prompt packages.
|
||||
- No generated prose sentence is hard-coded into the module.
|
||||
|
||||
Suggested validation:
|
||||
|
||||
```bash
|
||||
go test ./internal/briefing ./internal/promptinput
|
||||
```
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Stage 4: Tomorrow Render Context And Template
|
||||
|
||||
Goal: render Tomorrow Markdown from structured generated text, module outputs,
|
||||
and report metadata.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Add a dedicated Tomorrow render context under `internal/generatedtext`, for
|
||||
example:
|
||||
|
||||
```go
|
||||
type TomorrowRenderContext struct {
|
||||
Report TomorrowReportContext
|
||||
GeneratedText Tomorrow
|
||||
Modules TomorrowTemplateModules
|
||||
Collected facts.CollectedFacts
|
||||
Derived facts.DerivedFacts
|
||||
}
|
||||
```
|
||||
|
||||
- Add `TomorrowReportContext` with:
|
||||
- `Title`, for example `Sunday's Weather`;
|
||||
- `ForecastDate`;
|
||||
- `ForecastDateLabel`, for example `Sunday, June 15, 2026`;
|
||||
- `ForecastDayName`, for example `Sunday`;
|
||||
- `GeneratedAt`;
|
||||
- `GeneratedAtLabel`, for example
|
||||
`Saturday, June 14, 2026 at 9:14 AM`;
|
||||
- `ValidPeriod`;
|
||||
- `Timezone`.
|
||||
- Construct `Title` in Go, not in the template.
|
||||
- Add `TomorrowTemplateModules` with pointer fields for the module outputs used
|
||||
by the template:
|
||||
- `Metadata`;
|
||||
- `DerivedDailySummary`;
|
||||
- `DerivedDaypartSummaries`;
|
||||
- `PrecipTiming`;
|
||||
- `AlertDigest`;
|
||||
- `SPCConvectiveOutlooks`;
|
||||
- `AreaForecastDiscussion`;
|
||||
- `SPCConvectiveDiscussion`;
|
||||
- `WeatherStory`;
|
||||
- `TomorrowPlanning`.
|
||||
- Add an ordered daypart slice for the template, derived from the configured
|
||||
daypart order rather than ranging directly over a map. This can live in
|
||||
`TomorrowTemplateModules`, for example `Dayparts []TomorrowDaypartContext`.
|
||||
- Add `BuildTomorrowRenderContext`.
|
||||
- Add `internal/reporttemplate/templates/tomorrow.md.tmpl`.
|
||||
- Add Tomorrow to `internal/reporttemplate` template lookup.
|
||||
- Template shape:
|
||||
- title;
|
||||
- forecast date;
|
||||
- generated timestamp;
|
||||
- `GeneratedText.Summary`;
|
||||
- deterministic `Daypart Forecast` bullets in configured order;
|
||||
- conditional `Precipitation Timing` only when precipitation windows exist;
|
||||
- deterministic precipitation window bullets before optional
|
||||
`GeneratedText.PrecipitationTiming`;
|
||||
- `Forecast Discussion` with one paragraph per
|
||||
`GeneratedText.ForecastDiscussion` item.
|
||||
- Keep current conditions and hourly forecast available through the data
|
||||
package and render context, but do not render them in the initial Tomorrow
|
||||
template unless the template explicitly uses them.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- The template renders without map-order nondeterminism.
|
||||
- Precipitation Timing is omitted when no precipitation windows exist.
|
||||
- Forecast Discussion supports multiple paragraphs.
|
||||
- Missing optional modules produce clean omission or fallback behavior, not
|
||||
template execution errors.
|
||||
|
||||
Suggested validation:
|
||||
|
||||
```bash
|
||||
go test ./internal/generatedtext ./internal/reporttemplate ./internal/briefing
|
||||
```
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Stage 5: App Workflow Integration
|
||||
|
||||
Goal: route Tomorrow through the generated-text-template workflow end to end.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Change Tomorrow report definition to:
|
||||
- `PromptID: "weather.tomorrow_generated_text"`
|
||||
- `GenerationMode: report.GenerationModeGeneratedTextTemplate`
|
||||
- `TemplateID: "tomorrow"`
|
||||
- `GeneratedTextSchemaID: "tomorrow"`
|
||||
- Update `internal/app.buildRenderContext` dispatch:
|
||||
- hourly template requires `generatedtext.Hourly`;
|
||||
- tomorrow template requires `generatedtext.Tomorrow`;
|
||||
- unsupported type/template combinations return actionable errors.
|
||||
- Ensure Scriptorium `run` writes raw generated text to a `.json` path for
|
||||
Tomorrow, matching the existing generated-text-template workflow.
|
||||
- Ensure normalized generated text, render context JSON, generated Markdown,
|
||||
metadata, and final report artifacts are persisted through existing state
|
||||
helpers.
|
||||
- Ensure app errors include report ID `tomorrow` and RunID context.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- `weatherreporter generate tomorrow` no longer invokes Scriptorium for full
|
||||
Markdown.
|
||||
- The workflow validates Scriptorium JSON output, builds a Tomorrow render
|
||||
context, and renders Markdown locally.
|
||||
- Hourly generated-text-template behavior remains unchanged.
|
||||
|
||||
Suggested validation:
|
||||
|
||||
```bash
|
||||
go test ./internal/app ./internal/state ./internal/adapters/scriptorium
|
||||
```
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Stage 6: CLI, State, Distributor, And Batch Behavior
|
||||
|
||||
Goal: update cross-package behavior affected by the report ID clean break.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Update CLI tests and command-output expectations for `generate tomorrow`.
|
||||
- Update state/path tests so managed artifacts, snapshots, data packages,
|
||||
generated-text artifacts, render contexts, and report files use artifact group
|
||||
`tomorrow`.
|
||||
- Update batch tests:
|
||||
- evening batch emits report ID `tomorrow`;
|
||||
- batch output copy name remains `tomorrow.md`;
|
||||
- partial-failure behavior is unchanged.
|
||||
- Update Recent Changes tests:
|
||||
- Tomorrow compares only against prior `tomorrow` snapshots;
|
||||
- Daily Today no longer treats Tomorrow as a compatible prior unless the
|
||||
implementation explicitly keeps that relationship for Daily Today only.
|
||||
- Update distributor notification tests so rendered template variables use:
|
||||
- `report_id=tomorrow`;
|
||||
- `artifact_group=tomorrow`;
|
||||
- `batch_output_name=tomorrow.md`.
|
||||
- Update config tests so report module overrides use `reports.tomorrow`.
|
||||
Do not accept `reports.daily_tomorrow` unless a future explicit
|
||||
compatibility decision reverses the clean break.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Public CLI syntax is stable.
|
||||
- Persisted artifacts and distributor request context use the new report ID.
|
||||
- Batch behavior is unchanged except for the new ID.
|
||||
- No tests rely on `daily_tomorrow`.
|
||||
|
||||
Suggested validation:
|
||||
|
||||
```bash
|
||||
go test ./internal/cli ./internal/app ./internal/state ./internal/config ./internal/report
|
||||
```
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Stage 7: Documentation And Examples
|
||||
|
||||
Goal: align implemented docs and maintained examples after the code change.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Update non-roadmap docs only after the behavior is implemented.
|
||||
- Inspect and update:
|
||||
- `docs/cli.md`;
|
||||
- `docs/config.md`;
|
||||
- `docs/operations.md`;
|
||||
- `docs/troubleshooting.md`, if new failure modes are introduced;
|
||||
- `docs/internal/report-registry.md`;
|
||||
- `docs/internal/generatedtext.md`;
|
||||
- `docs/internal/reporttemplate.md`;
|
||||
- `docs/internal/state.md`;
|
||||
- `docs/templates.md`;
|
||||
- relevant Scriptorium and distributor integration docs only if their
|
||||
weatherreporter-facing contract changed.
|
||||
- Update `examples/config.yml` if it references Tomorrow modules or
|
||||
`reports.daily_tomorrow`.
|
||||
- Keep future Today/Daily split language only under `docs/roadmap/`.
|
||||
- Do not document unimplemented Today or generic Daily products as current
|
||||
behavior.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Non-roadmap docs describe implemented behavior only.
|
||||
- Docs use report ID `tomorrow`.
|
||||
- Examples load under current config validation.
|
||||
- No stale user-facing references to `daily_tomorrow` remain outside historical
|
||||
roadmap context.
|
||||
|
||||
Suggested validation:
|
||||
|
||||
```bash
|
||||
rg -n "daily_tomorrow|Daily Tomorrow|weather.daily_report" README.md docs examples internal
|
||||
git diff --check
|
||||
```
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Stage 8: Final Validation
|
||||
|
||||
Goal: verify the completed cutover as a coherent behavior change.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
go test ./internal/report ./internal/generatedtext ./internal/reporttemplate ./internal/briefing ./internal/app ./internal/cli ./internal/state
|
||||
go test ./...
|
||||
go run ./cmd/weatherreporter --help
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Also run targeted stale-symbol checks:
|
||||
|
||||
```bash
|
||||
rg -n "DailyTomorrow|dailyTomorrow|daily_tomorrow" internal docs examples
|
||||
rg -n "weather.tomorrow_generated_text|TemplateID:.*tomorrow|GeneratedTextSchemaID:.*tomorrow" internal docs
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Full test suite passes.
|
||||
- Help output still shows `generate tomorrow`.
|
||||
- No production-code stale `daily_tomorrow` symbols remain.
|
||||
- Generated-text-template artifacts for Tomorrow are persisted in the same
|
||||
categories as Hourly.
|
||||
- Existing Hourly behavior still passes tests.
|
||||
|
||||
This stage is suitable for one implementation prompt.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None block implementation. The required decisions are locked by
|
||||
`docs/roadmap/tomorrow.md` and this implementation plan:
|
||||
|
||||
- Tomorrow uses report ID `tomorrow`.
|
||||
- Tomorrow uses prompt ID `weather.tomorrow_generated_text`.
|
||||
- Tomorrow uses template ID and generated-text schema ID `tomorrow`.
|
||||
- Tomorrow forecast discussion is an array of paragraph strings.
|
||||
- `daily_tomorrow` compatibility aliases are intentionally not preserved.
|
||||
|
||||
## Global Validation Checklist
|
||||
|
||||
- `go test ./...`
|
||||
- `go run ./cmd/weatherreporter --help`
|
||||
- `git diff --check`
|
||||
- `rg -n "DailyTomorrow|dailyTomorrow|daily_tomorrow" internal docs examples`
|
||||
- Confirm `weatherreporter generate tomorrow` uses structured JSON from
|
||||
Scriptorium and renders final Markdown locally.
|
||||
- Confirm distributor notification context uses `report_id=tomorrow` and
|
||||
`artifact_group=tomorrow`.
|
||||
- Confirm examples contain no unimplemented fields and no secrets.
|
||||
Reference in New Issue
Block a user