diff --git a/docs/internal/app-orchestration.md b/docs/internal/app-orchestration.md new file mode 100644 index 0000000..e004fb8 --- /dev/null +++ b/docs/internal/app-orchestration.md @@ -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. diff --git a/docs/internal/briefing.md b/docs/internal/briefing.md index a06d58e..7a95765 100644 --- a/docs/internal/briefing.md +++ b/docs/internal/briefing.md @@ -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. diff --git a/docs/internal/changes.md b/docs/internal/changes.md index 333bd86..c5644c7 100644 --- a/docs/internal/changes.md +++ b/docs/internal/changes.md @@ -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. diff --git a/docs/internal/forecast-derivation.md b/docs/internal/forecast-derivation.md index ae49553..fe8a2dc 100644 --- a/docs/internal/forecast-derivation.md +++ b/docs/internal/forecast-derivation.md @@ -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. diff --git a/docs/internal/prompt-input.md b/docs/internal/prompt-input.md index 3fe5499..18f128a 100644 --- a/docs/internal/prompt-input.md +++ b/docs/internal/prompt-input.md @@ -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. diff --git a/docs/internal/report-registry.md b/docs/internal/report-registry.md index eebfa32..e3fd757 100644 --- a/docs/internal/report-registry.md +++ b/docs/internal/report-registry.md @@ -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. diff --git a/docs/internal/scriptorium-adapter.md b/docs/internal/scriptorium-adapter.md index 52f9b65..293e856 100644 --- a/docs/internal/scriptorium-adapter.md +++ b/docs/internal/scriptorium-adapter.md @@ -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 --input data_package= --format json -``` +## External Adapters Used -The run invocation shape is: +- external `scriptorium` CLI -```text -scriptorium run --prompt --input data_package= --out -``` +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. diff --git a/docs/internal/state.md b/docs/internal/state.md index ebbb9c2..67ab02e 100644 --- a/docs/internal/state.md +++ b/docs/internal/state.md @@ -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. diff --git a/docs/internal/weather-data.md b/docs/internal/weather-data.md index 7a9d85c..ada9546 100644 --- a/docs/internal/weather-data.md +++ b/docs/internal/weather-data.md @@ -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.