Document internal component boundaries

This commit is contained in:
2026-05-29 19:54:22 +00:00
parent f23af43013
commit 4f530b2b6a
9 changed files with 407 additions and 263 deletions

View File

@@ -0,0 +1,89 @@
# App Orchestration Internals
This document describes the implemented workflow coordinator in `internal/app`.
## Purpose
`internal/app` coordinates top-level use cases: generating one report, running
morning or evening batches, building inspectable briefing artifacts, fetching
weather bundles, and reading existing artifacts for inspection.
## Inputs And Outputs
Inputs:
- app request structs containing config, report or batch selection, clock time,
optional report date, optional Storm Report bounds, output paths, renderer
fakes, or state-store fakes
- resolved report definitions from `internal/report`
- forecast bundles from the Weather API adapter
- prior briefing snapshots from `internal/state`
Outputs:
- report results with briefing, data package, preflight, report, metadata,
prior snapshot, Recent Changes, and Scriptorium results
- batch summaries with per-report status and artifact paths
- inspection JSON values for reports, metadata, briefings, data packages, prior
snapshots, and source provenance
## Boundaries
- The package coordinates workflow order.
- It does not parse CLI flags, load YAML files directly, implement HTTP calls,
derive forecast facts, define report periods, compare Markdown, or construct
Scriptorium argv.
## Config Fields Used
- `weather_api.*` for Weather API client construction and briefing metadata
- `scriptorium.*` for renderer construction
- `workspace.*` for filesystem state
- `dayparts` for daily and outlook summarization
- `recent_change.*` for structured Recent Changes thresholds
## External Adapters Used
- `internal/adapters/weatherapi` for forecast bundle fetching
- `internal/adapters/scriptorium` for render preflight and report generation
- `internal/state` filesystem store for persisted artifacts
## State Or Manifest Behavior
Generation saves the briefing snapshot, data package, preflight result when
available, rendered report, and metadata. Metadata links all managed artifact
paths. Inspection workflows read existing state and do not fetch weather data or
invoke Scriptorium.
## Skip And Resume Behavior
There is no resume workflow. Batch generation continues remaining independent
reports after one report fails, then reports aggregate success and failure
counts.
## Failure Behavior
- Resolve errors stop the requested workflow before fetching weather data.
- Weather API or briefing errors stop that report before Scriptorium is called.
- Render preflight runs before Scriptorium report generation.
- If render preflight returns a result and an error, preflight JSON and metadata
are persisted before the error is returned.
- If Scriptorium report generation returns an error after writing output,
metadata and the managed report path remain inspectable.
- Batch failures are recorded per report and surfaced through aggregate batch
failure.
## Tests
Inspect:
- `internal/app/app_test.go`
- `internal/cli/root_test.go`
- `internal/state/filesystem_test.go`
## Invariants
- Report behavior is resolved through `internal/report`.
- Render preflight precedes Scriptorium report generation.
- Recent Changes are computed from structured briefing snapshots.
- Metadata links artifacts produced for a run.

View File

