9.4 KiB
Batch Collection Roadmap
Purpose
This roadmap defines the planned change to make weatherreporter run morning
and weatherreporter run evening use one canonical upstream collection path
and data-aware batch planning.
The feature has two related goals:
- move upstream Weather API collection into a single
internal/collectpackage used by all generation workflows; - update scheduled batches so they generate Today, Tomorrow, and future Daily reports according to available full-day hourly forecast coverage.
This document lives under docs/roadmap/ because the behavior described here
is not yet implemented.
User Intent
Batch commands should produce a practical publication set while avoiding partial Daily reports.
Morning publication should generate:
- Today report for the current civil day;
- Tomorrow report for the next civil day;
- one Daily report for each later future civil day where the upstream hourly forecast fully covers the entire target day.
Evening publication should generate:
- Tomorrow report for the next civil day;
- one Daily report for each later future civil day where the upstream hourly forecast fully covers the entire target day.
Neither batch should generate Daily reports for partially covered days. That keeps the Daily report format simple and avoids requiring templates or modules to explain incomplete forecast coverage.
The morning batch should no longer include the legacy 3-Day Outlook or Weekend Outlook. Those reports remain individually generated report types unless separately removed.
Locked Decisions
- Add a new canonical upstream collection package:
internal/collect. - Keep Weather API HTTP details in
internal/adapters/weatherapi;collectorchestrates collection and returns normalized upstream data. - Use
internal/collectfor all report generation workflows, includinggenerate <report>,run morning, andrun evening. - Fetch upstream weather data once per command invocation.
- Pass the collected result into report generation; report generation should not fetch directly from Weather API.
- Keep batch planning in
internal/app; do not makeinternal/collectaware of morning, evening, report IDs, or batch membership. - Centralize batch-specific app planning in a single file, expected to be
internal/app/batch_plan.go, unless implementation shows a clearer local name. run morningshould generatetoday,tomorrow, then futuredailyreports in ascending local date order.run eveningshould generatetomorrow, then futuredailyreports in ascending local date order.- Future Daily eligibility is based on full hourly forecast coverage, not narrative forecast availability.
- Daily expansion starts with the day after tomorrow for both morning and evening batches.
- Remove
three-dayandweekendfromrun morning. - Dynamic Daily reports in a batch should use date-qualified
--out-dircopy names, such asdaily-YYYY-MM-DD.md. - Keep public CLI syntax unchanged:
weatherreporter run morningandweatherreporter run eveningremain the commands.
Current Repository Shape
Current code resolves batches statically:
internal/cli/root.goparsesrun morningorrun eveningand buildsapp.BatchRequest.internal/app.RunBatchDetailedcallsResolveBatch.internal/app.ResolveBatchdelegates toreport.Registry.BatchReports.internal/report.Registry.BatchReportscurrently resolves the morning batch to Today, 3-Day, and Weekend except on Sunday.internal/report.Registry.BatchReportscurrently resolves the evening batch to Tomorrow.internal/app.GenerateReportfetches the Weather API bundle for each report throughFetchBundle.FetchBundledirectly constructs the Weather API adapter and callsFetchBundle.- Daily report resolution already supports explicit target dates through
report.ResolveRequest.Date.
This means current batch resolution cannot decide future Daily membership from available upstream data without either fetching during planning or attempting report generation for candidate dates. It also means multiple reports in one batch can fetch different upstream snapshots.
Target Architecture
The target command flow is:
- CLI parses the command and loads config.
- App orchestration calls
internal/collectonce. internal/collectcalls the Weather API adapter and returns a collection result containing the normalizedweatherdata.Bundle.- App batch planning uses the collected bundle plus report registry metadata to resolve the requested reports.
- App report generation receives the same collected bundle for every report in the command.
- Facts, modules, prompt input, generated text, templates, state, and notifications operate as they do today, but consume already-collected data.
The intended dependency direction is:
internal/adapters/weatherapi -> internal/collect -> internal/app -> internal/facts -> internal/briefing/internal modules
Report definitions still live in internal/report. Report definitions should
not know how upstream data is fetched or how batch membership is expanded from
available data.
internal/collect Contract
The initial package should be intentionally narrow. A suitable first contract is:
package collect
type Request struct {
Config config.Config
}
type Result struct {
Bundle *weatherdata.Bundle
}
Expected behavior:
collect.Run(ctx, Request)constructs and uses the Weather API adapter.- It returns the normalized Weather API bundle.
- It wraps collection errors with operation context.
- It does not derive report facts.
- It does not resolve reports or batches.
- It does not write state artifacts.
- It does not invoke Scriptorium or distributor.
Future source families, such as radar, observations history, or additional review/report inputs, should be added to this package as upstream collection responsibilities. The package should remain source collection, not report policy.
Batch Target Behavior
Morning
run morning should resolve reports in this order:
todaytomorrowdailyfor each eligible future date beginning with the day after tomorrow
Evening
run evening should resolve reports in this order:
tomorrowdailyfor each eligible future date beginning with the day after tomorrow
Future Daily Eligibility
Eligibility for each future Daily report:
- compute the target civil day in
weather_api.timezone; - examine the collected hourly forecast periods;
- require hourly periods whose local
startTimevalues cover every required hourly start inside the civil day; - for ordinary days, required starts are
00:00through23:00local time; - on daylight-saving transitions, generate required starts by stepping through
the actual local civil day from
day.Starttoday.End, so 23-hour and 25-hour days are handled consistently; - require each selected period to have a valid start and end;
- stop scanning once no later complete civil day can be found within the available hourly forecast range.
The planner should use exact local hourly start matching for eligibility, not mere overlap. This keeps the contract clear: a day is eligible only when the hourly source contains a full set of hourly rows for that day.
Report Generation Contract
After the collection refactor, GenerateReport should no longer fetch upstream
data itself. The preferred final shape is:
Generatecollects once, resolves the single report, then callsGenerateReportwith the collected result.RunBatchDetailedcollects once, plans the batch, then callsGenerateReportfor each resolved report with the same collected result.GenerateReportrequires collected data and returns an actionable error if called without it.
A transitional optional collected-data field may be used during implementation, but the final state should have one explicit collection path and no hidden Weather API fetch inside report generation.
Output And State Policy
Existing managed workspace artifact paths should remain stable. Multiple Daily
reports can appear in one batch, so --out-dir copies must not use the same
daily.md filename for every dynamic Daily report. Dynamic Daily batch copies
should use daily-YYYY-MM-DD.md. Today and Tomorrow should keep their existing
batch copy names.
Distributor upload paths and managed report paths should continue to be derived
from report definitions and resolved report metadata, not from optional
--out-dir copies.
Implementation Planning
The staged implementation plan belongs in docs/roadmap/implementation.md.
That document should be treated as the executable plan for coding agents.
After implementation, update implemented docs only:
docs/cli.mddocs/operations.mddocs/internal/app-orchestration.mddocs/internal/report-registry.md- relevant troubleshooting entries if new failure modes are surfaced
Do not document future collection sources outside roadmap docs.
Refactors To Avoid
- Do not create a generic workflow engine.
- Do not move report definitions out of
internal/report. - Do not make
internal/collectaware of report IDs, prompt IDs, or batch names. - Do not make modules fetch upstream data.
- Do not add config knobs for partial Daily coverage in this pass.
- Do not remove 3-Day or Weekend report definitions unless separately planned.
- Do not change public CLI syntax for
run morningorrun evening.
Open Questions
None block the roadmap.