Files
weatherreporter/docs/roadmap/batch.md

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/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 <report>, 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:

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:

  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.