@@ -5,63 +5,58 @@ This document describes the implemented briefing package boundary.
## Purpose
`internal/briefing` builds structured report-specific briefing packages from
forecast summaries and report metadata. The package currently implements Daily
Today, Daily Tomorrow, 3-Day Outlook, Weekend Outlook, and Storm Report
briefing content.
resolved report metadata, forecast bundles, and derived forecast summaries.
Briefings are curated inputs for prompt data packages, not rendered report
prose.
## Inputs and Outputs
## Inputs And Outputs
Inputs:
- resolved report definition and valid period
- forecast bundle
- derived forecast summary or summaries
- resolved report definition, generation time, timezone, and valid period
- forecast bundle with source provenance and warnings
- derived daily or period summaries where required
- configured units and timezone
Output:
Outputs:
- `briefing.Package` JSON containing common metadata and report-specific
briefing content
- `briefing.Package` with common metadata and one report-specific content
object for Daily, 3-Day, Weekend, or Storm Report
- optional JSON file written by `briefing.Save`
## Boundaries
- Briefings are structured weather facts and context for later prompt input.
- This package does not fetch weather data, compare prior snapshots, build
`scriptorium` data packages, or render final report prose.
- This package selects and shapes weather facts for prompts.
- It does not fetch weather data, compare prior snapshots, build
`data_package` files, invoke Scriptorium, or write workflow metadata.
## Behavior
## Config Fields Used
- Common metadata includes schema version, RunID, report ID, variant, prompt ID,
generation time, units, timezone, valid period, source location, source
provenance, hashes, and source warnings.
- Daily content includes bottom-line inputs, daypart summaries, relevant alerts,
outdoor window inputs, narrative periods, discussion context, and weather
story context when available.
- Daily Tomorrow also includes planning inputs for morning readiness,
commute/school/workday concerns, and what may change overnight.
- 3-Day content includes one summary per local day or partial day, with overall
character, temperature range, precipitation, wind, risk, outdoor-window, and
alert inputs, plus broader discussion and weather-story context when
available.
- Weekend content uses the same daily outlook summaries and adds planning
inputs for best outdoor windows, worst weather windows, rain/storm timing,
comfort concerns, and confidence or uncertainty context.
- Storm content uses the explicit event window and includes event headline
inputs, hazards, most-likely scenario inputs, reasonable worst-case inputs,
confidence and uncertainty inputs, watch items, active alerts, relevant
hourly and narrative forecast periods, and available discussion or weather
story context.
- Briefing JSON is written atomically by `briefing.Save`.
The package receives configured units and timezone from the app layer. Daypart
configuration is consumed by `internal/forecast` before briefing builders run.
## External Adapters Used
None directly.
## State Or Manifest Behavior
`briefing.Save` writes briefing JSON atomically. Managed workspace placement is
owned by `internal/state`.
## Skip And Resume Behavior
None. Builders either return a complete briefing package or an error.
## Failure Behavior
- Daily briefing construction requires a Daily report definition and a derived
daily forecast summary.
- Daily briefing construction requires a Daily report definition and derived
daily summary.
- 3-Day briefing construction requires a 3-Day report definition and at least
one derived daily summary in the outlook period.
one derived summary.
- Weekend briefing construction requires a Weekend report definition and at
least one derived daily summary in the weekend period.
- Storm briefing construction requires a Storm Report definition and a forecast
least one derived summary.
- Storm briefing construction requires a Storm Report definition and forecast
bundle.
- Save failures include path and operation context.
@@ -74,11 +69,11 @@ Inspect:
- `internal/briefing/weekend_test.go`
- `internal/briefing/storm_test.go`
- `internal/app/app_test.go`
- `internal/cli/root_test.go`
## Invariants
- Weather facts come from normalized and derived source data.
- Briefing output remains JSON-inspectable.
- LLM prompt input packaging and `scriptorium` execution remain outside this
- Briefings contain structured weather facts and source context.
- Common metadata includes RunID, report ID, prompt ID, valid period, source
provenance, source hashes, and source warnings.
- LLM prompt input packaging and Scriptorium execution remain outside this
boundary.

View File

@@ -1,62 +1,61 @@
# Changes Internals
This document describes the implemented structured change comparison boundary.
This document describes structured Recent Changes comparison.
## Purpose
`internal/changes` compares current and prior structured briefing snapshots and
produces compact change records for prompt input data packages.
`internal/changes` compares current and prior briefing packages and emits
compact change records for prompt input data packages.
## Inputs and Outputs
## Inputs And Outputs
Inputs:
- prior briefing package
- current briefing package
- configured Recent Changes thresholds
- comparison thresholds from configuration
Output:
Outputs:
- ordered `changes.Change` records with type, message, previous value, and
current value where useful
- ordered `changes.Change` items with type, message, previous value, and current
value where useful
## Boundaries
- This package compares structured briefing data only.
- It does not read state directly, render Markdown, invoke `scriptorium`, or
compare generated report text.
- It does not read filesystem state, find prior snapshots, render Markdown,
invoke Scriptorium, or compare generated report text.
## Config Fields Used
The app maps these config fields into comparison thresholds:
The app maps these fields into comparison thresholds:
- `recent_change.temperature_degrees`
- `recent_change.precip_probability_points`
- `recent_change.wind_gust_miles_per_hour`
- `recent_change.precip_timing_shift_minutes`
## Behavior
## External Adapters Used
Daily, 3-Day, and Weekend comparison currently detect:
None.
- temperature changes crossing configured thresholds
- precipitation probability and timing changes
- alert additions and removals
- peak wind gust changes
- snow, ice, and thunder risk changes
## State Or Manifest Behavior
When no prior comparable snapshot exists, the app sends an empty Recent Changes
section in the data package. Daily Today and Daily Tomorrow are compatible for
same-valid-date comparison through the report registry. 3-Day Outlook compares
with prior 3-Day Outlook snapshots for the same valid local date. Weekend
Outlook compares with prior Weekend Outlook snapshots for the same weekend
window.
None directly. The app loads prior briefing snapshots through `internal/state`
before calling comparison functions.
## Skip And Resume Behavior
No resume behavior. When the app has no prior comparable snapshot, it sends an
empty Recent Changes list without calling a comparison function.
## Failure Behavior
Daily comparison requires both inputs to contain Daily briefing content. 3-Day
comparison requires both inputs to contain 3-Day briefing content. Weekend
comparison requires both inputs to contain Weekend briefing content.
- Daily comparison requires both inputs to contain Daily briefing content.
- 3-Day comparison requires both inputs to contain 3-Day briefing content.
- Weekend comparison requires both inputs to contain Weekend briefing content.
- Storm Report currently has no comparison implementation, so the app leaves
Recent Changes empty for Storm reports.
## Tests
@@ -70,5 +69,6 @@ Inspect:
## Invariants
- Recent Changes are based on structured snapshots, not Markdown report text.
- Comparison thresholds come from configuration.
- The comparison output remains compact enough for prompt input.
- Report compatibility is determined outside this package by report definitions
and state lookup.
- Output stays compact enough for prompt input.

