diff --git a/docs/roadmap/today.md b/docs/roadmap/today.md deleted file mode 100644 index 52e1203..0000000 --- a/docs/roadmap/today.md +++ /dev/null @@ -1,424 +0,0 @@ -# Today Report Roadmap - -## Purpose - -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, distributor identity, and deterministic planning module should use -`today`. - -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 - -Today should render from deterministic current-day facts plus structured prose -from Scriptorium: - -```markdown -# Today's Weather - -**Forecast date:** Friday, May 29, 2026 -**Updated:** Friday, May 29, 2026 at 8:30 AM - - - -## Daypart Forecast - -- **Morning:** -- **Midday:** -- **Afternoon:** -- **Evening:** - -## Precipitation Timing - -- **10:00 AM** to **1:00 PM**: Precipitation is expected during this period. - The peak precipitation chance is 70% at 11:00 AM. -- - -## Forecast Discussion - - -``` - -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: - -- report ID: `today` -- public generate command: `today` -- prompt ID: `weather.today_generated_text` -- generation mode: `generated_text_template` -- template ID: `today` -- generated-text schema ID: `today` -- artifact group: `today` -- batch output name: `today.md` -- 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)` - -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 - -Today should use the same structured prose shape as Tomorrow: - -```json -{ - "summary": "string", - "forecast_discussion": ["string"], - "precipitation_timing": "string", - "confidence": "string" -} -``` - -Required: - -- `summary` -- `forecast_discussion` - -Optional: - -- `precipitation_timing` -- `confidence` - -Validation should match Tomorrow semantics: - -- reject malformed JSON and unknown fields -- reject trailing JSON values -- trim `summary`, `precipitation_timing`, and `confidence` -- trim each `forecast_discussion` paragraph -- drop blank discussion paragraphs -- 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 -Tomorrow types directly. The shape should mirror Tomorrow so template behavior -stays explicit and testable: - -```go -type TodayRenderContext struct { - Report TodayReportContext - GeneratedText Today - Modules TodayTemplateModules - Collected facts.CollectedFacts - Derived facts.DerivedFacts -} -``` - -`TodayReportContext` should include: - -- `Title`, exactly `Today's Weather` -- `ForecastDate` -- `ForecastDateLabel`, for example `Friday, May 29, 2026` -- `ForecastDayName`, for example `Friday` -- `GeneratedAt` -- `GeneratedAtLabel` -- `ValidPeriod` -- `Timezone` - -`TodayTemplateModules` should expose the categories the Today template needs: - -- `Metadata` -- `CurrentConditions` -- `HourlyForecast` -- `DerivedDailySummary` -- `DerivedDaypartSummaries` -- ordered daypart rows -- `PrecipTiming` -- `AlertDigest` -- `SPCConvectiveOutlooks` -- `AreaForecastDiscussion` -- `SPCConvectiveDiscussion` -- `WeatherStory` -- `TodayPlanning` - -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, with a Today-specific planning module: - -- `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` - -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`. - - 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-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 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. - -4. Add Today template and render context. - - Add `today.md.tmpl`. - - Add `TodayRenderContext`, `TodayReportContext`, and - `TodayTemplateModules`. - - Add `BuildTodayRenderContext`. - - Use the internal snapshot lookup helper for module extraction. - - Add render-context and template tests for populated and omitted optional - modules. - -5. Register Today in generated-text and embedded asset catalogs. - - Add a generated-text catalog entry. - - 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. - -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`. - -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/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 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, 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` -- config report module overrides for `reports.today` - -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 - -No open decisions remain that block implementation. - -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. diff --git a/internal/generatedtext/render_context_test.go b/internal/generatedtext/render_context_test.go index ebdd340..5592136 100644 --- a/internal/generatedtext/render_context_test.go +++ b/internal/generatedtext/render_context_test.go @@ -203,14 +203,12 @@ func TestBuildTodayRenderContext(t *testing.T) { "# Today's Weather", "**Forecast date:** Monday, June 15, 2026", "Today starts quiet, then showers become more likely later in the day.", - "Currently, it is 58°F and clear.", + "Currently, it is 58°F and clear. It feels like 57°F, with a relative humidity of 61% and winds from the northwest at 9 mph.", "- **Morning:** Partly cloudy, with temperatures in the low 60s.", "- **Afternoon:** Showers, with temperatures in the mid 70s. Chance of precipitation is 70%.", "## Precipitation Timing", "- **3:00 PM** to **6:00 PM**: Precipitation is expected during this period. The peak precipitation chance is 70% at 3:00 PM.", "The most likely rain window is from midafternoon into early evening.", - "## Planning Notes", - "- Take sunglasses early.", "Morning conditions should stay mostly dry.", "Rain chances increase during the afternoon as deeper moisture arrives.", } { @@ -225,9 +223,11 @@ func TestBuildTodayRenderContext(t *testing.T) { "- **Morning:**", "- **Afternoon:**", "## Precipitation Timing", - "## Planning Notes", "## Forecast Discussion", }) + if strings.Contains(text, "## Planning Notes") || strings.Contains(text, "- Take sunglasses early.") || strings.Contains(text, "Forecast details are limited") { + t.Fatalf("rendered template included removed Today template content:\n%s", text) + } } func TestBuildTodayRenderContextAllowsOmittedOptionalModules(t *testing.T) { @@ -250,7 +250,7 @@ func TestBuildTodayRenderContextAllowsOmittedOptionalModules(t *testing.T) { t.Fatalf("Render() error = %v", err) } text := string(rendered) - for _, unwanted := range []string{"## Current Conditions", "## Precipitation Timing", "## Planning Notes"} { + for _, unwanted := range []string{"## Current Conditions", "## Precipitation Timing", "## Planning Notes", "Forecast details are limited"} { if strings.Contains(text, unwanted) { t.Fatalf("rendered template included %q without module data:\n%s", unwanted, text) } @@ -493,8 +493,12 @@ func testTodaySnapshot(t *testing.T) module.Snapshot { ID: module.CurrentConditions, StanzaName: string(module.CurrentConditions), Value: briefing.CurrentConditionsModule{ - ConditionTextLower: "clear", - TemperatureF: intPtr(58), + ConditionTextLower: "clear", + TemperatureF: intPtr(58), + ApparentTemperatureF: intPtr(57), + RelativeHumidityPercent: intPtr(61), + WindSpeedMph: intPtr(9), + WindDirectionText: "northwest", }, }, { diff --git a/internal/reporttemplate/reporttemplate_test.go b/internal/reporttemplate/reporttemplate_test.go index 64d10b3..c12a674 100644 --- a/internal/reporttemplate/reporttemplate_test.go +++ b/internal/reporttemplate/reporttemplate_test.go @@ -35,11 +35,14 @@ func TestTodayTemplateLookup(t *testing.T) { if err != nil { t.Fatalf("Template() error = %v", err) } - for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", "## Current Conditions", "## Daypart Forecast", "## Planning Notes", "## Forecast Discussion"} { + for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", "## Current Conditions", "## Daypart Forecast", "## Forecast Discussion"} { if !strings.Contains(source, want) { t.Fatalf("template missing %q:\n%s", want, source) } } + if strings.Contains(source, "## Planning Notes") { + t.Fatalf("template includes Planning Notes section:\n%s", source) + } } func TestSchemaLookup(t *testing.T) { @@ -365,8 +368,12 @@ func TestRenderToday(t *testing.T) { }, Modules: testTodayModules{ CurrentConditions: &testCurrentConditions{ - ConditionTextLower: "clear", - TemperatureF: intPtr(58), + ConditionTextLower: "clear", + TemperatureF: intPtr(58), + ApparentTemperatureF: intPtr(57), + RelativeHumidityPercent: intPtr(61), + WindDirectionText: "northwest", + WindSpeedMph: intPtr(9), }, Dayparts: []testTomorrowDaypart{ { @@ -393,6 +400,12 @@ func TestRenderToday(t *testing.T) { MentionPrecipitation: true, }, }, + { + Key: "evening", + Summary: testDaypartSummary{ + DisplayName: "Evening", + }, + }, }, PrecipTiming: &testPrecipTiming{ PrecipitationWindows: []testPrecipWindow{ @@ -414,14 +427,11 @@ func TestRenderToday(t *testing.T) { "**Forecast date:** Monday, June 15, 2026", "**Updated:** Monday, June 15, 2026 at 7:14 AM", "Today starts dry before showers return later in the day.", - "Currently, it is 58°F and clear.", + "Currently, it is 58°F and clear. It feels like 57°F, with a relative humidity of 61% and winds from the northwest at 9 mph.", "- **Morning:** Sunny, with temperatures rising from the upper 50s to the upper 60s.", "- **Afternoon:** Showers, with temperatures in the upper 70s. Chance of precipitation is 70%.", "- **3:00 PM** to **6:00 PM**: Precipitation is expected during this period. The peak precipitation chance is 70% at 3:00 PM.", "A few showers may linger into early evening.", - "## Planning Notes", - "- Morning weather looks routine.", - "- Watch late-day shower timing.", "Clouds increase after sunrise.", "Rain chances peak during the afternoon.", } { @@ -436,9 +446,13 @@ func TestRenderToday(t *testing.T) { "- **Morning:**", "- **Afternoon:**", "## Precipitation Timing", - "## Planning Notes", "## Forecast Discussion", }) + for _, unwanted := range []string{"## Planning Notes", "Morning weather looks routine.", "Watch late-day shower timing.", "- **Evening:**", "Forecast details are limited"} { + if strings.Contains(text, unwanted) { + t.Fatalf("rendered template included %q:\n%s", unwanted, text) + } + } } func TestRenderTomorrowOmitsPrecipitationTimingWithoutWindows(t *testing.T) { diff --git a/internal/reporttemplate/templates/today.md.tmpl b/internal/reporttemplate/templates/today.md.tmpl index 68f57f4..05be3a0 100644 --- a/internal/reporttemplate/templates/today.md.tmpl +++ b/internal/reporttemplate/templates/today.md.tmpl @@ -5,12 +5,14 @@ {{ .GeneratedText.Summary }} -{{ with .Modules.CurrentConditions }}{{ $current := . }}## Current Conditions -Currently, {{ with .TemperatureF }}it is {{ . }}°F{{ with $current.ConditionTextLower }} and {{ . }}{{ end }}{{ else }}{{ with .ConditionTextLower }}conditions are {{ . }}{{ else }}latest current conditions are available{{ end }}{{ end }}. +{{ with .Modules.CurrentConditions }} +## Current Conditions +{{ with .TemperatureF }}Currently, it is {{ . }}°F{{ with $.Modules.CurrentConditions.ConditionTextLower }} and {{ . }}{{ end }}.{{ else }}{{ with .ConditionText }}Currently, it is {{ . }}.{{ else }}Current conditions are unavailable.{{ end }}{{ end }}{{ with .ApparentTemperatureF }} It feels like {{ . }}°F{{ with $.Modules.CurrentConditions.RelativeHumidityPercent }}, with a relative humidity of {{ . }}%{{ end }}{{ with $.Modules.CurrentConditions.WindDirectionText }} and winds from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}{{ end }}.{{ else }}{{ with .RelativeHumidityPercent }} Relative humidity is {{ . }}%.{{ end }}{{ with .WindDirectionText }} Winds are from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}.{{ end }}{{ end }} -{{ end }}## Daypart Forecast -{{ with .Modules.Dayparts }}{{ range . }}{{ $daypart := . }}- **{{ if .Summary.DisplayName }}{{ .Summary.DisplayName }}{{ else }}{{ .Key }}{{ end }}:** {{ with .Summary.DominantConditionDisplay }}{{ . }}{{ else }}{{ with .Summary.DominantCondition }}{{ . }}{{ else }}Forecast details are limited{{ end }}{{ end }}{{ if eq .Summary.TemperatureTrend "rising" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures rising from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "falling" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures falling from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "peaking" }}{{ with .Summary.TemperaturePeakPhraseF }}, with temperatures peaking in the {{ . }}{{ end }}{{ else }}{{ with .Summary.TemperatureSteadyPhraseF }}, with temperatures in the {{ . }}{{ else }}{{ with .Summary.TemperaturePhraseF }}, with temperatures in the {{ . }}{{ end }}{{ end }}{{ end }}.{{ if .Summary.MentionPrecipitation }}{{ with .Summary.MaxPopPercent }} Chance of precipitation is {{ . }}%.{{ end }}{{ end }} -{{ end }}{{ else }}- No daypart forecast details are available. +{{ end }} +## Daypart Forecast +{{ with .Modules.Dayparts }}{{ range . }}{{ $daypart := . }}{{ if or .Summary.DominantConditionDisplay .Summary.DominantCondition }}- **{{ if .Summary.DisplayName }}{{ .Summary.DisplayName }}{{ else }}{{ .Key }}{{ end }}:** {{ with .Summary.DominantConditionDisplay }}{{ . }}{{ else }}{{ with .Summary.DominantCondition }}{{ . }}{{ end }}{{ end }}{{ if eq .Summary.TemperatureTrend "rising" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures rising from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "falling" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures falling from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "peaking" }}{{ with .Summary.TemperaturePeakPhraseF }}, with temperatures peaking in the {{ . }}{{ end }}{{ else }}{{ with .Summary.TemperatureSteadyPhraseF }}, with temperatures in the {{ . }}{{ else }}{{ with .Summary.TemperaturePhraseF }}, with temperatures in the {{ . }}{{ end }}{{ end }}{{ end }}.{{ if .Summary.MentionPrecipitation }}{{ with .Summary.MaxPopPercent }} Chance of precipitation is {{ . }}%.{{ end }}{{ end }} +{{ end }}{{ end }}{{ else }}- No daypart forecast details are available. {{ end }} {{ with .Modules.PrecipTiming }}{{ with .PrecipitationWindows }} @@ -20,13 +22,7 @@ Currently, {{ with .TemperatureF }}it is {{ . }}°F{{ with $current.ConditionTex {{ end }}{{ with $.GeneratedText.PrecipitationTiming }} {{ . }} {{ end }} -{{ end }}{{ end }}{{ with .Modules.TodayPlanning }}{{ if or .MorningReadiness .CommuteSchoolWorkdayConcerns .OutdoorPlanning .LateDayChangeWatch }} -## Planning Notes -{{ with .MorningReadiness }}{{ range . }}- {{ . }} -{{ end }}{{ end }}{{ with .CommuteSchoolWorkdayConcerns }}{{ range . }}- {{ . }} -{{ end }}{{ end }}{{ with .OutdoorPlanning }}{{ range . }}- {{ . }} -{{ end }}{{ end }}{{ with .LateDayChangeWatch }}{{ range . }}- {{ . }} -{{ end }}{{ end }}{{ end }}{{ end }} +{{ end }}{{ end }} ## Forecast Discussion {{ range .GeneratedText.ForecastDiscussion }} {{ . }}