Add an implementation plan to convert the tomorrow report into the new hybrid deterministic/LLM format
This commit is contained in:
441
docs/roadmap/implementation.md
Normal file
441
docs/roadmap/implementation.md
Normal file
@@ -0,0 +1,441 @@
|
||||
# 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.
|
||||
276
docs/roadmap/tomorrow.md
Normal file
276
docs/roadmap/tomorrow.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# Tomorrow Report Roadmap
|
||||
|
||||
## Purpose
|
||||
|
||||
This roadmap defines the target state for making Tomorrow an independent
|
||||
generated-text-template report. The feature is not implemented yet, so this
|
||||
document lives under `docs/roadmap/`.
|
||||
|
||||
## Intent
|
||||
|
||||
Tomorrow should become its own report product, not a variant of the Daily
|
||||
Report. The current CLI command `weatherreporter generate tomorrow` should
|
||||
remain, but the internal report ID, prompt ID, template, schema, workspace
|
||||
paths, and distributor identity should use `tomorrow`.
|
||||
|
||||
The report should combine deterministic daypart and precipitation facts with
|
||||
LLM prose for the high-level summary, optional precipitation context, and
|
||||
forecast discussion. The resulting Markdown should be predictable and
|
||||
template-driven, similar to the implemented Hourly Report.
|
||||
|
||||
Longer term, Today, Tomorrow, and Daily may all become separate report products
|
||||
with different prompts, templates, and deterministic sections. This roadmap
|
||||
starts that split with Tomorrow.
|
||||
|
||||
## Target Report Shape
|
||||
|
||||
Example structure:
|
||||
|
||||
```markdown
|
||||
# Sunday's Weather
|
||||
|
||||
**Forecast Date:** Sunday, June 15, 2026
|
||||
**Generated:** Saturday, June 14, 2026 at 9:14 AM
|
||||
|
||||
<GeneratedText summary>
|
||||
|
||||
## Daypart Forecast
|
||||
|
||||
- **Overnight:** <deterministic daypart line>
|
||||
- **Morning:** <deterministic daypart line>
|
||||
- **Midday:** <deterministic daypart line>
|
||||
- **Afternoon:** <deterministic daypart line>
|
||||
- **Evening:** <deterministic daypart line>
|
||||
|
||||
## Precipitation Timing
|
||||
|
||||
- **1:00 AM** to **5:00 AM**: Precipitation is expected during this period. The peak precipitation chance is 59% at 2:00 AM.
|
||||
- <optional GeneratedText precipitation_timing>
|
||||
|
||||
## Forecast Discussion
|
||||
|
||||
<GeneratedText forecast_discussion paragraphs>
|
||||
```
|
||||
|
||||
`Precipitation Timing` should render only when at least one precipitation
|
||||
window exists for the valid period. The threshold for precipitation windows
|
||||
remains the existing precipitation-window threshold, currently 40%.
|
||||
|
||||
## Locked Decisions
|
||||
|
||||
- Replace report ID `daily_tomorrow` with `tomorrow`.
|
||||
- Do not preserve compatibility aliases for `daily_tomorrow`; this is a
|
||||
pre-release clean break.
|
||||
- Keep public CLI syntax: `weatherreporter generate tomorrow`.
|
||||
- Use generated-text-template generation for Tomorrow, not full Markdown
|
||||
generation by Scriptorium.
|
||||
- Use a dedicated Scriptorium prompt ID, template ID, and schema ID:
|
||||
- prompt ID: `weather.tomorrow_generated_text`
|
||||
- template ID: `tomorrow`
|
||||
- generated-text schema ID: `tomorrow`
|
||||
- Use `ArtifactGroup: "tomorrow"` and `BatchOutputName: "tomorrow.md"`.
|
||||
- Use `CompatiblePriorIDs: []report.ID{report.Tomorrow}`.
|
||||
- Keep valid-period behavior: Tomorrow covers the next local civil day.
|
||||
- Keep Morning/Evening batch behavior unless explicitly changed later; evening
|
||||
batch should still include Tomorrow.
|
||||
- Future Today/Daily split is out of scope for this roadmap.
|
||||
|
||||
## GeneratedText Contract
|
||||
|
||||
Add a Tomorrow GeneratedText schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"summary": "string",
|
||||
"forecast_discussion": ["string"],
|
||||
"precipitation_timing": "string",
|
||||
"confidence": "string"
|
||||
}
|
||||
```
|
||||
|
||||
Required:
|
||||
|
||||
- `summary`
|
||||
- `forecast_discussion`
|
||||
|
||||
Optional:
|
||||
|
||||
- `precipitation_timing`
|
||||
- `confidence`
|
||||
|
||||
`forecast_discussion` should be an array of paragraph strings so Scriptorium
|
||||
can return multi-paragraph discussion without embedding paragraph delimiters in
|
||||
one string. Empty or whitespace-only discussion paragraphs should be rejected or
|
||||
trimmed out during validation; after trimming, at least one paragraph is
|
||||
required.
|
||||
|
||||
`confidence` may be validated and persisted but does not need to render in the
|
||||
initial template.
|
||||
|
||||
## Template Context
|
||||
|
||||
Add a dedicated Tomorrow render context rather than reusing Hourly context
|
||||
types.
|
||||
|
||||
Recommended top-level shape:
|
||||
|
||||
```go
|
||||
type TomorrowRenderContext struct {
|
||||
Report TomorrowReportContext
|
||||
GeneratedText Tomorrow
|
||||
Modules TomorrowTemplateModules
|
||||
Collected facts.CollectedFacts
|
||||
Derived facts.DerivedFacts
|
||||
}
|
||||
```
|
||||
|
||||
`TomorrowReportContext` should include:
|
||||
|
||||
- `Title`: for example `Sunday's Weather`
|
||||
- `ForecastDate`: canonical local forecast date if useful
|
||||
- `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`
|
||||
|
||||
Do not derive the possessive title in the template. Go should provide `Title`
|
||||
so wording is consistent and easy to test.
|
||||
|
||||
`TomorrowTemplateModules` should expose the module outputs needed by the
|
||||
template:
|
||||
|
||||
- `Metadata`
|
||||
- `DerivedDailySummary`
|
||||
- `DerivedDaypartSummaries`
|
||||
- `PrecipTiming`
|
||||
- `AlertDigest`
|
||||
- `SPCConvectiveOutlooks`
|
||||
- `AreaForecastDiscussion`
|
||||
- `SPCConvectiveDiscussion`
|
||||
- `WeatherStory`
|
||||
- `TomorrowPlanning`, if still useful
|
||||
|
||||
Current conditions and hourly forecast can remain in the module snapshot and
|
||||
data package if useful for Scriptorium, but they do not need to render in the
|
||||
initial Tomorrow template unless a later design calls for them.
|
||||
|
||||
## Daypart Forecast
|
||||
|
||||
The Daypart Forecast should be deterministic but composable. Avoid adding a
|
||||
single prewritten Go `DaypartLine` string that makes template wording rigid.
|
||||
|
||||
Add presentation-friendly fields to `derived_daypart_summaries` only where they
|
||||
avoid awkward template logic. Likely useful fields:
|
||||
|
||||
- display name, such as `Overnight` or `Morning`;
|
||||
- lower-case dominant condition text for inline sentences;
|
||||
- rounded temperature range phrase if available;
|
||||
- precipitation mention flag using the existing hourly line mention threshold
|
||||
concept, currently 20%;
|
||||
- max precipitation probability and friendly max time;
|
||||
- optional wind phrase or wind range only if deterministic wind wording is
|
||||
clearly needed.
|
||||
|
||||
The initial implementation may keep daypart bullet wording simple. It should be
|
||||
easy to revise the template text without editing Go unless new facts are
|
||||
needed.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
1. Report identity split
|
||||
- Rename `report.DailyTomorrow` to `report.Tomorrow` with ID `tomorrow`.
|
||||
- Update registry order, resolver references, CLI mapping, batch selection,
|
||||
state metadata expectations, docs, and tests.
|
||||
- Preserve `weatherreporter generate tomorrow`.
|
||||
- Accept that workspace paths, RunIDs, distributor bundle IDs, and report
|
||||
URLs change from `daily_tomorrow` to `tomorrow`.
|
||||
|
||||
2. GeneratedText contract
|
||||
- Add `generatedtext.Tomorrow`, validation, normalized JSON output, and
|
||||
tests.
|
||||
- Add `tomorrow.generated_text.schema.json`.
|
||||
- Add `internal/reporttemplate/prompts/tomorrow.generated_text.md` as the
|
||||
maintained prompt source asset.
|
||||
- Update app validation dispatch to use the Tomorrow schema.
|
||||
|
||||
3. Template and render context
|
||||
- Add `internal/reporttemplate/templates/tomorrow.md.tmpl`.
|
||||
- Add Tomorrow template/schema lookup entries.
|
||||
- Add `BuildTomorrowRenderContext`.
|
||||
- Update app render-context dispatch for template ID `tomorrow`.
|
||||
- Persist render context in the existing generated-text-template workflow.
|
||||
|
||||
4. Module presentation fields
|
||||
- Add only the daypart presentation fields needed by the template.
|
||||
- Reuse the existing precipitation window hour-label fields.
|
||||
- Keep deterministic weather derivation in Go and wording/layout in the
|
||||
template.
|
||||
|
||||
5. Report definition conversion
|
||||
- Change Tomorrow report definition to:
|
||||
- `PromptID: "weather.tomorrow_generated_text"`
|
||||
- `GenerationMode: generated_text_template`
|
||||
- `TemplateID: "tomorrow"`
|
||||
- `GeneratedTextSchemaID: "tomorrow"`
|
||||
- `ArtifactGroup: "tomorrow"`
|
||||
- `BatchOutputName: "tomorrow.md"`
|
||||
- compatible prior IDs containing only `tomorrow`
|
||||
- Review module composition and keep only modules used by the prompt,
|
||||
template, or future inspection value.
|
||||
|
||||
6. Documentation and examples
|
||||
- After implementation, update non-roadmap docs for implemented behavior:
|
||||
`docs/cli.md`, `docs/operations.md`, `docs/internal/report-registry.md`,
|
||||
`docs/internal/generatedtext.md`, `docs/internal/reporttemplate.md`, and
|
||||
`docs/templates.md`.
|
||||
- Update examples that refer to `reports.tomorrow` or report module
|
||||
overrides if the config key changes.
|
||||
|
||||
## Test Plan
|
||||
|
||||
- Report tests:
|
||||
- registry contains `tomorrow`, not `daily_tomorrow`;
|
||||
- `generate tomorrow` resolves report ID `tomorrow`;
|
||||
- valid period remains next local civil day;
|
||||
- evening batch still includes Tomorrow;
|
||||
- RunID and artifact paths use `tomorrow`.
|
||||
- GeneratedText tests:
|
||||
- `summary` and non-empty `forecast_discussion` are required;
|
||||
- `forecast_discussion` trims paragraph strings and rejects/omits blanks;
|
||||
- optional `precipitation_timing` and `confidence` normalize correctly;
|
||||
- unknown fields are rejected.
|
||||
- Template tests:
|
||||
- title renders as `<weekday>'s Weather`;
|
||||
- forecast date and generated labels render;
|
||||
- daypart bullets render in configured daypart order;
|
||||
- precipitation section is omitted when no precipitation windows exist;
|
||||
- precipitation section includes deterministic windows and optional LLM text
|
||||
when windows exist;
|
||||
- forecast discussion renders multiple paragraphs.
|
||||
- App/CLI workflow tests:
|
||||
- `weatherreporter generate tomorrow` uses structured Scriptorium output and
|
||||
the template renderer;
|
||||
- raw generated text, validated generated text, render context, report, and
|
||||
metadata artifacts are persisted;
|
||||
- optional `--out` behavior remains unchanged;
|
||||
- distributor notification uses report ID/artifact group `tomorrow`.
|
||||
|
||||
Validation commands:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## Open Questions
|
||||
|
||||
None block implementation. Recommended defaults are:
|
||||
|
||||
- make `forecast_discussion` an array of strings for Tomorrow;
|
||||
- keep Hourly GeneratedText unchanged for now;
|
||||
- do not add Daily Today or generic Daily report splits in this change;
|
||||
- do not preserve `daily_tomorrow` compatibility aliases.
|
||||
@@ -1,46 +1,56 @@
|
||||
You are writing structured prose slots for a short-term hourly weather report.
|
||||
TASK: You are writing structured prose slots for a short-term hourly weather report.
|
||||
|
||||
The calling application will render the final Markdown report. Your job is not
|
||||
to write the full report. Return only a JSON object matching the configured
|
||||
schema.
|
||||
The calling application will render the final Markdown report. Your job is not to write the full report. Return only a JSON object matching the configured schema.
|
||||
|
||||
Use only the supplied `data_package`. Do not invent weather details, times,
|
||||
hazards, probabilities, or impacts that are not supported by the data.
|
||||
Use only the supplied `data_package`. Do not invent weather details, times, hazards, probabilities, or impacts that are not supported by the data.
|
||||
|
||||
The report focuses on the valid period in `report.valid_period`, typically the
|
||||
next several hours for the configured location.
|
||||
|
||||
Write for a general local audience. Be clear, practical, and concise.
|
||||
The report focuses on the valid period in `report.valid_period`, typically the next several hours for the configured location.
|
||||
|
||||
Return these fields:
|
||||
|
||||
- `summary`: required. 1-2 sentences summarizing the main weather story for the
|
||||
valid period.
|
||||
- `forecast_discussion`: required. 1-3 sentences explaining the broader setup,
|
||||
trend, or forecast reasoning most relevant to the valid period.
|
||||
- `precipitation_timing`: optional. Include only when the deterministic
|
||||
`precip_timing` module contains precipitation windows. Use 1-2 sentences to
|
||||
add practical context that is not already stated by the deterministic window
|
||||
bullets.
|
||||
- `confidence`: optional. Include only if uncertainty, timing spread, or
|
||||
conflicting signals materially affect how the reader should interpret the
|
||||
forecast.
|
||||
|
||||
Guidance:
|
||||
|
||||
- Do not repeat deterministic current conditions, alert bullets, hourly forecast
|
||||
bullets, or precipitation-window bullets verbatim.
|
||||
- Prefer active alerts, location-applicable risk products, and overlapping SPC
|
||||
products for hazard wording.
|
||||
- Use the hourly forecast and precipitation timing modules for timing details.
|
||||
- Use current conditions only for immediate context; do not let them override
|
||||
the forecast.
|
||||
- Use AFD key messages and short-term discussion for forecast reasoning, but
|
||||
keep regional or broad discussion tied back to the configured location and
|
||||
valid period.
|
||||
- Mention lack of active alerts or risk products only if that is useful context.
|
||||
- Do not include Markdown headings, bullets, or code fences.
|
||||
- Do not include fields outside the schema.
|
||||
- If a field cannot be supported by the data, keep it brief and conservative.
|
||||
- `summary`: required. 1-2 sentences summarizing the main weather story for the valid period.
|
||||
- `forecast_discussion`: required. 2-3 sentences explaining the broader setup, trend, or forecast reasoning most relevant to the valid period.
|
||||
- `precipitation_timing`: optional. Include only when the deterministic `precip_timing` module contains precipitation windows.
|
||||
- `confidence`: optional. Include only if uncertainty, timing spread, or conflicting signals materially affect how the reader should interpret the forecast.
|
||||
|
||||
Return JSON only.
|
||||
|
||||
# summary
|
||||
|
||||
The summary should typically consist of two sentences.
|
||||
|
||||
If an active warning is relevant during the report period, lead with the hazard. Otherwise, the first sentence should state the most likely local weather outcome for the valid period, including the overall character of the weather and expected temperature/temperature range.
|
||||
|
||||
If the forecast indicates a significant shift in conditions over time (e.g., from sunny to overcast), then identify the hour when the shift is most likely to occur. If the conditions are generally similar or stable across the forecast period, then pick a single descriptor (e.g., mostly clear) that best captures the character of the weather.
|
||||
|
||||
The second sentence should state the most important active hazard, caveat, uncertainty, or alternate outcome, if one exists. If there is no meaningful caveat, the second sentence may be omitted, or may briefly say that no major complications are apparent.
|
||||
|
||||
In the lead, distinguish the main weather outcome from the caveat. If showers and thunderstorms have different timing, state that difference rather than combining them as a single risk throughout the valid period. If the main caveat is a regional severe-weather or precipitation risk displaced from the report location, state that limitation clearly.
|
||||
|
||||
Example style:
|
||||
|
||||
- “The rest of the afternoon is expected to be warm and dry, with mostly clear skies. There is a slight chance of isolated showers and thunderstorms developing from late afternoon into early evening.”
|
||||
|
||||
# forecast_discussion
|
||||
|
||||
Use narrative products to explain the “why” behind the local forecast when useful.
|
||||
|
||||
Useful context may include:
|
||||
|
||||
- synoptic pattern
|
||||
- fronts or boundaries
|
||||
- shortwaves, troughs, or ridges
|
||||
- instability, moisture, shear, forcing, or capping
|
||||
- regional placement of precipitation or severe-weather chances
|
||||
- hazard types and timing windows
|
||||
- confidence or uncertainty
|
||||
- conditional outcomes
|
||||
- relevant notes about the following day or days
|
||||
|
||||
# precipitation_timing
|
||||
|
||||
Use 1-2 sentences to add practical context, including:
|
||||
|
||||
- Whether the precipitation is associated with a moving frontal boundary, convective initiation, or wide stratiform rain (if this can be determined from the data package);
|
||||
- The expected type, intensity, and duration of the precipitation; and
|
||||
- Any caveats or uncertainty with respect to the onset, duration, or occurrance of the precipitation.
|
||||
|
||||
Reference in New Issue
Block a user