View File

@@ -1,57 +1,66 @@
# Forecast Derivation Internals
This document describes the implemented deterministic forecast summarization
boundary.
This document describes deterministic forecast summarization in
`internal/forecast`.
## Purpose
`internal/forecast` converts a normalized forecast bundle into inspectable
daily and multi-day daypart summaries. These summaries are structured data for
later briefing builders; they are not rendered report text.
`internal/forecast` converts normalized bundle data into daily and period
summaries used by briefing builders.
## Inputs and Outputs
## Inputs And Outputs
Inputs:
- `forecast.Bundle`
- local date and timezone
- report period, for multi-day summaries
- configured daypart definitions with `HH:MM` start and end values
- local date or resolved report period
- timezone
- configured daypart definitions
Output:
Outputs:
- `forecast.DailySummary` with a civil-day period, daypart summaries, selected
narrative periods, alert overlaps, discussion context, source warnings, and
source provenance.
- `forecast.BuildPeriodDailySummaries` output with one clipped daily summary
for each local day or partial day in a report period.
- `forecast.DailySummary` for one local civil day
- one clipped daily summary per local day or partial day from
`BuildPeriodDailySummaries`
- daypart summaries with selected hourly periods, ranges, timed maximums,
conditions, indicators, and alert overlaps
## Boundaries
- This package groups and summarizes already-normalized forecast data.
- It does not fetch weather data, resolve report definitions, compare prior
snapshots, build prompt input packages, or call `scriptorium`.
- This package groups, selects, and summarizes already-normalized forecast
data.
- It does not perform HTTP calls, parse CLI flags, resolve report definitions,
compare prior snapshots, build prompt input packages, or invoke Scriptorium.
## Behavior
## Config Fields Used
- Daypart windows use half-open intervals.
- Overnight dayparts are supported when the end clock is not after the start
clock.
- Hourly forecast periods are selected by overlap with the daypart window.
- Each daypart computes temperature range, apparent-temperature range, maximum
precipitation probability, peak wind speed, peak wind gust, dominant
condition, notable conditions, and basic weather indicators.
- Alerts are selected by overlap with the daily period and each daypart.
- Narrative periods and discussion context are selected as broader source
context for later briefing builders.
- Multi-day period summaries clip the first and last local days to the resolved
report period before selecting hourly periods and alerts.
- `dayparts[].name`
- `dayparts[].start`
- `dayparts[].end`
Threshold constants for basic indicators live in forecast code rather than
configuration.
## External Adapters Used
None directly. Forecast data arrives through `forecast.Bundle`.
## State Or Manifest Behavior
None. Source warnings and provenance from the bundle are carried into summaries
for later metadata and briefing output.
## Skip And Resume Behavior
None. Missing optional source context can produce empty selections, but missing
required hourly data fails summarization.
## Failure Behavior
- Missing hourly forecast data returns an error.
- Invalid daypart definitions return actionable parse errors.
- Alert records without parseable RFC3339 start/end fields are skipped.
- A nil bundle or missing hourly forecast data returns an error.
- Invalid daypart definitions return parse errors with context.
- Alert records without parseable RFC3339 timing are skipped.
- Empty selected periods produce empty summaries rather than generated prose.
## Tests
@@ -62,7 +71,6 @@ Inspect:
## Invariants
- Weather facts come from normalized source data, not generated prose.
- Outputs remain JSON-inspectable.
- Forecast derivation remains independent of CLI, HTTP adapters, and report
registry behavior.
- Go owns report-period selection and meteorological summarization.
- Weather facts come from normalized source data.
- Outputs remain JSON-inspectable and independent of CLI, state, and adapters.

