Reconcile internal implementation guides

This commit is contained in:
2026-08-13 04:25:40 +00:00
parent b985c5faac
commit 88fde0df7f
4 changed files with 103 additions and 143 deletions

View File

@@ -1,59 +1,36 @@
# Collection Internals # 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 normalized Weather API bundle. The external HTTP contract belongs in the
[Weather API integration guide](../integrations/weatherapi.md); normalized data [Weather API integration guide](../integrations/weatherapi.md); normalized
semantics belong in [weather-data internals](weather-data.md). source values belong in [weather-data internals](weather-data.md).
## Contract ## Contract
`Run` accepts a `context.Context` and a `Request` containing effective `Run` receives a context and effective configuration in `Request`. It creates
`config.Config`. It constructs the Weather API adapter from that configuration, the Weather API adapter, calls `FetchBundle`, and returns the adapter's
calls `FetchBundle`, and returns `Result{Bundle: *weatherdata.Bundle}`. 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 The package neither chooses reports nor derives facts, builds modules, invokes
that normalized source; collection does not trigger a second identical current Promptkit, writes files, or sends notifications. Request scheduling, endpoint
conditions request. 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 ## Application Use
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.
The package wraps adapter construction failures, including an invalid Weather `internal/app` owns the `Collector` interface used by report workflows and
API base URL, as weather-collection setup errors and fetch failures as tests. Its default implementation delegates to `collect.Run`; callers may
bundle-collection errors. It does not retry, persist, select reports, derive substitute a collector at that boundary. Application orchestration owns
facts, build modules, invoke Promptkit, or notify Distributor. 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 ## Verification
response bodies into application-facing errors. Oversized response bodies fail
collection before source decoding.
The required hourly product must contain one or more periods with usable time Focused package tests cover a successful fetch and wrapping failures from
bounds. An invalid hourly product fails collection before derivation begins. adapter construction and bundle retrieval:
## Application Composition ```sh
go test ./internal/collect
`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`.

View File

@@ -2,74 +2,46 @@
`internal/forecast` deterministically selects and summarizes normalized `internal/forecast` deterministically selects and summarizes normalized
forecast data. It has no transport, filesystem, CLI, subprocess, or report forecast data. It has no transport, filesystem, CLI, subprocess, or report
registry dependency. Its summaries are consumed by registry dependency. The report-scoped caller is [fact
[fact contracts](facts.md) and later module builders. 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 `BuildDailySummary` builds one summary for one local civil day. The facts
when both intervals share time. `BuildDailySummary` creates one local civil layer calls it for Daily, Today, and Tomorrow reports; it does not provide a
day; `BuildPeriodDailySummaries` intersects every local civil day with the multi-day or arbitrary-period summary constructor. `timeutil.Period` supplies
requested period, preserving partial first and last days. the shared half-open overlap rule used while selecting source values.
`ResolveDayparts` converts each configured name, start clock, and end clock `ResolveDayparts` turns configured local clock ranges into windows. A range
into a local window. An end clock at or before its start clock wraps into the whose end is not after its start continues into the next civil day. The
next civil day. The daypart and timezone defaults are defined in the available daypart and timezone settings are defined in the
[configuration reference](../config.md), not here. [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 ## Boundaries And Failures
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.
Hourly precipitation probabilities must be finite percentages from 0 through Daily-summary construction requires a bundle with hourly forecast data,
100. Daily-summary construction rejects invalid values before they can affect valid precipitation probabilities, and valid daypart definitions. Optional
timed maxima or precipitation windows. 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: Thresholds, text classification, unit normalization, and alert selection are
heat, cold, and wind use package-owned numeric cutoffs; snow, ice, fog, and package implementation rules. Report identity, period selection, and the
wind text are detected from the forecast description. `BuildPrecipTiming` resulting derived-fact shape are owned by [fact contracts](facts.md); external
sorts periods, records the maximum and first precipitation, groups contiguous source semantics are owned by [weather-data internals](weather-data.md).
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.
Daypart temperature and apparent-temperature ranges are Fahrenheit values, and ## Verification
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.
Alert overlap parsing supports the normalized alert payload's available timing Focused `internal/forecast` tests exercise daily and overnight dayparts,
fields. Unparseable alerts and invalid intervals are ignored; valid overlaps summary derivation, invalid precipitation data, precipitation timing, and
are clipped to the requested period and ordered by alert start time. alert overlap handling. `internal/facts` tests cover the report-scoped caller:
`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:
```sh ```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.

View File

@@ -1,27 +1,35 @@
# Prompt Input Internals # 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 ## 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 | Focused tests cover package construction, report-local dates, validation,
| --- | --- | curated snapshot exports, deterministic YAML grouping, and safe source-warning
| `applicable_risk_products` | alert digest, SPC convective outlooks | projection:
| `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:
```sh ```sh
go test ./internal/promptinput go test ./internal/promptinput

View File

@@ -1,34 +1,37 @@
# Report Registry Internals # 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 | Definitions carry the internal collaborators needed downstream: prompt and
| --- | --- | --- | --- | --- | --- | template identity, module configuration, output naming, Distributor path
| `daily` | `2.0.0` | `weather-balanced` | Explicit local civil day | Dynamic Daily inclusion is app-owned | `daily-YYYY-MM-DD.md` | templates, and fixed batch eligibility. The external prompt contract is owned
| `today` | `2.0.0` | `weather-balanced` | Selected or current local civil day | Morning | `today.md` | by the [Promptkit integration guide](../integrations/promptkit.md), template
| `tomorrow` | `2.0.0` | `weather-balanced` | Next local civil day | Evening | `tomorrow.md` | surface by the [report template guide](../templates.md), and published
| `hourly` | `2.0.0` | `weather-light` | Rolling six-hour interval | — | `hourly.md` | 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 `WithModuleOverrides` returns an independently cloned registry with replacement
in the effective timezone, so multiple Daily items have distinct destinations module configuration for recognized report IDs. The application owns batch
and identifiers. Exact template fields and schema assets belong to [report planning and data-dependent inclusion; see [app orchestration
templates](../templates.md) and [generated-text internals](generatedtext.md). internals](app-orchestration.md).
Prompt assets own default profile selection; the registry stores no provider
setting.
## 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. Focused tests protect retained report definitions, period resolution, Daily
run-ID disambiguation, and rejection of retired command or configuration names:
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:
```sh ```sh
go test ./internal/report go test ./internal/report