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
dailyis a separate report ID, not an alias fortoday,tomorrow, or legacydaily_today.weatherreporter generate dailyremains the public command, but it must run the new generated-text-template Daily report.weatherreporter generate dailyrequires--date YYYY-MM-DD.- The supplied date is interpreted as a local civil date in the effective
report timezone after config and
--tzoverrides. - 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
dailyand generated-text schema IDdaily. - Daily uses artifact group
dailyand batch output namedaily.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_todayreport definition andreports.daily_todayconfig-key support. - Historical workspace artifacts with
daily_todaymetadata are not migrated.
Implementation Principles
- Preserve public CLI syntax except for the intentional breaking change that
generate dailynow 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/briefingand module IDs/options ininternal/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.gointernal/briefing/tomorrow_planning_module.gointernal/briefing/today_planning_module.gointernal/briefing/modules.gointernal/briefing/derived_modules_test.godocs/roadmap/daily.md
Implementation
- Add
module.DailyPlanningwith valuedaily_planning. - Add
module.DailyPlanningOptions struct{}. - Add
internal/briefing/daily_planning_module.go. - Add
DailyPlanningModulewith the initial fields:morning_readinesscommute_school_workday_concernsovernight_change_watch
- Build the Daily planning module from the same underlying summary inputs as
Tomorrow planning, but do not reuse the public
TomorrowPlanningModuletype. - Share private helper functions with Tomorrow only when the helper expresses report-neutral mechanics.
- Register
daily_planningin the default module registry with:- stanza name
daily_planning - default options
module.DailyPlanningOptions{} - supported reports
[]report.ID{report.Daily}afterreport.Dailyexists in Stage 3; if Stage 1 is implemented beforereport.Daily, add the module ID/options now and wire report support in Stage 3.
- stanza name
Acceptance Criteria
daily_planningis 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.gointernal/generatedtext/today.gointernal/generatedtext/catalog.gointernal/generatedtext/*_test.gointernal/reporttemplate/reporttemplate.gointernal/reporttemplate/templates/tomorrow.md.tmplinternal/reporttemplate/prompts/tomorrow.generated_text.mdinternal/reporttemplate/schemas/tomorrow.generated_text.schema.jsoninternal/reporttemplate/reporttemplate_test.go
Implementation
- Add
internal/generatedtext/daily.go. - Add
type Daily structwith the same public JSON shape as Tomorrow:summaryrequired stringforecast_discussionrequired[]stringprecipitation_timingoptional stringconfidenceoptional 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
dailymaps toValidateDaily. - 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.gointernal/generatedtext/render_context_test.gointernal/briefing/*_module.gointernal/module/module.gointernal/factsinternal/reporttemplate/templates/tomorrow.md.tmpl
Implementation
- Add:
type DailyRenderContext struct {
Report DailyReportContext
GeneratedText Daily
Modules DailyTemplateModules
Collected facts.CollectedFacts
Derived facts.DerivedFacts
}
- Add
DailyReportContextwith:TitleForecastDateForecastDateLabelForecastDayNameGeneratedAtGeneratedAtLabelValidPeriodTimezone
- Add
DailyTemplateModuleswith the Daily template surfaces defined indocs/roadmap/daily.md, includingDailyPlanning. - Add a Daily daypart context if the Tomorrow daypart context is not already generic enough to use privately.
- Add
BuildDailyRenderContext. - Generate
Titleas<weekday>'s Weather, for exampleMonday's Weather. - Build
ForecastDateLabelfrom 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
CollectedandDerivedfor 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.gointernal/report/daily_report.gointernal/report/today_report.gointernal/report/tomorrow_report.gointernal/report/names.gointernal/report/period.gointernal/report/period_test.gointernal/briefing/modules.gointernal/app/app.gointernal/changes
Implementation
- Add or change the active Daily report ID to:
Daily ID = "daily"
- Remove active use of
DailyToday.- Prefer removing the exported
DailyTodayconstant entirely if no active code needs it. - If temporary compile sequencing requires keeping it during this stage, remove it before the stage is complete.
- Prefer removing the exported
- Replace
dailyTodayDefinitionwithdailyDefinition. - 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
- ID
- Add
dailyModules()with the module order fromdocs/roadmap/daily.md:metadatacurrent_conditionsnarrative_forecastderived_daily_summaryderived_daypart_summariesprecip_timingalert_digestspc_convective_outlooksarea_forecast_discussionspc_convective_discussionweather_storyoutdoor_windowsdaily_planninghourly_forecast
- Add
resolveDailyrequiringResolveRequest.Date.- Return an actionable error when
Dateis zero. - Resolve the date as a local civil day in
ResolveRequest.Location.
- Return an actionable error when
- Update report name/config resolution:
IDForCommandName("daily")returnsDaily.IDForConfigKey("daily")returnsDaily.IDForConfigKey("daily_today")returns an unknown config-key error.
- Update module registry supported-report lists:
- replace
report.DailyTodaywithreport.Dailyfor shared Daily-compatible modules; - add
report.Dailyto Daily planning support.
- replace
- Update Recent Changes dispatch where it currently groups daily-style reports,
replacing
DailyTodaywithDaily. - Ensure
BatchReportscontinues to include Today in the morning batch and Tomorrow in the evening batch, with no Daily membership.
Acceptance Criteria
report.DefaultRegistry()includesdailyand notdaily_today.weatherreporter generate dailyresolves to report IDdaily.reports.dailyconfig overrides apply to Daily.reports.daily_todayis 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_todaysnapshots 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:
- report ID/name/config resolution;
- module registry and Recent Changes updates;
- 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.gointernal/cli/root_test.gointernal/app/app.gointernal/app/app_test.gointernal/stateinternal/adapters/scriptoriuminternal/adapters/distributorexamples/config.yml
Implementation
- Update CLI date policy:
generate dailyrequires--date YYYY-MM-DD;- missing
--datereturns a concise actionable error; - malformed
--dateremains an error; generate todaykeeps its current behavior;generate tomorrowremains 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.
- prompt ID
- 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-DDruns through the generated-text-template path.weatherreporter generate dailywithout--datefails before generation.weatherreporter generate daily --date bad-datefails 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
--outcopy 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/reportinternal/briefinginternal/configinternal/appinternal/changesinternal/promptinputinternal/stateinternal/generatedtextinternal/reporttemplate- package tests
Implementation
- Remove remaining production-code references to:
DailyToday;daily_today;weather.daily_reporton 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_todayas a hidden alias.
Acceptance Criteria
rg -n "DailyToday|daily_today|weather.daily_report" internal examples docshas 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
dailyresolves todaily_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.mddocs/cli.mddocs/config.mddocs/operations.mddocs/templates.mddocs/troubleshooting.mddocs/internal/report-registry.mddocs/internal/generatedtext.mddocs/internal/reporttemplate.mddocs/internal/module.mddocs/internal/app-orchestration.mdexamples/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.
- document
- Update
docs/config.md:- document
reports.dailymodule overrides; - remove active
reports.daily_todayreferences.
- document
- 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_planningmodule;- app orchestration only where Daily differs from generic generated-text-template flow.
- Update
examples/config.ymlonly if it includes report module override examples that should referencedaily. - 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_todayas 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 --helplistsdaily,today, andtomorrowdistinctly. - Confirm
generate dailyhelp or parser behavior makes--daterequired. - 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_todayworkspace 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
--dateis 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 --helpis accurate.git diff --checkpasses.weatherreporter generate daily --date YYYY-MM-DDis the only valid Daily generation form.weatherreporter generate dailywithout--datefails.reports.dailyis accepted.reports.daily_todayis 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, nottomorrow_planning. - Daily is absent from morning and evening scheduled batches.
- Non-roadmap documentation describes only implemented behavior.