View File

@@ -1,54 +1,64 @@
# Prompt Input Internals
This document describes the implemented prompt input package boundary.
This document describes prompt input data package construction.
## Purpose
`internal/promptinput` converts a structured briefing package into the
`data_package` JSON file passed to `scriptorium` prompts.
`internal/promptinput` converts a structured briefing package and optional
Recent Changes into the `data_package` JSON passed to Scriptorium prompts.
## Inputs and Outputs
## Inputs And Outputs
Input:
Inputs:
- `briefing.Package` containing Daily-family, 3-Day Outlook, Weekend Outlook,
or Storm Report content
- `briefing.Package`
- optional `[]changes.Change`
Output:
Outputs:
- `promptinput.Package` JSON with report metadata, briefing content, source
warnings, RunID, and a Recent Changes section.
- `promptinput.Package` containing schema version, RunID, report metadata,
briefing content, Recent Changes, and source warnings
- optional JSON file written by `promptinput.Save`
## Boundaries
- This package owns the prompt input schema and required-field validation.
- It does not fetch weather data, compute forecast summaries, compare prior
snapshots, or invoke `scriptorium`.
- This package owns the prompt input schema and validation.
- It does not fetch weather data, derive forecast summaries, find prior
snapshots, compare changes, or invoke Scriptorium.
## Behavior
## Config Fields Used
- `promptinput.Build` copies report metadata from the briefing package.
- `promptinput.Validate` rejects missing or inconsistent required fields before
render preflight.
- `promptinput.Save` writes JSON atomically where practical.
- Recent Changes is present as an `items` list. It is empty when no prior
comparable snapshot exists or no meaningful changes are detected.
None directly. Config-derived values are already present in briefing metadata
before this package runs.
## External Adapters Used
None.
## State Or Manifest Behavior
`promptinput.Save` writes JSON atomically. Managed workspace paths are owned by
`internal/state`.
## Skip And Resume Behavior
None. Recent Changes is always present as an `items` list and may be empty.
## Failure Behavior
Validation errors name the missing or inconsistent field. Save failures include
the filesystem operation and path context.
Validation fails before render preflight when required top-level or briefing
metadata fields are missing or inconsistent, or when no report content is
present. Save failures include filesystem operation and path context.
## Tests
Inspect:
- `internal/promptinput/package_test.go`
- `internal/changes/daily_test.go`
- `internal/app/app_test.go`
## Invariants
- Prompt input data remains structured JSON.
- Scriptorium receives structured `data_package` JSON.
- Briefing metadata and top-level report metadata must agree.
- Recent Changes is not inferred from rendered report text.
- Recent Changes are not inferred from rendered report text.

View File

