249 lines
9.4 KiB
Markdown
249 lines
9.4 KiB
Markdown
# 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:
|
|
|
|
```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.
|