Files
weatherreporter/docs/roadmap/implementation.md

23 KiB

Daily Report Implementation Roadmap

Purpose

This roadmap defines the staged implementation plan for docs/roadmap/daily.md. It is written for an LLM coding agent that will implement the new generated-text-template daily report in order.

The target feature is a clean replacement of the existing active Daily path: weatherreporter generate daily should run a new independent daily report that requires --date YYYY-MM-DD, uses generated structured text plus a Markdown template, and initially renders the same report shape as tomorrow.

This file is planning-only. Non-roadmap documentation should be updated only in the implementation stage after the behavior exists.

Source Roadmap

Use docs/roadmap/daily.md as the feature roadmap and source of user intent. That document defines the target state, report identity, command behavior, module composition, generated-text contract, and replacement policy for the legacy daily_today report.

Locked Decisions

  • daily is a separate report ID, not an alias for today, tomorrow, or legacy daily_today.
  • weatherreporter generate daily remains the public command, but it must run the new generated-text-template Daily report.
  • weatherreporter generate daily requires --date YYYY-MM-DD.
  • The supplied date is interpreted as a local civil date in the effective report timezone after config and --tz overrides.
  • The valid period is [00:00, next 00:00) for the selected local civil day.
  • Daily is manually targeted and is not added to morning or evening batches.
  • Daily uses prompt ID weather.daily_generated_text.
  • Daily uses template ID daily and generated-text schema ID daily.
  • Daily uses artifact group daily and batch output name daily.md.
  • Daily has its own generated-text type, schema, prompt asset, Markdown template, render-context type, and planning module.
  • Daily may share private helpers with Tomorrow when mechanics are identical, but it must not expose Tomorrow-specific public types or stanzas.
  • Remove active daily_today report definition and reports.daily_today config-key support.
  • Historical workspace artifacts with daily_today metadata are not migrated.

Implementation Principles

  • Preserve public CLI syntax except for the intentional breaking change that generate daily now requires --date.
  • Keep report identity, prompt IDs, generation mode, module order, artifact groups, batch membership, and compatibility policy centralized in internal/report.
  • Keep CLI parsing in internal/cli; enforce the missing-date policy in both CLI parsing and the report resolver so non-CLI callers cannot accidentally generate an undated Daily report.
  • Keep generated-text schema validation in internal/generatedtext.
  • Keep embedded schemas, prompts, and templates as separate files under internal/reporttemplate.
  • Keep deterministic module output in internal/briefing and module IDs/options in internal/module.
  • Do not add compatibility aliases for daily_today.
  • Update implemented documentation only after the code behavior exists.

Stage 1: Daily Planning Module

Goal

Add the Daily-specific planning module before activating the new report. This keeps module and report work separable and makes the eventual Daily default composition explicit.

Files To Inspect

  • internal/module/module.go
  • internal/briefing/tomorrow_planning_module.go
  • internal/briefing/today_planning_module.go
  • internal/briefing/modules.go
  • internal/briefing/derived_modules_test.go
  • docs/roadmap/daily.md

Implementation

  • Add module.DailyPlanning with value daily_planning.
  • Add module.DailyPlanningOptions struct{}.
  • Add internal/briefing/daily_planning_module.go.
  • Add DailyPlanningModule with the initial fields:
    • morning_readiness
    • commute_school_workday_concerns
    • overnight_change_watch
  • Build the Daily planning module from the same underlying summary inputs as Tomorrow planning, but do not reuse the public TomorrowPlanningModule type.
  • Share private helper functions with Tomorrow only when the helper expresses report-neutral mechanics.
  • Register daily_planning in the default module registry with:
    • stanza name daily_planning
    • default options module.DailyPlanningOptions{}
    • supported reports []report.ID{report.Daily} after report.Daily exists in Stage 3; if Stage 1 is implemented before report.Daily, add the module ID/options now and wire report support in Stage 3.

Acceptance Criteria

  • daily_planning is a distinct module ID and stanza.
  • No Daily path emits tomorrow_planning.
  • No public Daily type aliases or embeds TomorrowPlanningModule.
  • Unsupported reports receive an actionable unsupported-module error.