@@ -1,53 +1,59 @@
# Report Registry Internals
This document describes the implemented report identity and valid-period
boundary.
This document describes report identity, valid-period resolution, batch
membership, and comparison declarations in `internal/report`.
## Purpose
`internal/report` centralizes report IDs, prompt IDs, comparison strategies,
valid-period resolution, report metadata, and scheduled batch membership.
`internal/report` centralizes report definitions so report IDs, prompt IDs,
default output names, comparison strategies, and valid periods are declared in
one package.
## Inputs and Outputs
## Inputs And Outputs
Inputs:
- report ID or batch name
- generation time
- configured timezone
- timezone
- optional Daily date override
- optional manual storm start and end times
- optional Storm Report start and end times
Outputs:
- `report.Resolved` values with definition metadata and half-open valid periods
- `report.Metadata` values suitable for later persisted run metadata
- `report.Metadata` values used by briefing and persisted metadata builders
## Boundaries
- This package defines report identity and time coverage only.
- It does not fetch weather data, build briefings, compare snapshots, write
state, or call `scriptorium`.
state, parse CLI flags, or invoke Scriptorium.
## Behavior
## Config Fields Used
- Daily Today covers one configured local civil day.
- Daily Tomorrow covers the next configured local civil day.
- 3-Day Outlook covers generation time through local midnight after the second
following local civil day.
- Weekend Outlook covers Saturday 00:00 to Monday 00:00 Monday through
Thursday; Friday and Saturday cover the remaining weekend from Friday 18:00
or generation time, whichever is later.
- Manual Storm Report uses explicit start and end times.
- Morning batch resolves Daily Today and 3-Day Outlook, plus Weekend Outlook
except on Sunday.
- Evening batch resolves Daily Tomorrow.
The app supplies `weather_api.timezone` as a loaded `time.Location`. Report
output path copying uses default output names from report definitions.
## External Adapters Used
None.
## State Or Manifest Behavior
None directly. Resolved metadata contributes RunID, report ID, prompt ID,
generation time, timezone, and valid period to later briefing and state
metadata.
## Skip And Resume Behavior
No resume behavior. Morning batch resolution skips Weekend Outlook on Sunday.
## Failure Behavior
- Unknown report and batch names return actionable errors.
- Sunday Weekend Outlook resolution returns an error.
- Storm windows require start and end, with end after start.
- Unknown reports and batch names return actionable errors.
- Weekend Outlook resolution returns an error when resolved directly on Sunday.
- Storm Report resolution requires start and end, with end after start.
## Tests
@@ -55,9 +61,11 @@ Inspect:
- `internal/report/period_test.go`
- `internal/app/app_test.go`
- `internal/cli/root_test.go`
## Invariants
- Report selection goes through the registry.
- Valid periods are independent of rendered report text.
- Prompt IDs and comparison strategies are declared with report definitions.
- Daily Today and Daily Tomorrow both use `weather.daily_report`.
- Valid periods are half-open intervals independent of rendered report text.
- Comparison strategy is declared by report definition.

View File

@@ -1,59 +1,67 @@
# Scriptorium Adapter Internals
This document describes the implemented `scriptorium` subprocess adapter.
This document describes the subprocess adapter in
`internal/adapters/scriptorium`.
## Purpose
`internal/adapters/scriptorium` runs `scriptorium render` to preflight prompt
wiring and `scriptorium run` to generate report artifacts.
The adapter runs `scriptorium render` for prompt preflight and `scriptorium run`
for Markdown report generation while isolating subprocess details from domain
packages.
## Inputs and Outputs
## Inputs And Outputs
Input:
Inputs:
- prompt ID
- prompt input data package path
- report output path for `run`
- configured binary, config path, profile, timeout, and extra arguments
Output:
Outputs:
- captured stdout, with truncation tracking
- captured stderr, with truncation tracking
- argv used for execution
- captured stdout and stderr with truncation flags
- exit code
- full argv used for inspection
- report output path for `run`
## Boundaries
- This adapter owns `scriptorium` CLI flag construction and subprocess
execution.
- It does not choose report types, build prompt input, fetch weather data, or
decide workflow order.
- This adapter owns Scriptorium argv construction and subprocess execution.
- It does not choose report types, build prompt input, fetch weather data,
decide workflow order, or persist workflow metadata.
## Behavior
## Config Fields Used
The render invocation shape is:
- `scriptorium.binary`
- `scriptorium.config_path`
- `scriptorium.profile`
- `scriptorium.timeout`
- `scriptorium.extra_args`
```text
scriptorium render --prompt <prompt_id> --input data_package=<path> --format json
```
## External Adapters Used
The run invocation shape is:
- external `scriptorium` CLI
```text
scriptorium run --prompt <prompt_id> --input data_package=<path> --out <artifact_path>
```
See [Scriptorium integration](../integrations/scriptorium.md) for the external
CLI contract used by this project.
Configured `--config` and `--profile` values are added when present. Arguments
are passed directly as argv, not through a shell. Stdout and stderr are captured
separately. `SaveRenderResult` writes the captured result as JSON for inspection.
## State Or Manifest Behavior
`SaveRenderResult` can write render results atomically. The app and state store
own managed preflight paths and metadata links.
## Skip And Resume Behavior
None. Context cancellation and configured timeout stop subprocess execution.
## Failure Behavior
Nonzero render and run exits return both the captured result and an error
containing the exit code and stderr. Run exit code `2` is treated as an error
but may still produce a report artifact. Command execution respects context
cancellation and the configured timeout.
- Missing prompt ID, data package path, or run output path returns an error.
- Subprocess start or context errors are wrapped with operation context.
- Nonzero render and run exits return captured output plus an error containing
exit code and stderr.
- Captured stdout and stderr are size-limited and marked when truncated.
## Tests
@@ -65,7 +73,6 @@ Inspect:
## Invariants
- `scriptorium` details stay inside the adapter package.
- The input name for prompt packages is always `data_package`.
- Render preflight remains orchestration behavior; this adapter only exposes the
subprocess operations.
- No shell interpolation is used.
- The Scriptorium input name is `data_package`.
- Scriptorium-specific flags stay inside adapter and config boundaries.

