diff --git a/docs/cli.md b/docs/cli.md index 1521ee0..07ae661 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -9,7 +9,7 @@ batches, and inspects stored artifacts. weatherreporter generate today --out ./today.md ``` -This loads configuration, fetches weather data, writes managed workspace +This loads configuration, collects weather data, writes managed workspace artifacts, runs `scriptorium render` as a preflight check, runs structured `scriptorium run`, validates generated text, renders the embedded Today template, and writes an extra Markdown copy to `./today.md`. If distributor @@ -70,7 +70,7 @@ Hourly Report, 3-Day Outlook, and Weekend Outlook are explicit only; they are not included in `run morning` or `run evening`. `inspect` commands read existing workspace artifacts and emit JSON to stdout. -They do not fetch weather data or invoke `scriptorium`. +They do not collect weather data or invoke `scriptorium`. ## Flags diff --git a/docs/config.md b/docs/config.md index eb74bce..8ace2c6 100644 --- a/docs/config.md +++ b/docs/config.md @@ -29,8 +29,8 @@ weather_api: base_url: https://weather.api.example.com/ ``` -`weather_api.base_url` is required for commands that fetch weather data. Other -fields fall back to defaults. +`weather_api.base_url` is required for commands that collect weather data. +Other fields fall back to defaults. ## Production-Oriented Config @@ -41,7 +41,7 @@ config test suite. ### `weather_api` -- `base_url`: absolute base URL for the Weather API. Required for generation and fetch workflows. +- `base_url`: absolute base URL for the Weather API. Required for generation and collection workflows. - `timeout`: HTTP timeout duration. Default: `10s`. - `precision`: numeric precision query value. Default: `1`. - `units`: Weather API units query value. Default: `us`. diff --git a/docs/internal/app-orchestration.md b/docs/internal/app-orchestration.md index 91bab6a..c25f8b1 100644 --- a/docs/internal/app-orchestration.md +++ b/docs/internal/app-orchestration.md @@ -18,7 +18,7 @@ Inputs: - `GenerateRequest` for one report command - `BatchRequest` for morning or evening batch commands -- `FetchBundleRequest` for explicit bundle fetch and save workflows +- `FetchBundleRequest` for explicit bundle collection and save workflows - `ReportRequest` for single-report generation - resolved report definitions from `internal/report` - collection results from `internal/collect` @@ -33,7 +33,7 @@ Outputs: notification result when attempted - batch summaries with per-report status, artifact paths, error text, and notification outcome when attempted -- saved Weather API bundle JSON for fetch workflows +- saved Weather API bundle JSON for explicit bundle collection workflows - inspection JSON values for reports, metadata, module snapshots, data packages, prior snapshots, and source provenance diff --git a/docs/internal/briefing.md b/docs/internal/briefing.md index 8cda4fe..85b4d1e 100644 --- a/docs/internal/briefing.md +++ b/docs/internal/briefing.md @@ -77,7 +77,7 @@ remain in report metadata, source provenance, and integration artifacts. - This package selects and shapes already-collected weather facts for prompts. - It validates module composition against report compatibility and option types. -- It does not fetch weather data, compare prior snapshots, write module +- It does not collect weather data, compare prior snapshots, write module snapshots, build YAML data packages, invoke Scriptorium, or write workflow metadata. diff --git a/docs/internal/module.md b/docs/internal/module.md index 889d56e..71b5f06 100644 --- a/docs/internal/module.md +++ b/docs/internal/module.md @@ -250,7 +250,7 @@ meet the severity threshold. - This package owns module identifiers, config item envelopes, output envelopes, snapshot validation, and typed stanza lookup. -- It does not define report IDs, execute builders, fetch weather data, derive +- It does not define report IDs, execute builders, collect weather data, derive forecast facts, write state, or invoke Scriptorium. ## State Or Manifest Behavior diff --git a/docs/internal/prompt-input.md b/docs/internal/prompt-input.md index af9a259..5ea204d 100644 --- a/docs/internal/prompt-input.md +++ b/docs/internal/prompt-input.md @@ -128,7 +128,7 @@ Current categories are: - This package owns prompt package schema, YAML marshaling, YAML loading, and validation. -- It does not fetch weather data, derive forecast summaries, execute modules, +- It does not collect weather data, derive forecast summaries, execute modules, choose module prompt export shapes, find prior snapshots, compare changes, choose artifact paths, or invoke Scriptorium. diff --git a/docs/internal/report-registry.md b/docs/internal/report-registry.md index 9a9a1c6..0666ac2 100644 --- a/docs/internal/report-registry.md +++ b/docs/internal/report-registry.md @@ -78,7 +78,7 @@ must be after start time. ## Boundaries `internal/report` defines report metadata, public report names, batch command -names, output naming, and time coverage. It does not fetch weather data, plan +names, output naming, and time coverage. It does not collect weather data, plan batch membership, build module values, compare snapshot contents, write state, parse CLI flags, or invoke Scriptorium. diff --git a/docs/internal/reporttemplate.md b/docs/internal/reporttemplate.md index 76e536b..1353442 100644 --- a/docs/internal/reporttemplate.md +++ b/docs/internal/reporttemplate.md @@ -43,7 +43,7 @@ Generated-text prompt sources are maintained under ## Boundaries This package owns embedded asset lookup, Go template parsing, and Markdown -template execution. It does not fetch weather data, build module outputs, +template execution. It does not collect weather data, build module outputs, validate GeneratedText, construct render contexts, choose report definitions, write artifacts, invoke Scriptorium, or notify distributor. diff --git a/docs/internal/scriptorium-adapter.md b/docs/internal/scriptorium-adapter.md index b7100b2..2170c8b 100644 --- a/docs/internal/scriptorium-adapter.md +++ b/docs/internal/scriptorium-adapter.md @@ -34,7 +34,7 @@ Outputs: `internal/adapters/scriptorium` owns Scriptorium command construction and subprocess execution. It does not choose report types, build prompt input, -fetch weather data, decide workflow order, or persist workflow metadata. +collect weather data, decide workflow order, or persist workflow metadata. The adapter exposes request and result structs for render, Markdown run, and structured generated-text run operations. State persistence uses state-owned diff --git a/docs/operations.md b/docs/operations.md index 152f07d..cc90aae 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -254,8 +254,8 @@ and the default output filename value is `daily.md`. For Today, the default report ID and artifact group values are both `today`, and the batch output filename value is `today.md`. -Notification happens after final metadata save for generated reports. Weather -API, module snapshot, data-package, render preflight, Scriptorium run, +Notification happens after final metadata save for generated reports. +Collection, module snapshot, data-package, render preflight, Scriptorium run, generated-text validation, template rendering, and metadata-save failures do not trigger notification. A notification failure fails that report. In a batch, other reports continue, the failed report includes notification @@ -281,7 +281,7 @@ bundle, so existing uploaded dated report paths can remain available. ## Inspection Inspection commands read existing workspace artifacts and emit JSON to stdout. -They do not fetch weather data or run `scriptorium`. +They do not collect weather data or run `scriptorium`. ```text weatherreporter inspect reports --limit 10 diff --git a/docs/roadmap/batch.md b/docs/roadmap/batch.md deleted file mode 100644 index f5e4931..0000000 --- a/docs/roadmap/batch.md +++ /dev/null @@ -1,248 +0,0 @@ -# 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. diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md index 3d6d9af..c17cf08 100644 --- a/docs/roadmap/future.md +++ b/docs/roadmap/future.md @@ -73,8 +73,8 @@ represented in `CollectedFacts`. Future module work should preserve these boundaries: -- collect upstream facts once per report run -- keep upstream fetching out of modules +- keep upstream collection in app orchestration +- keep upstream collection out of modules - keep broad reusable calculations in `DerivedFacts` - keep prompt-facing field shape inside module builders - use typed options for configurable module behavior diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index e206424..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,443 +0,0 @@ -# Batch Collection Implementation Roadmap - -## Purpose - -This is the staged implementation plan for `docs/roadmap/batch.md`. Implement -the stages in order. The feature has two goals: - -- route all upstream Weather API collection through a canonical - `internal/collect` package; -- update `run morning` and `run evening` so they use one collected snapshot and - dynamically add future Daily reports only for dates with complete hourly - coverage. - -This is an implementation roadmap only. Background, user intent, and target -policy live in `docs/roadmap/batch.md`. - -## Global Constraints - -- Preserve public CLI syntax. -- Preserve managed workspace artifact paths. -- Preserve distributor upload behavior and paths. -- Keep Weather API HTTP details inside `internal/adapters/weatherapi`. -- Keep source collection in `internal/collect`. -- Keep batch planning in `internal/app`. -- Keep report definitions in `internal/report`. -- Do not make `internal/collect` aware of report IDs, prompt IDs, or batch - names. -- Do not add config fields for partial Daily coverage. -- Do not create a workflow engine, scheduler package, or plugin system. -- Do not remove 3-Day or Weekend report definitions in this change. - -## Stage 1: Add Canonical Collection Package - -Goal: introduce `internal/collect` as the only app-facing upstream collection -API while preserving current behavior. - -Implementation: - -- Add `internal/collect`. -- Define: - - ```go - type Request struct { - Config config.Config - } - - type Result struct { - Bundle *weatherdata.Bundle - } - ``` - -- Add `Run(ctx context.Context, req Request) (*Result, error)`. -- `Run` should construct the Weather API adapter with `weatherapi.New` and call - `client.FetchBundle(ctx)`. -- Return an actionable error when adapter construction or fetch fails. -- Keep the returned data normalized as `*weatherdata.Bundle`; do not derive - `facts.CollectedFacts` or `facts.DerivedFacts` in this package. -- Update `internal/app.FetchBundle` and `FetchAndSaveBundle`, if retained, to - call `collect.Run` rather than constructing `weatherapi.New` directly. - -Tests: - -- Add `internal/collect` tests using a local Weather API test server or a small - adapter seam if needed. -- Keep existing `FetchAndSaveBundle` app tests passing. -- Ensure collection errors include collection/fetch context without leaking - secrets. - -Acceptance: - -- `internal/collect` owns app-facing Weather API collection. -- `internal/app.FetchBundle` no longer constructs `weatherapi.New` directly. -- No report or batch behavior changes yet. - -Validation: - -```sh -go test ./internal/collect ./internal/app ./internal/adapters/weatherapi -git diff --check -``` - -## Stage 2: Add App Collection Seam - -Goal: make collection testable from app orchestration without requiring live -Weather API calls. - -Implementation: - -- Add a narrow app-owned collector interface, for example: - - ```go - type Collector interface { - Run(context.Context, collect.Request) (*collect.Result, error) - } - ``` - -- Add a default adapter that calls `collect.Run`. -- Add `Collector` fields to `GenerateRequest` and `BatchRequest`. -- Default to the real collector when the request does not provide one. -- Do not expose collector options through CLI. - -Tests: - -- Add app tests proving `Generate` uses the provided collector. -- Add app tests proving collection failure stops generation before report - execution. -- Add batch tests proving `RunBatchDetailed` can use a fake collector in later - stages. - -Acceptance: - -- App orchestration can be tested with a fake collector. -- CLI behavior is unchanged. -- External adapter types do not leak into app request or result structs. - -Validation: - -```sh -go test ./internal/app ./internal/cli -git diff --check -``` - -## Stage 3: Make Report Generation Require Collected Data - -Goal: remove hidden Weather API fetching from `GenerateReport`. - -Implementation: - -- Add a collection field to `ReportRequest`, for example: - - ```go - Collection collect.Result - ``` - -- Update `Generate` to: - - collect once; - - resolve the requested report; - - pass the collection into `GenerateReport`. -- Update `GenerateReport` to use `req.Collection.Bundle`. -- If `req.Collection.Bundle` is nil, return an actionable error such as - `collected weather bundle is required`. -- Remove the direct `FetchBundle` call from `GenerateReport`. -- Keep `BuildReportFacts` unchanged: it should still receive a - `*weatherdata.Bundle`. -- Update all app tests that call `GenerateReport` directly to pass a collected - test bundle through `ReportRequest.Collection`. - -Tests: - -- Add or update tests proving single-report generation collects once. -- Add or update tests proving `GenerateReport` fails before state writes when - no collected bundle is provided. -- Keep generated-text, notification, state, and output-copy tests passing with - the explicit collection field. - -Acceptance: - -- `GenerateReport` has no direct Weather API fetch path. -- Single-report commands still produce the same artifacts. -- `GenerateReport` has an explicit data dependency. - -Validation: - -```sh -go test ./internal/app ./internal/cli -rg -n "weatherapi\\.New|\\.FetchBundle\\(" internal -git diff --check -``` - -Expected grep matches at this stage should be limited to -`internal/collect`, `internal/adapters/weatherapi`, and their tests, plus any -transitional app fetch helper tests that explicitly verify `FetchBundle`. - -## Stage 4: Add Hourly Full-Day Coverage Helper - -Goal: isolate the Daily eligibility rule before changing batch behavior. - -Implementation: - -- Add helper logic in `internal/app/batch_plan.go`. -- The helper should inspect `weatherdata.ForecastRun` hourly periods and return - eligible future Daily dates. -- Inputs should include: - - hourly forecast run; - - `now`; - - loaded report timezone/location. -- The helper should: - - start candidate Daily expansion at the day after tomorrow; - - compute local civil days with `timeutil.CivilDay`; - - build required hourly start instants by stepping from civil-day start to - civil-day end in one-hour increments; - - require every required start instant to exist as a valid hourly period - `StartTime`; - - require matching periods to have valid end times after start times; - - scan candidate dates through the maximum local date represented by hourly - period start times; - - return dates in ascending local date order; - - return no dates when hourly data is missing. -- Use exact start-time matching, not overlap-only matching. - -Tests: - -- Full ordinary local day with starts `00:00` through `23:00` is eligible. -- Missing one required hour makes the date ineligible. -- Partial final day is skipped. -- Today and tomorrow are never returned by expansion. -- Multiple eligible future days are returned in order. -- Non-hourly or invalid periods are ignored. -- DST transition days use actual civil-day hourly instants. -- Missing hourly forecast returns no dynamic Daily dates. - -Acceptance: - -- Daily eligibility is tested independently from batch execution. -- The helper does not resolve reports, call Weather API, write state, or invoke - Scriptorium. - -Validation: - -```sh -go test ./internal/app -git diff --check -``` - -## Stage 5: Add Shared Batch Planner - -Goal: make morning and evening batch membership app-owned and data-aware. - -Implementation: - -- Continue using `report.BatchForCommandName` for CLI validation. -- Add an internal planned report type in `internal/app`, for example: - - ```go - type plannedBatchReport struct { - Resolved report.Resolved - OutputCopyName string - } - ``` - -- Implement app-owned batch planning in `internal/app/batch_plan.go`. -- Morning plan: - - resolve `report.Today`; - - resolve `report.Tomorrow`; - - resolve `report.Daily` for each eligible future date from Stage 4. -- Evening plan: - - resolve `report.Tomorrow`; - - resolve `report.Daily` for each eligible future date from Stage 4. -- Resolve dynamic Daily reports by setting `ResolveRequest.Date` to the target - local date. -- Dynamic Daily planned reports should set `OutputCopyName` to - `daily-YYYY-MM-DD.md`. -- Today and Tomorrow should use their report definition batch output names. -- Remove `three-day` and `weekend` from morning planning. -- Stop using `report.Registry.BatchReports` from app batch execution. Either - remove that method if it becomes unused, or leave it unused only if tests or - docs still need it temporarily. Do not allow app batch execution to use it. - -Tests: - -- Morning order is Today, Tomorrow, then Daily dates. -- Evening order is Tomorrow, then Daily dates. -- Dynamic Daily dates start day after tomorrow. -- 3-Day and Weekend are absent from morning. -- Dynamic Daily resolves valid periods for the requested dates. -- Planned dynamic Daily output copy names are date-qualified. -- Unknown batch names still fail through existing CLI/report validation. - -Acceptance: - -- Batch membership is owned by `internal/app`. -- Batch membership is based on one collected bundle. -- `internal/collect` has no report or batch policy. - -Validation: - -```sh -go test ./internal/app ./internal/report ./internal/cli -git diff --check -``` - -## Stage 6: Use One Collection Result Per Batch - -Goal: make both batch commands collect once and reuse that collection for every -report. - -Implementation: - -- Update `RunBatchDetailed` to: - - resolve the effective time; - - collect once using the request collector/default collector; - - plan the batch from that collection; - - pass the same `collect.Result` into every `GenerateReport` call. -- If collection fails, return before generating any report. -- Update batch report result construction to use `plannedBatchReport`. -- Update `batchOutputPath` or replace it with planned output-copy path logic: - - if `OutputDir` is empty, return empty output path; - - if `planned.OutputCopyName` is non-empty, use that; - - otherwise use `resolved.Definition.BatchOutputName`; - - join with `OutputDir`. -- Preserve per-report failure behavior after planning: later reports continue - after a report failure. -- Preserve notification failure behavior. - -Tests: - -- Counted or fake collector proves one collection call for morning. -- Counted or fake collector proves one collection call for evening. -- Collection failure prevents any renderer calls. -- Report failure still allows later planned reports to run. -- Notification failure still marks only that report failed and continues. -- `--out-dir` output paths use: - - `today.md` for Today; - - `tomorrow.md` for Tomorrow; - - `daily-YYYY-MM-DD.md` for dynamic Daily. - -Acceptance: - -- Both batch commands use one collection result per invocation. -- No report in a batch performs its own upstream fetch. -- Batch JSON and stderr behavior remain coherent. - -Validation: - -```sh -go test ./internal/app ./internal/cli ./internal/state -rg -n "weatherapi\\.New|\\.FetchBundle\\(" internal -git diff --check -``` - -Expected grep matches should be limited to `internal/collect`, -`internal/adapters/weatherapi`, and their tests. - -## Stage 7: Remove Or Retire Legacy Static Batch Resolution - -Goal: prevent future code from accidentally using stale batch membership. - -Implementation: - -- Inspect usages of `report.Registry.BatchReports`. -- If no longer needed, delete `Registry.BatchReports` and related tests. -- If keeping a reduced helper is necessary, document in code comments that app - batch planning is authoritative and ensure no production path calls the old - static membership helper. -- Update report-registry tests that currently assert old morning/evening - membership. - -Tests: - -- No production code path calls static registry batch membership. -- Report registry tests continue to cover report definitions, generated flags, - batch output names, and valid-period resolution as appropriate. - -Acceptance: - -- There is no stale static morning/evening membership path in production code. -- Future agents cannot accidentally reintroduce old Today/3-Day/Weekend - morning membership by calling a legacy helper. - -Validation: - -```sh -go test ./internal/report ./internal/app -rg -n "BatchReports\\(" internal -git diff --check -``` - -Expected `BatchReports` grep result should be empty or limited to tests or -comments that explicitly document it as non-production. - -## Stage 8: Documentation Updates - -Goal: update implemented documentation after the code behavior changes. - -Implementation: - -- Update `docs/cli.md`: - - morning batch now generates Today, Tomorrow, and eligible future Daily - reports; - - evening batch now generates Tomorrow and eligible future Daily reports; - - Daily eligibility is full hourly coverage. -- Update `docs/operations.md` with the same operator-facing behavior and - collection-failure behavior. -- Update `docs/internal/app-orchestration.md`: - - `internal/collect` boundary; - - one collection per command; - - app-owned batch planning; - - explicit collected data passed to report generation. -- Update `docs/internal/report-registry.md`: - - report definitions remain canonical for report metadata; - - batch membership is app-owned when data-dependent. -- Add a new implemented internal component doc for `internal/collect`, for - example `docs/internal/collect.md`. -- Do not describe future source families as implemented behavior. - -Tests/checks: - -- Grep docs for stale old batch language: Today/3-Day/Weekend morning, - Weekend except Sunday, Daily not part of scheduled batches. -- Confirm docs do not imply `internal/collect` owns report or batch policy. - -Acceptance: - -- Non-roadmap docs describe only implemented behavior. -- Operator docs and internal docs agree about batch membership. - -Validation: - -```sh -rg -n "3-Day|Weekend|scheduled batch|not part of scheduled|except on Sunday" docs README.md -git diff --check -``` - -## Stage 9: Final Validation - -Goal: verify the completed migration and behavior end to end. - -Run: - -```sh -go test ./... -go run ./cmd/weatherreporter --help -rg -n "weatherapi\\.New|\\.FetchBundle\\(" internal -rg -n "BatchReports\\(" internal -git diff --check -``` - -Manual review: - -- `weatherapi.New` and `.FetchBundle(` matches are limited to - `internal/collect`, `internal/adapters/weatherapi`, and their tests. -- `BatchReports(` matches are absent from production paths, or explicitly - documented as non-production if retained. -- `run morning` output summary can include multiple Daily reports without - duplicate `--out-dir` copy paths. -- `run evening` uses the same collection and dynamic Daily expansion logic as - morning. -- Managed workspace artifact paths are unchanged. -- Distributor upload paths are unchanged. - -## Open Questions - -None. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 9f12024..0cac8cf 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -6,7 +6,7 @@ fixes. See [CLI reference](cli.md), [Configuration reference](config.md), and ## `weather_api.base_url is required` -Symptom: a generation command fails before fetching weather data. +Symptom: a generation command fails before collecting weather data. Likely cause: no Weather API base URL is configured. @@ -235,13 +235,18 @@ Relevant docs: [Report Templates](templates.md), Symptom: `run morning` or `run evening` returns nonzero. -Likely cause: at least one report in the batch failed. +Likely cause: weather collection failed before planning, or at least one +planned report failed after planning succeeded. -Diagnostic: inspect stdout for the JSON summary and stderr for compact status -lines. +Diagnostic: if stdout contains a JSON summary, inspect each failed report item +and stderr status line. If no summary was emitted, inspect the command error; +configuration, Weather API collection, or batch validation failed before any +report artifacts were created. -Safe fix: use the failed report's artifact paths from the summary, then inspect -metadata, sources, module snapshot, and data package for that RunID. +Safe fix: for collection failures, fix the configuration or upstream Weather +API availability and rerun the batch. For report failures, use the failed +report's artifact paths from the summary, then inspect metadata, sources, +module snapshot, and data package for that RunID. Relevant docs: [CLI reference](cli.md), [Operations guide](operations.md).