Tests

  • Add or update module tests for:
    • output shape;
    • missing-summary fallback behavior;
    • supported Daily report;
    • unsupported Today, Tomorrow, Hourly, Three-Day, Weekend, and Storm reports.
  • Suggested focused command after this stage:
go test ./internal/module ./internal/briefing

Prompt Size

Small enough for one implementation prompt.

Stage 2: Daily GeneratedText Contract And Assets

Goal

Add Daily generated-text validation and embedded assets while keeping the active report registry unchanged until Stage 3.

Files To Inspect

  • internal/generatedtext/tomorrow.go
  • internal/generatedtext/today.go
  • internal/generatedtext/catalog.go
  • internal/generatedtext/*_test.go
  • internal/reporttemplate/reporttemplate.go
  • internal/reporttemplate/templates/tomorrow.md.tmpl
  • internal/reporttemplate/prompts/tomorrow.generated_text.md
  • internal/reporttemplate/schemas/tomorrow.generated_text.schema.json
  • internal/reporttemplate/reporttemplate_test.go

Implementation

  • Add internal/generatedtext/daily.go.
  • Add type Daily struct with the same public JSON shape as Tomorrow:
    • summary required string
    • forecast_discussion required []string
    • precipitation_timing optional string
    • confidence optional string
  • Add ValidateDaily.
  • Match Tomorrow validation semantics:
    • reject malformed JSON;
    • reject unknown fields;
    • reject trailing values;
    • trim string fields;
    • trim each forecast-discussion paragraph;
    • drop blank forecast-discussion paragraphs;
    • require nonblank summary;
    • require at least one nonblank forecast-discussion paragraph;
    • return canonical normalized JSON.
  • Add internal/reporttemplate/schemas/daily.generated_text.schema.json.
  • Add internal/reporttemplate/prompts/daily.generated_text.md.
  • Add internal/reporttemplate/templates/daily.md.tmpl, initially matching the Tomorrow rendered Markdown structure while referencing Daily render-context fields.
  • Register Daily in the generated-text catalog with schema ID daily.
  • Register the Daily schema and template asset lookup in internal/reporttemplate.

Acceptance Criteria

  • Daily generated text validates independently from Tomorrow.
  • The Daily schema and template can be looked up by ID daily.
  • The Daily prompt asset exists as maintained source material for out-of-band Scriptorium registration.
  • No report registry behavior changes yet unless Stage 2 and Stage 3 are intentionally implemented together.

Tests

  • Add generated-text tests for:
    • valid Daily JSON;
    • missing summary;
    • missing or blank forecast_discussion;
    • unknown fields;
    • trailing JSON;
    • trimming and canonical output.
  • Add catalog tests proving schema ID daily maps to ValidateDaily.
  • Add reporttemplate tests for Daily schema lookup, template lookup, and basic render behavior.
  • Suggested focused command:
go test ./internal/generatedtext ./internal/reporttemplate

Prompt Size

Small enough for one implementation prompt.

Stage 3: Daily Render Context

Goal

Add a dedicated Daily template context that mirrors Tomorrow mechanics without exposing Tomorrow public types.

Files To Inspect

  • internal/generatedtext/render_context.go
  • internal/generatedtext/render_context_test.go
  • internal/briefing/*_module.go
  • internal/module/module.go
  • internal/facts
  • internal/reporttemplate/templates/tomorrow.md.tmpl

Implementation

  • Add:
type DailyRenderContext struct {
    Report        DailyReportContext
    GeneratedText Daily
    Modules       DailyTemplateModules
    Collected     facts.CollectedFacts
    Derived       facts.DerivedFacts
}
  • Add DailyReportContext with:
    • Title
    • ForecastDate
    • ForecastDateLabel
    • ForecastDayName
    • GeneratedAt
    • GeneratedAtLabel
    • ValidPeriod
    • Timezone
  • Add DailyTemplateModules with the Daily template surfaces defined in docs/roadmap/daily.md, including DailyPlanning.
  • Add a Daily daypart context if the Tomorrow daypart context is not already generic enough to use privately.
  • Add BuildDailyRenderContext.
  • Generate Title as <weekday>'s Weather, for example Monday's Weather.
  • Build ForecastDateLabel from the valid-period start in the effective timezone.
  • Reuse private module snapshot lookup and ordered-daypart helpers where useful, but keep Daily's exported types distinct.

Acceptance Criteria

  • Daily render context is independent and template-friendly.
  • Optional modules are nil when omitted by missing-data policy.
  • Ordered dayparts use the same ordering and omission behavior as Tomorrow.
  • Daily planning is available as .Modules.DailyPlanning.
  • The render context exposes Collected and Derived for advanced template use, consistent with current generated-text-template reports.

Tests

  • Add render-context tests for:
    • title and forecast date label;
    • generated-at label;
    • valid period and timezone;
    • Daily planning extraction;
    • omitted optional modules;
    • daypart ordering;
    • collected and derived facts propagation.
  • Suggested focused command:
go test ./internal/generatedtext ./internal/reporttemplate

Prompt Size

Small enough for one implementation prompt.

Stage 4: Report Registry Cutover

Goal

Replace the active legacy daily_today report definition with the new generated text-template daily report.

Files To Inspect

  • internal/report/definition.go
  • internal/report/daily_report.go
  • internal/report/today_report.go
  • internal/report/tomorrow_report.go
  • internal/report/names.go
  • internal/report/period.go
  • internal/report/period_test.go
  • internal/briefing/modules.go
  • internal/app/app.go
  • internal/changes

Implementation

  • Add or change the active Daily report ID to:
Daily ID = "daily"
  • Remove active use of DailyToday.
    • Prefer removing the exported DailyToday constant entirely if no active code needs it.
    • If temporary compile sequencing requires keeping it during this stage, remove it before the stage is complete.
  • Replace dailyTodayDefinition with dailyDefinition.
  • Daily definition values:
    • ID Daily
    • name Daily Report
    • prompt ID weather.daily_generated_text
    • generation mode GenerationModeGeneratedTextTemplate
    • template ID daily
    • generated-text schema ID daily
    • artifact group daily
    • batch output name daily.md
    • generated true
    • compatible prior IDs []ID{Daily}
    • comparison strategy same valid local date
    • no morning batch membership
    • no evening batch membership
  • Add dailyModules() with the module order from docs/roadmap/daily.md:
    • 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
    • daily_planning
    • hourly_forecast
  • Add resolveDaily requiring ResolveRequest.Date.
    • Return an actionable error when Date is zero.
    • Resolve the date as a local civil day in ResolveRequest.Location.
  • Update report name/config resolution:
    • IDForCommandName("daily") returns Daily.
    • IDForConfigKey("daily") returns Daily.
    • IDForConfigKey("daily_today") returns an unknown config-key error.
  • Update module registry supported-report lists:
    • replace report.DailyToday with report.Daily for shared Daily-compatible modules;
    • add report.Daily to Daily planning support.
  • Update Recent Changes dispatch where it currently groups daily-style reports, replacing DailyToday with Daily.
  • Ensure BatchReports continues to include Today in the morning batch and Tomorrow in the evening batch, with no Daily membership.

Acceptance Criteria

  • report.DefaultRegistry() includes daily and not daily_today.
  • weatherreporter generate daily resolves to report ID daily.
  • reports.daily config overrides apply to Daily.
  • reports.daily_today is rejected.
  • Daily uses generated-text-template mode.
  • Daily metadata, RunID, artifact paths, distributor variables, and report output all use report ID/artifact group daily.
  • Scheduled batches do not include Daily.

Tests

  • Update report tests for:
    • registry membership;
    • command-name resolution;
    • config-key resolution;
    • generated-text-template metadata;
    • explicit-date valid period;
    • missing-date resolver error;
    • batch membership.
  • Update module registry tests to prove every default Daily module is buildable.
  • Update Recent Changes tests to use Daily snapshots instead of legacy daily_today snapshots where applicable.
  • Suggested focused command:
go test ./internal/report ./internal/briefing ./internal/changes

Prompt Size

This is the first larger cutover stage. It is still suitable for one implementation prompt if the agent works package by package and keeps tests focused. If compile errors spread widely, split into:

  1. report ID/name/config resolution;
  2. module registry and Recent Changes updates;
  3. report tests and stale-symbol cleanup.

Stage 5: CLI And App Workflow Integration

Goal

Make the public command weatherreporter generate daily --date YYYY-MM-DD execute the full generated-text-template workflow and reject missing dates.

Files To Inspect

  • internal/cli/root.go
  • internal/cli/root_test.go
  • internal/app/app.go
  • internal/app/app_test.go
  • internal/state
  • internal/adapters/scriptorium
  • internal/adapters/distributor
  • examples/config.yml

Implementation

  • Update CLI date policy:
    • generate daily requires --date YYYY-MM-DD;
    • missing --date returns a concise actionable error;
    • malformed --date remains an error;
    • generate today keeps its current behavior;
    • generate tomorrow remains date-free.
  • Ensure --config, --units, --tz, --out, and distributor notification behavior continue to work as they do for other generated-text-template reports.
  • Update app generated-text dispatch so Daily uses:
    • prompt ID weather.daily_generated_text;
    • schema ID daily;
    • template ID daily;
    • BuildDailyRenderContext.
  • Ensure persisted artifacts include:
    • raw generated text JSON;
    • generated-text run result;
    • normalized generated text;
    • render context;
    • rendered Markdown;
    • metadata;
    • optional output copy.
  • Ensure distributor upload, when enabled, uses the managed Daily Markdown report path and Daily template variables.

Acceptance Criteria

  • weatherreporter generate daily --date YYYY-MM-DD runs through the generated-text-template path.
  • weatherreporter generate daily without --date fails before generation.
  • weatherreporter generate daily --date bad-date fails before generation.
  • Existing Today, Tomorrow, Hourly, Three-Day, Weekend, and Storm commands keep their current syntax.
  • Daily app workflow saves the same classes of artifacts as Today/Tomorrow.
  • Daily optional --out copy behavior remains separate from the managed report path.

Tests

  • Update CLI parser tests for:
    • required Daily date;
    • malformed Daily date;
    • valid Daily date;
    • Today and Tomorrow date behavior unchanged.
  • Add or update app workflow tests for:
    • Daily generated-text Scriptorium request;
    • Daily schema validation;
    • Daily render context persistence;
    • Daily rendered report path;
    • Daily optional output copy;
    • Daily distributor request values when notification is enabled.
  • Suggested focused command:
go test ./internal/cli ./internal/app ./internal/state

Prompt Size

Medium. Suitable for one implementation prompt after Stages 1-4 compile.

Stage 6: Legacy DailyToday Sweep

Goal

Remove stale active-code references to the legacy daily_today report after the new Daily path is working.

Files To Inspect

  • internal/report
  • internal/briefing
  • internal/config
  • internal/app
  • internal/changes
  • internal/promptinput
  • internal/state
  • internal/generatedtext
  • internal/reporttemplate
  • package tests

Implementation

  • Remove remaining production-code references to:
    • DailyToday;
    • daily_today;
    • weather.daily_report on the active Daily path.
  • Update test fixtures and helper names that represent the active Daily report.
  • Keep references only when intentionally describing historical artifacts in roadmap text.
  • Do not add migration logic for old workspace files.
  • Do not keep daily_today as a hidden alias.

Acceptance Criteria

  • rg -n "DailyToday|daily_today|weather.daily_report" internal examples docs has no production-code or implemented-doc matches, except future/historical roadmap references if intentionally retained.
  • All report and module defaults refer to active report IDs.
  • Tests no longer assume daily resolves to daily_today.

Tests

  • Run:
rg -n "DailyToday|daily_today|weather.daily_report" internal examples docs
go test ./internal/...

Prompt Size

Small to medium. This can be combined with Stage 5 only if the agent has enough context and compile errors are already localized.

Stage 7: Documentation And Examples

Goal

Update implemented documentation and maintained examples after the Daily feature exists. Keep planned or deferred behavior only under docs/roadmap/.

Files To Inspect

  • README.md
  • docs/cli.md
  • docs/config.md
  • docs/operations.md
  • docs/templates.md
  • docs/troubleshooting.md
  • docs/internal/report-registry.md
  • docs/internal/generatedtext.md
  • docs/internal/reporttemplate.md
  • docs/internal/module.md
  • docs/internal/app-orchestration.md
  • examples/config.yml
  • tests that load examples

Implementation

  • Update docs/cli.md:
    • document weatherreporter generate daily --date YYYY-MM-DD;
    • describe missing date as an error;
    • keep Today and Tomorrow documented as separate commands.
  • Update docs/config.md:
    • document reports.daily module overrides;
    • remove active reports.daily_today references.
  • Update docs/operations.md:
    • document Daily as manually targeted by date;
    • document Daily artifact paths and managed-report behavior.
  • Update docs/templates.md:
    • document Daily template variables and generated-text fields.
  • Update internal docs:
    • report registry Daily identity;
    • generated-text Daily validation;
    • reporttemplate Daily assets;
    • daily_planning module;
    • app orchestration only where Daily differs from generic generated-text-template flow.
  • Update examples/config.yml only if it includes report module override examples that should reference daily.
  • Do not describe scheduled Daily behavior, old artifact migration, or future template divergence as implemented behavior.

Acceptance Criteria

  • Non-roadmap docs describe only implemented Daily behavior.
  • No implemented docs describe daily_today as an active report.
  • Examples use implemented report config keys only.
  • README remains concise and links to canonical docs instead of duplicating reference material.

Tests And Checks

go test ./internal/config ./internal/cli
git diff --check
rg -n "daily_today|weather.daily_report|DailyToday" README.md docs examples

Review any remaining matches manually. Roadmap references may remain only when they are clearly historical or future planning context.

Prompt Size

Medium. Suitable for one implementation prompt after code behavior exists.

Stage 8: Final Validation

Goal

Verify the complete Daily cutover and catch stale references or documentation drift.

Required Commands

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

Stale Reference Checks

rg -n "DailyToday|daily_today|weather.daily_report" internal examples README.md docs
rg -n "reports\\.daily_today|weatherreporter generate daily(?!.*--date)" docs examples

The second command uses a regex feature that may not be supported by every rg build. If it fails, use simpler searches:

rg -n "reports\\.daily_today|weatherreporter generate daily" docs examples

Review remaining matches manually.

Manual Review Items

  • Confirm weatherreporter --help lists daily, today, and tomorrow distinctly.
  • Confirm generate daily help or parser behavior makes --date required.
  • Confirm morning and evening batch definitions did not change except where tests explicitly prove intended behavior.
  • Confirm distributor template variables for Daily use report ID/artifact group daily.
  • Confirm old workspace artifacts are not migrated or rewritten.

Deferred Work

Do not include these in the Daily replacement implementation:

  • scheduling Daily in morning or evening batches;
  • migration of old daily_today workspace artifacts;
  • compatibility alias support for daily_today;
  • changing Today or Tomorrow semantics;
  • adding a generic report-template inheritance system;
  • consolidating Daily and Tomorrow public generated-text types;
  • making Daily default to today or tomorrow when --date is omitted;
  • changing Scriptorium prompt registration behavior, which remains out of band.

Open Questions

No open questions block implementation.

The roadmap intentionally chooses the clean-break option for all previously ambiguous areas: daily_today is removed from active behavior, --date is required, Daily is not scheduled, and Daily owns separate template/schema/prompt and planning-module surfaces even when they initially match Tomorrow.

Global Validation Checklist

  • go test ./... passes.
  • go run ./cmd/weatherreporter --help is accurate.
  • git diff --check passes.
  • weatherreporter generate daily --date YYYY-MM-DD is the only valid Daily generation form.
  • weatherreporter generate daily without --date fails.
  • reports.daily is accepted.
  • reports.daily_today is rejected.
  • No active code path uses daily_today.
  • Daily generated reports use weather.daily_generated_text.
  • Daily rendered Markdown uses the Daily template.
  • Daily generated-text JSON uses the Daily schema.
  • Daily data packages include daily_planning, not tomorrow_planning.
  • Daily is absent from morning and evening scheduled batches.
  • Non-roadmap documentation describes only implemented behavior.