# 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/collect` package 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`; `collect` orchestrates collection and returns normalized upstream data. - Use `internal/collect` for all report generation workflows, including `generate `, `run morning`, and `run 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 make `internal/collect` aware 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 morning` should generate `today`, `tomorrow`, then future `daily` reports in ascending local date order. - `run evening` should generate `tomorrow`, then future `daily` reports 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-day` and `weekend` from `run morning`. - Dynamic Daily reports in a batch should use date-qualified `--out-dir` copy names, such as `daily-YYYY-MM-DD.md`. - Keep public CLI syntax unchanged: `weatherreporter run morning` and `weatherreporter run evening` remain the commands. ## Current Repository Shape Current code resolves batches statically: - `internal/cli/root.go` parses `run morning` or `run evening` and builds `app.BatchRequest`. - `internal/app.RunBatchDetailed` calls `ResolveBatch`. - `internal/app.ResolveBatch` delegates to `report.Registry.BatchReports`. - `internal/report.Registry.BatchReports` currently resolves the morning batch to Today, 3-Day, and Weekend except on Sunday. - `internal/report.Registry.BatchReports` currently resolves the evening batch to Tomorrow. - `internal/app.GenerateReport` fetches the Weather API bundle for each report through `FetchBundle`. - `FetchBundle` directly constructs the Weather API adapter and calls `FetchBundle`. - 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: 1. CLI parses the command and loads config. 2. App orchestration calls `internal/collect` once. 3. `internal/collect` calls the Weather API adapter and returns a collection result containing the normalized `weatherdata.Bundle`. 4. App batch planning uses the collected bundle plus report registry metadata to resolve the requested reports. 5. App report generation receives the same collected bundle for every report in the command. 6. 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: ```text 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: ```go 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: 1. `today` 2. `tomorrow` 3. `daily` for each eligible future date beginning with the day after tomorrow ### Evening `run evening` should resolve reports in this order: 1. `tomorrow` 2. `daily` for 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 `startTime` values cover every required hourly start inside the civil day; - for ordinary days, required starts are `00:00` through `23:00` local time; - on daylight-saving transitions, generate required starts by stepping through the actual local civil day from `day.Start` to `day.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: - `Generate` collects once, resolves the single report, then calls `GenerateReport` with the collected result. - `RunBatchDetailed` collects once, plans the batch, then calls `GenerateReport` for each resolved report with the same collected result. - `GenerateReport` requires 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.md` - `docs/operations.md` - `docs/internal/app-orchestration.md` - `docs/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/collect` aware 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 morning` or `run evening`. ## Open Questions None block the roadmap.