View File

@@ -1,13 +1,13 @@
# State Internals
This document describes the implemented filesystem state boundary.
This document describes filesystem state in `internal/state`.
## Purpose
`internal/state` owns durable artifact paths, atomic JSON writes, metadata, and
prior comparable snapshot lookup.
`internal/state` owns managed artifact paths, atomic JSON writes, persisted
metadata, prior snapshot lookup, and read-only artifact inspection helpers.
## Inputs and Outputs
## Inputs And Outputs
Inputs:
@@ -15,26 +15,27 @@ Inputs:
- resolved report definition and valid period
- briefing package
- prompt input data package
- `scriptorium render` result
- rendered report path preparation
- Scriptorium render result
- rendered report path preparation request
- RunID for inspection lookups
Outputs:
- briefing snapshot JSON
- prompt input data package JSON
- render preflight JSON
- Markdown report path
- metadata JSON
- prior comparable snapshot metadata when available
- prior briefing package when loaded by path
- briefing snapshot JSON path
- prompt input data package JSON path
- render preflight JSON path
- managed Markdown report path
- metadata JSON path
- prior comparable snapshot metadata
- loaded briefing or data package
- recent report records for inspection
- metadata and data package lookup by RunID
## Boundaries
- This package owns managed workspace layout and narrow path validation.
- It does not fetch weather data, derive forecasts, build prompt inputs, invoke
`scriptorium`, or compare briefing contents.
- This package owns managed workspace layout, path validation, filesystem
writes, and metadata reads.
- It does not fetch weather data, derive forecasts, build prompt input content,
compare briefing contents, invoke Scriptorium, or parse CLI flags.
## Config Fields Used
@@ -47,25 +48,35 @@ Outputs:
Workspace subdirectories must be relative paths that stay under
`workspace.root`.
## State Behavior
## External Adapters Used
Managed artifact names use RunID, which is generated from report generation time
and report ID. Metadata is stored beside briefing snapshots by report group and
valid local date. Prior snapshot lookup reads metadata for the same valid local
date and returns the latest earlier compatible run. Daily Today and Daily
Tomorrow are compatible with each other; 3-Day Outlook is compatible with prior
3-Day Outlook snapshots; Weekend Outlook is compatible with prior Weekend
Outlook snapshots for the same weekend window. The store can load a briefing
snapshot by path for structured comparison. The store can list metadata-backed
report records and load metadata or data packages by RunID for inspection. The
store prepares the managed Markdown report path before `scriptorium run` writes
it.
- local filesystem
## State Or Manifest Behavior
Managed paths are grouped by report family and valid-period start date for JSON
artifacts. Reports are written under the report group. Metadata is stored beside
briefing snapshots and links briefing, data package, preflight, and report
paths. Report listing walks metadata files under the snapshots directory.
Prior snapshot lookup reads metadata and selects the latest earlier compatible
snapshot. Daily Today and Daily Tomorrow are compatible with each other for the
same valid local date. 3-Day Outlook compares with prior 3-Day snapshots for
the same valid local date. Weekend Outlook compares with prior Weekend snapshots
for the same weekend window. Storm Report currently has no prior lookup.
## Skip And Resume Behavior
There is no resume workflow. Missing metadata directories return no inspection
records or no prior snapshot rather than creating state.
## Failure Behavior
Writes are atomic where practical: JSON is written to a temporary file in the
target directory and then renamed into place. Invalid workspace paths and
missing required metadata fields produce actionable errors.
- Invalid workspace paths return validation errors.
- Missing required metadata fields prevent metadata writes.
- JSON writes use a temporary file followed by rename where practical.
- Read and decode failures include path context.
- Unknown RunIDs produce an actionable lookup error.
## Tests
@@ -77,5 +88,5 @@ Inspect:
## Invariants
- Managed paths stay under the configured workspace root.
- Metadata links the artifacts produced for a run.
- Metadata links artifacts produced for a run.
- Prior lookup is based on structured metadata, not rendered report text.

