diff --git a/docs/internal/collect.md b/docs/internal/collect.md index 00249b5..2817ebe 100644 --- a/docs/internal/collect.md +++ b/docs/internal/collect.md @@ -1,59 +1,36 @@ # Collection Internals -`internal/collect` is the application-facing boundary for collecting the +`internal/collect` is the small application-facing boundary that obtains one normalized Weather API bundle. The external HTTP contract belongs in the -[Weather API integration guide](../integrations/weatherapi.md); normalized data -semantics belong in [weather-data internals](weather-data.md). +[Weather API integration guide](../integrations/weatherapi.md); normalized +source values belong in [weather-data internals](weather-data.md). ## Contract -`Run` accepts a `context.Context` and a `Request` containing effective -`config.Config`. It constructs the Weather API adapter from that configuration, -calls `FetchBundle`, and returns `Result{Bundle: *weatherdata.Bundle}`. +`Run` receives a context and effective configuration in `Request`. It creates +the Weather API adapter, calls `FetchBundle`, and returns the adapter's +normalized bundle in `Result`. Adapter construction errors are wrapped as +weather-collection setup errors and fetch errors as bundle-collection errors. -The adapter's successful readiness request for current conditions is reused as -that normalized source; collection does not trigger a second identical current -conditions request. +The package neither chooses reports nor derives facts, builds modules, invokes +Promptkit, writes files, or sends notifications. Request scheduling, endpoint +retrieval, response limits, and source-level warnings belong to the Weather +API adapter and its integration contract. -After readiness succeeds, the adapter obtains the other independent source -responses concurrently. It merges their normalized results in the established -source order, so provenance, warnings, and source-local failures remain -deterministic. Cancellation remains authoritative for every in-flight request. +## Application Use -The package wraps adapter construction failures, including an invalid Weather -API base URL, as weather-collection setup errors and fetch failures as -bundle-collection errors. It does not retry, persist, select reports, derive -facts, build modules, invoke Promptkit, or notify Distributor. +`internal/app` owns the `Collector` interface used by report workflows and +tests. Its default implementation delegates to `collect.Run`; callers may +substitute a collector at that boundary. Application orchestration owns +collection timing, reuse across a workflow, and the handling of nil collection +results. See [app orchestration internals](app-orchestration.md) for that +flow. -Fetch failures retain Weather API endpoint context but do not project upstream -response bodies into application-facing errors. Oversized response bodies fail -collection before source decoding. +## Verification -The required hourly product must contain one or more periods with usable time -bounds. An invalid hourly product fails collection before derivation begins. +Focused package tests cover a successful fetch and wrapping failures from +adapter construction and bundle retrieval: -## Application Composition - -`internal/app` owns the narrow `Collector` interface used by workflow tests; -the production implementation delegates to `collect.Run`. Generation, batch -execution, and explicit bundle fetching all use this boundary. Application -orchestration rejects a nil collector result or a nil bundle before report work -can continue. - -Single-report generation and a batch each collect once. A batch passes the same -normalized collection to planning and to every report it generates. Collection -failure prevents later workflow work for that request. - -## Boundaries And Invariants - -Collection owns adapter creation and retrieval of one normalized bundle. It -must not make report, period, batch, prompt, module, filesystem, or notification -decisions. - -- App-facing Weather API collection always passes through this package. -- The returned value is normalized source data, not facts or prompt input. -- Context cancellation is passed to the Weather API adapter. -- Errors retain whether setup or fetching failed. - -Focused tests are in `internal/collect/collect_test.go`; orchestration use is -also covered by `internal/app/app_test.go`. +```sh +go test ./internal/collect +``` diff --git a/docs/internal/forecast-derivation.md b/docs/internal/forecast-derivation.md index 3320212..e098351 100644 --- a/docs/internal/forecast-derivation.md +++ b/docs/internal/forecast-derivation.md @@ -2,74 +2,46 @@ `internal/forecast` deterministically selects and summarizes normalized forecast data. It has no transport, filesystem, CLI, subprocess, or report -registry dependency. Its summaries are consumed by -[fact contracts](facts.md) and later module builders. +registry dependency. The report-scoped caller is [fact +contracts](facts.md), which owns the choice of data required by each report. -## Period and daypart semantics +## Daily Derivation -Selections use `timeutil.Period` half-open overlap: a value is selected only -when both intervals share time. `BuildDailySummary` creates one local civil -day; `BuildPeriodDailySummaries` intersects every local civil day with the -requested period, preserving partial first and last days. +`BuildDailySummary` builds one summary for one local civil day. The facts +layer calls it for Daily, Today, and Tomorrow reports; it does not provide a +multi-day or arbitrary-period summary constructor. `timeutil.Period` supplies +the shared half-open overlap rule used while selecting source values. -`ResolveDayparts` converts each configured name, start clock, and end clock -into a local window. An end clock at or before its start clock wraps into the -next civil day. The daypart and timezone defaults are defined in the -[configuration reference](../config.md), not here. +`ResolveDayparts` turns configured local clock ranges into windows. A range +whose end is not after its start continues into the next civil day. The +available daypart and timezone settings are defined in the +[configuration reference](../config.md). -## Deterministic summaries +The summary keeps selected hourly and narrative values, the discussion, +source warnings and provenance, alert overlaps, and one summary for each +resolved daypart. Daypart summaries derive their measurements, conditions, +weather indicators, and precipitation timing from normalized forecast +periods. `BuildPrecipTiming` is also available to the facts layer for a +report's selected hourly periods. -`BuildDailySummary` requires an hourly run with at least one period. It adds -the selected narrative periods, discussion, alert overlaps, source provenance, -source warnings, and one `DaypartSummary` per resolved window. A daypart keeps -its selected hourly periods and derives temperature and apparent-temperature -ranges, timed precipitation and wind maxima, dominant and notable conditions, -and weather indicators. +## Boundaries And Failures -Hourly precipitation probabilities must be finite percentages from 0 through -100. Daily-summary construction rejects invalid values before they can affect -timed maxima or precipitation windows. +Daily-summary construction requires a bundle with hourly forecast data, +valid precipitation probabilities, and valid daypart definitions. Optional +normalized products remain absent when unavailable. Invalid alerts are ignored +while valid overlaps are selected for the relevant day or daypart window. -Indicators are deterministic checks over normalized values and condition text: -heat, cold, and wind use package-owned numeric cutoffs; snow, ice, fog, and -wind text are detected from the forecast description. `BuildPrecipTiming` -sorts periods, records the maximum and first precipitation, groups contiguous -periods at or above its package-owned probability threshold, and records -thunder mentions. -Ice detection uses the bounded condition vocabulary `ice`, `icy`, `freezing`, -and `sleet` as whole words. +Thresholds, text classification, unit normalization, and alert selection are +package implementation rules. Report identity, period selection, and the +resulting derived-fact shape are owned by [fact contracts](facts.md); external +source semantics are owned by [weather-data internals](weather-data.md). -Daypart temperature and apparent-temperature ranges are Fahrenheit values, and -timed wind maxima are mph values. When only metric source fields are present, -they are converted to those units before they are stored or evaluated against -indicator thresholds; populated US-customary fields take precedence. +## Verification -Alert overlap parsing supports the normalized alert payload's available timing -fields. Unparseable alerts and invalid intervals are ignored; valid overlaps -are clipped to the requested period and ordered by alert start time. -`DailySummary.AlertOverlaps` is limited to the local civil day, while each -daypart evaluates the full alert run against its complete window, including the -next-day portion of an overnight window. - -## Missing data and failures - -Empty selections yield empty summary fields rather than generated prose. -Direct daily or period-summary calls fail when their required bundle, valid -period, hourly data, or daypart definitions are invalid. A nil location uses -UTC when these APIs are called directly. Optional narrative, discussion, and -alerts remain absent when their normalized products are absent. - -Forecast thresholds used for brief indicators and precipitation timing are -implementation rules. - -## Verification and invariants - -Focused tests cover local civil days, clipped periods, daypart resolution, -summary metrics, precipitation-window threshold behavior, and alert overlap: +Focused `internal/forecast` tests exercise daily and overnight dayparts, +summary derivation, invalid precipitation data, precipitation timing, and +alert overlap handling. `internal/facts` tests cover the report-scoped caller: ```sh -go test ./internal/forecast ./internal/timeutil +go test ./internal/forecast ./internal/facts ``` - -The package preserves normalized inputs as inspectable structured values and -never decides report identity, delivery, or presentation wording. diff --git a/docs/internal/prompt-input.md b/docs/internal/prompt-input.md index ac1a7ca..a7b70dd 100644 --- a/docs/internal/prompt-input.md +++ b/docs/internal/prompt-input.md @@ -1,27 +1,35 @@ # Prompt Input Internals -`internal/promptinput` converts report metadata, an ordered module snapshot, and source warnings into the YAML `data_package` supplied inline to Promptkit. It owns the package schema, grouping, serialization, and validation; it does not choose an output destination, collect weather, execute a provider, or retain packages after a command ends. +`internal/promptinput` turns prepared report metadata and an ordered module +snapshot into the YAML data package passed to Promptkit. The externally visible +prompt and inline-input contract is owned by the [Promptkit integration +guide](../integrations/promptkit.md); preparation of the inputs is owned by +[prepared report internals](prepared-report.md). ## Package Construction -`Build` produces `weatherreporter.data_package.v4`. Its metadata projection comes from the prepared report identity and copies the run ID; report ID, variant, prompt ID, generation time, timezone, local current date, and valid period; ordered briefing stanzas; and prompt-safe source-warning summaries. Warning summaries include only source, code, severity, message, and completeness impact; raw transport and provenance fields such as endpoints never cross into the provider input. Prompt input contains no historical comparison section. +`Build` projects report identity, the report-local current date, source-warning +summaries, and each snapshot output's prompt-facing value into a package. It +does not expose source transport or provenance details. The module snapshot +defines stanza order and selects curated prompt values; the corresponding +module contracts are documented in [module internals](module.md) and [briefing +internals](briefing.md). -Briefing is a flat ordered set of stanza values. `Build` uses each output's `DataPackageValue`, so curated prompt exports take precedence and rich values are used only as a fallback. Prompt exports are selected by the [briefing registry](briefing.md), while the rich-versus-prompt contract is in [module internals](module.md). +`MarshalYAML` validates the package before serializing it. Serialization emits +the metadata stanza first, then groups the remaining recognized stanzas in the +package's fixed category order while preserving snapshot order within a +category. `Validate` enforces the supported schema version, required report +identity and period values, and a nonempty, complete ordered briefing. -## YAML Ordering And Validation +This package does not collect weather, choose an output destination, execute a +provider, or persist data packages. The application passes its in-memory YAML +to the Promptkit adapter as part of prepared report execution. -Serialization keeps `metadata` directly under `briefing`. Every other known stanza is placed in one category and emitted in category order while preserving its original module order: +## Verification -| Category | Current stanzas | -| --- | --- | -| `applicable_risk_products` | alert digest, SPC convective outlooks | -| `derived_summaries` | deterministic summaries, precipitation timing, outdoor windows, and planning values | -| `narrative_products` | narrative forecast, discussions, and weather story | -| `raw_data` | current conditions and hourly forecast | - -`Validate` requires the v4 schema version, report identity and period fields, and at least one ordered briefing stanza. `MarshalYAML` validates before serializing. Normal application execution passes marshalled YAML directly to Promptkit. - -Focused tests cover construction, curated exports, category ordering, serialization, and validation: +Focused tests cover package construction, report-local dates, validation, +curated snapshot exports, deterministic YAML grouping, and safe source-warning +projection: ```sh go test ./internal/promptinput diff --git a/docs/internal/report-registry.md b/docs/internal/report-registry.md index 861db4c..e3dfc5e 100644 --- a/docs/internal/report-registry.md +++ b/docs/internal/report-registry.md @@ -1,34 +1,37 @@ # Report Registry Internals -`internal/report` owns report identities, valid-period resolution, exact prompt identity and version, output names, default module composition, and Distributor path declarations. Public command syntax belongs in the [CLI reference](../cli.md); configuration aliases and overrides belong in the [configuration reference](../config.md). +`internal/report` owns the in-process registry of report identities and the +resolution of a report's valid period. Command names and configuration aliases +belong to the [CLI reference](../cli.md) and [configuration +reference](../config.md), respectively. -## Definitions And Resolution +## Registry And Resolution -Each `Definition` declares a stable ID and display name, prompt ID and version, template and generated-text schema IDs, valid-period resolver, default output name, Distributor path templates, module list, and fixed batch eligibility. `Resolved` combines a definition with one valid period and run identity. +`DefaultRegistry` supplies the maintained definitions. `Lookup` returns a +definition by its internal ID, while `Resolve` combines it with a request time, +location, and optional date to produce `Resolved`. The result carries the +definition, generation time, timezone, and resolved valid period; its metadata +and output-name helpers keep derived identity values consistent for callers. -| Report ID | Prompt version | Default profile | Period policy | Fixed batch flag | Default output | -| --- | --- | --- | --- | --- | --- | -| `daily` | `2.0.0` | `weather-balanced` | Explicit local civil day | Dynamic Daily inclusion is app-owned | `daily-YYYY-MM-DD.md` | -| `today` | `2.0.0` | `weather-balanced` | Selected or current local civil day | Morning | `today.md` | -| `tomorrow` | `2.0.0` | `weather-balanced` | Next local civil day | Evening | `tomorrow.md` | -| `hourly` | `2.0.0` | `weather-light` | Rolling six-hour interval | — | `hourly.md` | +Definitions carry the internal collaborators needed downstream: prompt and +template identity, module configuration, output naming, Distributor path +templates, and fixed batch eligibility. The external prompt contract is owned +by the [Promptkit integration guide](../integrations/promptkit.md), template +surface by the [report template guide](../templates.md), and published +Distributor paths by the [Distributor bundle guide](../integrations/distributor/pkg-bundle.md). -Daily derives its filename and run identity from the resolved valid-period start -in the effective timezone, so multiple Daily items have distinct destinations -and identifiers. Exact template fields and schema assets belong to [report -templates](../templates.md) and [generated-text internals](generatedtext.md). -Prompt assets own default profile selection; the registry stores no provider -setting. +`WithModuleOverrides` returns an independently cloned registry with replacement +module configuration for recognized report IDs. The application owns batch +planning and data-dependent inclusion; see [app orchestration +internals](app-orchestration.md). -## Collaborators And Boundaries +The registry never collects weather data, parses CLI flags, writes output, +executes Promptkit, or delivers a report. -`DefaultRegistry`, `Lookup`, `Resolve`, and report-name helpers prevent callers from duplicating report identity rules. Registry overrides clone a recognized definition and replace its module list. `DistributorPathTemplates` are consumed by app orchestration; their rendered external bundle-path contract is documented in the [Distributor bundle guide](../integrations/distributor/pkg-bundle.md). +## Verification -`morning` and `evening` are registry-owned batch names. Fixed flags declare Today and Tomorrow eligibility; app orchestration determines data-dependent Daily membership and the actual batch plan. - -The registry never collects weather data, parses CLI flags, writes output, executes Promptkit, or delivers a report. - -Focused tests cover definition completeness, command and alias lookup, period resolution, run IDs, output names, composition defaults, and override validation: +Focused tests protect retained report definitions, period resolution, Daily +run-ID disambiguation, and rejection of retired command or configuration names: ```sh go test ./internal/report