View File

@@ -1,59 +1,74 @@
# Weather Data Internals
This document describes the implemented weather data ingestion boundary.
This document describes Weather API ingestion into `forecast.Bundle`.
## Purpose
`internal/adapters/weatherapi` fetches normalized weather data from one
configured weather API endpoint and assembles a `forecast.Bundle`.
configured Weather API endpoint and assembles the bundle consumed by forecast
derivation and briefing builders.
## Inputs and Outputs
## Inputs And Outputs
Input:
Inputs:
- `config.Config` with `weather_api.base_url`, `format`, `units`, `timezone`,
`precision`, timeout, and missing-source policy.
- `config.Config` with Weather API URL, timeout, format, units, timezone,
precision, and missing-source policy
- HTTP responses using the Weather API `data` envelope
Output:
Outputs:
- `forecast.Bundle` containing observation, current conditions, hourly forecast,
narrative forecast, alerts, discussion, stub source slots, provenance, and
source warnings.
- `forecast.Bundle` with observation, current conditions, hourly forecast,
narrative forecast, active alerts, discussion, source records, and source
warnings
- stub source records for daily forecast and weather story source slots
- optional saved bundle JSON through app fetch helpers
## Boundaries
- The adapter performs HTTP calls and decoding only.
- Forecast derivation, daypart grouping, report periods, report rendering, and
`scriptorium` execution are outside this boundary.
- Hourly forecast data is required. Other missing or malformed source sections
use the configured missing-source policy.
- The adapter owns HTTP calls, response-envelope handling, source hashing, and
decoding into internal bundle types.
- It does not derive dayparts, resolve report periods, build briefings, compare
snapshots, write report state, or invoke Scriptorium.
## External Adapter
## Config Fields Used
The adapter calls:
- `weather_api.base_url`
- `weather_api.timeout`
- `weather_api.format`
- `weather_api.units`
- `weather_api.timezone`
- `weather_api.precision`
- `missing_source.default`
- `missing_source.sources`
- `/observations`
- `/conditions/current`
- `/forecast/hourly`
- `/forecast/narrative`
- `/alerts/active`
- `/discussion`
## External Adapters Used
Forecast routes use the full-product endpoints, not day-slice endpoints.
- Weather API HTTP service
## State
See [Weather API integration](../integrations/weatherapi.md) for the external
contract used by this project.
`app.FetchAndSaveBundle` can save an inspectable bundle JSON file using an
atomic rename. No report state, snapshots, or prompt input packages are written
yet.
## State Or Manifest Behavior
The adapter records source name, endpoint, query, fetch time, source timestamps
when available, SHA-256 hash over compact raw `data` JSON, missing status, and
source warnings. `app.FetchAndSaveBundle` can write bundle JSON atomically for
inspection.
## Skip And Resume Behavior
No resume behavior. Optional missing or malformed sources may be omitted,
warned, or treated as errors according to missing-source policy. Hourly forecast
data is required and cannot be skipped.
## Failure Behavior
- HTTP and envelope decode failures return actionable errors with endpoint
context.
- Missing hourly data fails the fetch.
- Missing or malformed optional sources follow `error`, `warn`, or `none`.
- Source identity uses SHA-256 over compacted raw `data` JSON.
- Missing or invalid `weather_api.base_url` prevents client construction.
- HTTP errors, response read failures, and envelope decode failures include
endpoint context.
- Missing hourly data or hourly forecasts with no periods fail bundle fetch.
- Optional and stub sources follow missing-source policy.
## Tests
@@ -65,5 +80,6 @@ Inspect:
## Invariants
- Weather facts come from normalized source data.
- External API details stay inside `internal/adapters/weatherapi`.
- Source provenance and warnings remain inspectable for later briefing builders.
- Full hourly and narrative products are fetched; Go owns report-period
selection.
- Source provenance and warnings remain inspectable downstream.