Document stateless output operations

This commit is contained in:
2026-08-01 20:11:57 +00:00
parent 97215ddb9b
commit bd34ec57f8
8 changed files with 183 additions and 322 deletions

View File

@@ -1,19 +1,22 @@
# weatherreporter # weatherreporter
Weatherreporter is a Go CLI that turns normalized weather data into managed, Weatherreporter is a Go CLI that turns normalized weather data into
human-facing Markdown reports. human-facing Markdown reports.
It provides repeatable reports with inspectable local artifacts, so operators It produces a Markdown report at an operator-owned destination and can upload
can review what was collected and generated for every run. the completed output through Distributor.
## Quickstart ## Quickstart
```sh ```sh
weatherreporter generate today --out ./today.md weatherreporter generate today
``` ```
Configure a Weather API endpoint first; see the Configure a Weather API endpoint first; see the
[configuration reference](docs/config.md). [configuration reference](docs/config.md). The report is written to
`today.md` in the current directory; use `--out` to choose another destination.
See the [CLI reference](docs/cli.md) and [operations guide](docs/operations.md)
for command and operating details.
## Documentation ## Documentation

View File

@@ -1,17 +1,17 @@
# Weatherreporter CLI # Weatherreporter CLI
`weatherreporter` generates weather reports, runs report batches, and inspects `weatherreporter` generates Markdown weather reports and runs report batches.
artifacts already stored in its workspace. It has no command for inspecting prior runs or application-owned state.
## Shortest Useful Command ## Shortest Useful Command
```sh ```sh
weatherreporter generate today --out ./today.md weatherreporter generate today
``` ```
The command uses the configured Weather API and writes an extra Markdown copy The command uses the configured Weather API and writes an atomically replaced
at `./today.md`. See the [configuration reference](config.md) to supply the `today.md` in the current directory. See the [configuration reference](config.md)
required Weather API endpoint. to supply the required Weather API endpoint.
## Commands And Usage ## Commands And Usage
@@ -24,12 +24,6 @@ weatherreporter generate tomorrow [--config PATH] [--units VALUE] [--tz NAME] [-
weatherreporter generate hourly [--config PATH] [--units VALUE] [--tz NAME] [--out PATH] [--llm-debug-dir PATH] [--quiet] weatherreporter generate hourly [--config PATH] [--units VALUE] [--tz NAME] [--out PATH] [--llm-debug-dir PATH] [--quiet]
weatherreporter run morning [--config PATH] [--units VALUE] [--tz NAME] [--out-dir PATH] [--llm-debug-dir PATH] [--quiet] weatherreporter run morning [--config PATH] [--units VALUE] [--tz NAME] [--out-dir PATH] [--llm-debug-dir PATH] [--quiet]
weatherreporter run evening [--config PATH] [--units VALUE] [--tz NAME] [--out-dir PATH] [--llm-debug-dir PATH] [--quiet] weatherreporter run evening [--config PATH] [--units VALUE] [--tz NAME] [--out-dir PATH] [--llm-debug-dir PATH] [--quiet]
weatherreporter inspect reports [--config PATH] [--limit N]
weatherreporter inspect metadata [--config PATH] RUN_ID
weatherreporter inspect modules [--config PATH] RUN_ID
weatherreporter inspect data-package [--config PATH] RUN_ID
weatherreporter inspect prior [--config PATH] RUN_ID
weatherreporter inspect sources [--config PATH] RUN_ID
``` ```
`weatherreporter --version` prints the version embedded in the executable. `weatherreporter --version` prints the version embedded in the executable.
@@ -38,69 +32,78 @@ builds report `development`.
| Command | Contract | | Command | Contract |
| --- | --- | | --- | --- |
| `generate daily` | Requires `--date YYYY-MM-DD`; the date is interpreted in the effective report timezone. | | `generate daily` | Requires `--date YYYY-MM-DD`; the date is interpreted in the effective report timezone. Its default filename is `daily-YYYY-MM-DD.md`. |
| `generate today` | Accepts an optional `--date YYYY-MM-DD`; without it, the current local date in the effective report timezone is used. | | `generate today` | Accepts an optional `--date YYYY-MM-DD`; without it, the current local date in the effective report timezone is used. Its default filename is `today.md`. |
| `generate tomorrow` | Uses the next local civil day and accepts the common generate flags. | | `generate tomorrow` | Uses the next local civil day and writes `tomorrow.md` by default. |
| `generate hourly` | Covers the next six hours in the effective report timezone. It does not accept `--date`, `--hours`, or `--duration`. | | `generate hourly` | Covers the next six hours in the effective report timezone and writes `hourly.md` by default. It does not accept `--date`, `--hours`, or `--duration`. |
| `run morning` and `run evening` | Run their defined report batches. `--out-dir` writes extra Markdown copies; `--out` is not accepted. | | `run morning` and `run evening` | Run their defined report batches and write each selected report beneath the current directory unless `--out-dir` selects another directory. `--out` is not accepted. |
`generate` accepts the four report command names shown above. `run` accepts `generate` accepts the four report command names shown above. `run` accepts
only `morning` and `evening`. Batch membership, workspace artifacts, and only `morning` and `evening`. Batch membership and notification ordering are
notification sequencing are described in the [operations guide](operations.md). described in the [operations guide](operations.md).
## Output, Errors, And Quiet Mode ## Output, Errors, And Quiet Mode
For `generate`, the default output is the report's filename in the current
directory. `--out PATH` selects one output file instead. A relative path is
resolved from the current directory; an absolute path is used as given. For a
batch, the equivalent default is the current directory and `--out-dir PATH`
selects its output directory. Successful summaries always report the resulting
absolute `outputPath` values.
Outputs are written atomically. A generation, rendering, write, or cancellation
failure before publication leaves an existing destination unchanged. A
notification failure occurs after publication, so the newly written output
remains available.
Action commands (`generate` and `run`) write a JSON summary to stdout unless Action commands (`generate` and `run`) write a JSON summary to stdout unless
`--quiet` is set. `run` also writes compact per-report and batch status lines `--quiet` is set. `run` also writes compact per-report and batch status lines
to stderr. A pre-run error, such as an invalid flag, missing required argument, to stderr. A pre-run error, such as an invalid flag, missing required argument,
or configuration-load failure, produces no partial JSON summary. When an action or configuration-load failure, produces no partial JSON summary. When an
fails after it has produced a result, its summary has `"status": "failed"` and action fails after it has produced a result, its summary has `"status": "failed"`
an `error` field. and an `error` field.
`--quiet` is supported by action commands only. It suppresses action summaries `--quiet` is supported by action commands only. It suppresses action summaries
and routine batch status output; it does not suppress command errors. and routine batch status output; it does not suppress command errors.
Inspection commands always write their requested JSON value to stdout and do
not accept `--quiet`.
### Generate Summary ### Generate Summary
A generate summary always identifies the command, report, run, generation A generate summary identifies the command, report, run, generation time, valid
time, valid period, and status: period, prompt version, timezone, and status. Successful output has an absolute
`outputPath`:
```json ```json
{ {
"command": "generate", "command": "generate",
"reportId": "today", "reportId": "today",
"reportName": "Today Report",
"promptId": "weather.today_generated_text", "promptId": "weather.today_generated_text",
"promptVersion": "2.0.0",
"runId": "20260529T120000.000000000Z_today", "runId": "20260529T120000.000000000Z_today",
"status": "succeeded", "status": "succeeded",
"generatedAt": "2026-05-29T12:00:00Z", "timezone": "America/Chicago",
"validPeriod": { "outputPath": "/srv/weather/today.md"
"start": "2026-05-29T00:00:00-05:00",
"end": "2026-05-30T00:00:00-05:00"
}
} }
``` ```
When available, the summary also includes `reportPath`, `metadataPath`, When available, the summary also includes the effective `profileId`,
`dataPackagePath`, `preparationPath`, `executionPath`, `generatedTextRawPath`, `backendId`, `modelName`, `sourceWarnings`, `validationStatus`, requested
`generatedTextPath`, `renderContextPath`, and `llmDebugPath`. `outputPath` is included only `llmDebugPath`, and compact Distributor `notification` result. It does not
when `--out` wrote an extra copy. Distributor notification, when attempted, include historical or transient artifact paths such as metadata, prompt input,
adds `notificationPath` and may add a compact `notification` object. raw generated text, render context, or notification receipts.
### Run Summary And Stderr ### Run Summary And Stderr
A run summary contains `command`, `batch`, `status`, `startedAt`, `finishedAt`, A run summary contains `command`, `batch`, `status`, `startedAt`, `finishedAt`,
`total`, `succeeded`, `failed`, and a `reports` array. It may also contain a `total`, `succeeded`, `failed`, and a `reports` array. Each report item includes
top-level `notification` object and `error`. Batch status is `failed` if any its identity, status, effective profile and model details when available,
report or the batch notification fails. source warnings, validation status, and absolute `outputPath` after publication.
The top-level summary may also contain a batch `notification` object and
`error`. Batch status is `failed` if any report or the batch notification fails.
Without `--quiet`, batch status lines use this form: Without `--quiet`, batch status lines use this form:
```text ```text
report=today status=succeeded output="reports/today.md" report=today status=succeeded output="/srv/weather/reports/today.md"
batch=morning total=2 succeeded=2 failed=0 batch=morning total=2 succeeded=2 failed=0
``` ```
@@ -112,12 +115,11 @@ batch=morning total=2 succeeded=2 failed=0
| `--config PATH` | all commands | Load `PATH` instead of `/usr/local/etc/weatherreporter/config.yml`. | | `--config PATH` | all commands | Load `PATH` instead of `/usr/local/etc/weatherreporter/config.yml`. |
| `--units VALUE` | `generate`, `run` | Override `weather_api.units` for this command. | | `--units VALUE` | `generate`, `run` | Override `weather_api.units` for this command. |
| `--tz NAME` | `generate`, `run` | Override `weather_api.timezone` for this command. | | `--tz NAME` | `generate`, `run` | Override `weather_api.timezone` for this command. |
| `--out PATH` | every `generate` command | Write an extra Markdown report copy. | | `--out PATH` | every `generate` command | Write the report to this file instead of its current-directory default. |
| `--llm-debug-dir PATH` | every `generate` and `run` command | Write requested sensitive prompt diagnostics outside the managed workspace. The path must be absolute. | | `--llm-debug-dir PATH` | every `generate` and `run` command | Write requested sensitive prompt diagnostics under this absolute path. |
| `--out-dir PATH` | `run morning`, `run evening` | Write extra Markdown report copies in `PATH`. | | `--out-dir PATH` | `run morning`, `run evening` | Write batch reports beneath this directory instead of the current directory. |
| `--quiet` | `generate`, `run` | Suppress action summaries and routine batch status output. | | `--quiet` | `generate`, `run` | Suppress action summaries and routine batch status output. |
| `--date YYYY-MM-DD` | `generate daily`, `generate today` | Required for Daily; optional for Today. | | `--date YYYY-MM-DD` | `generate daily`, `generate today` | Required for Daily; optional for Today. |
| `--limit N` | `inspect reports` | Maximum runs to list. Defaults to `20`; `0` means no limit. |
Distributor notification is configured through `notify.distributor`; there are Distributor notification is configured through `notify.distributor`; there are
no Distributor-specific CLI flags. See the [configuration reference](config.md). no Distributor-specific CLI flags. See the [configuration reference](config.md).
@@ -125,33 +127,9 @@ no Distributor-specific CLI flags. See the [configuration reference](config.md).
## Invocation Examples ## Invocation Examples
```sh ```sh
weatherreporter generate daily --date 2026-05-29 --out ./daily.md weatherreporter generate daily --date 2026-05-29
weatherreporter generate today --date 2026-05-29 --out ./today.md weatherreporter generate today --out ./reports/today.md
weatherreporter generate hourly --out ./hourly.md weatherreporter generate hourly --out /srv/weather/hourly.md
weatherreporter generate today --llm-debug-dir /var/tmp/weatherreporter-debug weatherreporter generate today --llm-debug-dir /var/tmp/weatherreporter-debug
weatherreporter run morning --out-dir ./reports --llm-debug-dir /var/tmp/weatherreporter-debug weatherreporter run morning --out-dir ./reports --llm-debug-dir /var/tmp/weatherreporter-debug
``` ```
## Inspection Commands
```sh
weatherreporter inspect reports --limit 10
weatherreporter inspect metadata 20260529T100000.000000000Z_today
weatherreporter inspect modules 20260529T100000.000000000Z_today
weatherreporter inspect data-package 20260529T100000.000000000Z_today
weatherreporter inspect prior 20260529T100000.000000000Z_today
weatherreporter inspect sources 20260529T100000.000000000Z_today
```
| Command | JSON returned |
| --- | --- |
| `inspect reports` | Recent generated runs, including artifact paths and source-warning counts. |
| `inspect metadata RUN_ID` | Persisted metadata for the run. |
| `inspect modules RUN_ID` | The run's persisted ordered module snapshot. |
| `inspect data-package RUN_ID` | The run's persisted prompt data package. |
| `inspect prior RUN_ID` | Prior comparable snapshot metadata, or `null` when none exists. |
| `inspect sources RUN_ID` | Source provenance and source warnings without full weather payloads. |
Inspection is read-only: it does not collect weather data or invoke Promptkit.
See the [operations guide](operations.md) for artifact lifecycle
and recovery.

View File

@@ -13,8 +13,8 @@ explicit `--config PATH` must exist. Values are applied in this order:
2. the configuration file, when present; and 2. the configuration file, when present; and
3. the `--units` and `--tz` command-line overrides. 3. the `--units` and `--tz` command-line overrides.
Environment variables do not override configuration fields. Output flags write Environment variables do not override configuration fields. Output flags select
extra report copies for a command and do not change configuration. operator-owned destinations for one command and do not change configuration.
## Maintained Examples ## Maintained Examples
@@ -129,7 +129,7 @@ The default paths are:
| `tomorrow` | `daily/{valid_start_date}/{run_id}.md`, `daily/{valid_start_date}/index.md`, `tomorrow/index.md` | | `tomorrow` | `daily/{valid_start_date}/{run_id}.md`, `daily/{valid_start_date}/index.md`, `tomorrow/index.md` |
See the [operations guide](operations.md) for notification timing, uploaded See the [operations guide](operations.md) for notification timing, uploaded
artifact selection, and failure handling. output selection, and failure handling.
### `missing_source` ### `missing_source`
@@ -160,7 +160,7 @@ individual `generate` or `run` command when explicitly needed.
`profile` selects an ID; `profile_file` and `profile_dir` supply definitions. `profile` selects an ID; `profile_file` and `profile_dir` supply definitions.
They are separate decisions. An explicit `profile` applies to every selected They are separate decisions. An explicit `profile` applies to every selected
report. Otherwise Hourly selects `weather-light`, while Daily, Today, and report. Otherwise Hourly selects `weather-light`, while Daily, Today, and
Tomorrow select `weather-balanced` through their exact `1.1.0` prompt Tomorrow select `weather-balanced` through their exact `2.0.0` prompt
definitions. definitions.
Promptkit resolves a selected profile definition from a test or embedding Promptkit resolves a selected profile definition from a test or embedding
@@ -179,21 +179,6 @@ model before use. An alternative profile may use `backend: local`; in that
case `promptkit.local.endpoint` supplies the conventional local backend case `promptkit.local.endpoint` supplies the conventional local backend
endpoint. endpoint.
### `workspace`
| Field | Default |
| --- | --- |
| `root` | `workspace` |
| `snapshots_dir` | `snapshots` |
| `reports_dir` | `reports` |
| `data_packages_dir` | `data-packages` |
| `preflight_dir` | `preflight` |
| `notifications_dir` | `notifications` |
`workspace.root` is required. Each workspace subdirectory must be a relative
path that stays within the root. See the [operations guide](operations.md) for
the managed workspace layout and lifecycle.
### `dayparts` ### `dayparts`
`dayparts` is a non-empty list of named local-time windows used in forecast `dayparts` is a non-empty list of named local-time windows used in forecast
@@ -202,18 +187,6 @@ derivation. Every item needs `name`, `start`, and `end`; start and end use
(`06:00``10:00`), `midday` (`10:00``15:00`), `afternoon` (`06:00``10:00`), `midday` (`10:00``15:00`), `afternoon`
(`15:00``17:00`), and `evening` (`17:00``24:00`). (`15:00``17:00`), and `evening` (`17:00``24:00`).
### `recent_change`
| Field | Default |
| --- | --- |
| `temperature_degrees` | `5` |
| `precip_probability_points` | `20` |
| `wind_gust_miles_per_hour` | `10` |
| `precip_timing_shift_minutes` | `120` |
These thresholds control when Recent Changes are included in prompt input for a
prior comparable module snapshot.
### `reports` ### `reports`
`reports` optionally overrides a report's ordered deterministic modules and `reports` optionally overrides a report's ordered deterministic modules and

View File

@@ -21,16 +21,15 @@ boundaries and invariants.
| Adding, changing, reviewing, or deleting tests | [Testing policy](policy/testing.md) and focused package tests | The policy defines risk-based sufficiency, durable test boundaries, doubles, and test-maintenance criteria. | | Adding, changing, reviewing, or deleting tests | [Testing policy](policy/testing.md) and focused package tests | The policy defines risk-based sufficiency, durable test boundaries, doubles, and test-maintenance criteria. |
| CLI commands, flags, output, quiet mode, or command wiring | [CLI reference](cli.md) and [CLI internals](internal/cli.md) | The reference owns the user contract; the internal guide owns command composition and output flow. | | CLI commands, flags, output, quiet mode, or command wiring | [CLI reference](cli.md) and [CLI internals](internal/cli.md) | The reference owns the user contract; the internal guide owns command composition and output flow. |
| Configuration fields, defaults, loading, overrides, validation, or secrets | [Configuration reference](config.md), [architecture policy](policy/architecture.md), and tests under `internal/config` | These separate the user-visible contract, architectural rules, and executable behavior. | | Configuration fields, defaults, loading, overrides, validation, or secrets | [Configuration reference](config.md), [architecture policy](policy/architecture.md), and tests under `internal/config` | These separate the user-visible contract, architectural rules, and executable behavior. |
| Top-level generation, batch, collection, inspection, or notification workflow | [App orchestration internals](internal/app-orchestration.md) | It owns workflow ordering, persistence points, failure propagation, and orchestration invariants. | | Top-level generation, batch, collection, output publication, or notification workflow | [App orchestration internals](internal/app-orchestration.md) | It owns workflow ordering, output publication, failure propagation, and orchestration invariants. |
| Weather API transport, source envelopes, source warnings, or collection | [Weather API integration](integrations/weatherapi.md), [weather-data internals](internal/weather-data.md), and [collection internals](internal/collect.md) | These separate the external contract, normalized source facts, and app-facing collection behavior. | | Weather API transport, source envelopes, source warnings, or collection | [Weather API integration](integrations/weatherapi.md), [weather-data internals](internal/weather-data.md), and [collection internals](internal/collect.md) | These separate the external contract, normalized source facts, and app-facing collection behavior. |
| Forecast periods, weather derivation, collected facts, or derived facts | [Forecast derivation internals](internal/forecast-derivation.md) and [fact contracts](internal/facts.md) | They own deterministic derivation and the fact boundaries used by reports. | | Forecast periods, weather derivation, collected facts, or derived facts | [Forecast derivation internals](internal/forecast-derivation.md) and [fact contracts](internal/facts.md) | They own deterministic derivation and the fact boundaries used by reports. |
| Report definitions, valid periods, report IDs, output naming, or batch composition | [Report registry internals](internal/report-registry.md) and [app orchestration internals](internal/app-orchestration.md) | Report definitions own selection and period rules; orchestration owns execution. | | Report definitions, valid periods, report IDs, output naming, or batch composition | [Report registry internals](internal/report-registry.md) and [app orchestration internals](internal/app-orchestration.md) | Report definitions own selection and period rules; orchestration owns execution. |
| Module IDs, module composition, briefing values, or prompt-facing exports | [Module contract internals](internal/module.md), [module builder internals](internal/briefing.md), and [prompt-input internals](internal/prompt-input.md) | These own module contracts, value construction, and the curated prompt-package boundary. | | Module IDs, module composition, briefing values, or prompt-facing exports | [Module contract internals](internal/module.md), [module builder internals](internal/briefing.md), and [prompt-input internals](internal/prompt-input.md) | These own module contracts, value construction, and the curated prompt-package boundary. |
| Recent Changes comparison | [Changes internals](internal/changes.md) and [operations guide](operations.md) | The internal guide owns structured comparison; operations owns user-visible artifact behavior. |
| Prompt execution, profiles, prompt inputs, or result handling | `internal/promptexec`, the Promptkit adapter, and [prompt-input internals](internal/prompt-input.md) | These separate the executor contract and input construction. | | Prompt execution, profiles, prompt inputs, or result handling | `internal/promptexec`, the Promptkit adapter, and [prompt-input internals](internal/prompt-input.md) | These separate the executor contract and input construction. |
| Generated-text schemas, validation, render contexts, templates, or Markdown rendering | [Generated-text internals](internal/generatedtext.md), [report-template internals](internal/reporttemplate.md), and [report template guide](templates.md) | These own structured text, renderer implementation, and the maintainer-facing template surface. | | Generated-text schemas, validation, render contexts, templates, or Markdown rendering | [Generated-text internals](internal/generatedtext.md), [report-template internals](internal/reporttemplate.md), and [report template guide](templates.md) | These own structured text, renderer implementation, and the maintainer-facing template surface. |
| Workspace paths, metadata, atomic persistence, lookup, inspection, diagnosis, or recovery | [State internals](internal/state.md) and [operations guide](operations.md) | These separate implementation behavior from operator workflows, diagnosis, and recovery. | | Output destinations, atomic publication, prompt diagnosis, or legacy cleanup | [Operations guide](operations.md) and [App orchestration internals](internal/app-orchestration.md) | Operations owns operator workflows; app internals owns the implementation boundary. |
| Distributor bundles, uploads, notification artifacts, or failures | [Distributor adapter internals](internal/distributor-adapter.md), [Distributor integration contracts](integrations/distributor/), and [operations guide](operations.md) | These separate adapter behavior, external contracts, and operational lifecycle. | | Distributor bundles, uploads, notification results, or failures | [Distributor adapter internals](internal/distributor-adapter.md), [Distributor integration contracts](integrations/distributor/), and [operations guide](operations.md) | These separate adapter behavior, external contracts, and operational lifecycle. |
| Maintained example configuration | [Configuration reference](config.md) and files under `examples/` | The reference owns field meaning; examples own complete copyable files. | | Maintained example configuration | [Configuration reference](config.md) and files under `examples/` | The reference owns field meaning; examples own complete copyable files. |
| Release preparation, tagging, publication, or verification | [Release procedure](release.md) | It owns version selection, release-note preparation, candidate validation, tag publication, CI behavior, and post-publication checks. | | Release preparation, tagging, publication, or verification | [Release procedure](release.md) | It owns version selection, release-note preparation, candidate validation, tag publication, CI behavior, and post-publication checks. |
| Proposed, deferred, or unimplemented work | Documents under `docs/roadmap/` | Future behavior and implementation status belong only in roadmaps until implemented. | | Proposed, deferred, or unimplemented work | Documents under `docs/roadmap/` | Future behavior and implementation status belong only in roadmaps until implemented. |
@@ -45,13 +44,13 @@ present before introducing a new package or abstraction.
| --- | --- | | --- | --- |
| `cmd/weatherreporter` | Binary entry point. | | `cmd/weatherreporter` | Binary entry point. |
| `internal/cli` | Command parsing, flags, help, output, and command wiring. | | `internal/cli` | Command parsing, flags, help, output, and command wiring. |
| `internal/app` | Generation, batches, collection coordination, notification, and inspection orchestration. | | `internal/app` | Stateless generation, batches, collection coordination, output publication, and notification. |
| `internal/config` | Configuration defaults, loading, precedence, secrets, and validation. | | `internal/config` | Configuration defaults, loading, precedence, secrets, and validation. |
| `internal/adapters` | Weather API, Promptkit, and Distributor boundaries. | | `internal/adapters` | Weather API, Promptkit, and Distributor boundaries. |
| `internal/weatherdata`, `internal/forecast`, `internal/facts` | Normalized source facts and deterministic derivation. | | `internal/weatherdata`, `internal/forecast`, `internal/facts` | Normalized source facts and deterministic derivation. |
| `internal/report`, `internal/module`, `internal/briefing`, `internal/changes` | Report registry, module contracts and values, and structured comparison. | | `internal/report`, `internal/module`, `internal/briefing`, `internal/changes` | Report registry, module contracts and values, and structured comparison. |
| `internal/promptinput`, `internal/generatedtext`, `internal/reporttemplate` | Prompt packages, generated-text validation, render contexts, and Markdown templates. | | `internal/promptinput`, `internal/generatedtext`, `internal/reporttemplate` | Prompt packages, generated-text validation, render contexts, and Markdown templates. |
| `internal/state`, `internal/fileutil`, `internal/timeutil` | Durable artifacts, atomic file operations, clocks, dates, timezones, and periods. | | `internal/fileutil`, `internal/timeutil` | Atomic output operations, clocks, dates, timezones, and periods. |
| `docs` | User, operator, integration, internal, policy, and roadmap documentation. | | `docs` | User, operator, integration, internal, policy, and roadmap documentation. |
| `examples` | Maintained copyable configuration. | | `examples` | Maintained copyable configuration. |

View File

@@ -1,30 +1,59 @@
# Weatherreporter Operations # Weatherreporter Operations
This guide covers normal operation, managed workspace state, inspection, This guide covers normal output handling, Distributor notification, secure
recovery, and operational caveats. See the [CLI reference](cli.md) for complete prompt diagnostics, and cleanup of legacy application state. See the [CLI
command syntax and the [configuration reference](config.md) for fields, reference](cli.md) for command syntax and the [configuration reference](config.md)
defaults, and notification templates. for fields, defaults, and notification templates.
## Normal Operation ## Normal Operation
After configuring a Weather API endpoint, generate one report: After configuring a Weather API endpoint, generate one report:
```sh ```sh
weatherreporter generate today --out ./today.md weatherreporter generate today
``` ```
A generation collects weather data, resolves the report period, builds and The command writes `today.md` in the current directory. Choose a different
persists the module snapshot and prompt data package, records Promptkit operator-owned file with `--out`; a relative path is resolved from the current
preparation provenance before provider execution, then persists raw output and directory and an absolute path is used directly. Weatherreporter renders in
execution provenance, validates the structured generated text, and renders the memory and atomically replaces the selected destination only after generation
managed Markdown report from the validated text and deterministic values. and rendering succeed. It does not create a default workspace, metadata,
These receipts describe the current workspace implementation; they are not a receipts, or intermediate output files.
cross-version profile-provenance contract.
The managed report and its final metadata are saved before single-report Before a destination is published, provider, validation, rendering, write, and
Distributor notification is attempted. `--out` writes an extra operator copy; cancellation failures leave an existing report unchanged. A notification
it never changes the managed report or upload source. A successful generate failure happens after publication, so retain and use the completed Markdown
command prints its summary to stdout unless `--quiet` is used. file while resolving the delivery error. The JSON result identifies the
absolute output path and active profile, backend, model, warnings, validation,
debug, and notification information; see the [CLI reference](cli.md) for its
exact fields.
## Batch Outputs And Distributor Notification
Run a scheduled batch with an explicit output directory when appropriate:
```sh
weatherreporter run morning --out-dir ./reports
```
Without `--out-dir`, batch reports are written beneath the current directory.
Morning runs Today, Tomorrow, and every eligible dated Daily Report; evening
runs Tomorrow and the same eligible Daily Reports. Eligible Daily dates begin
after tomorrow and require complete hourly coverage for their local civil day.
A batch collects once, processes each selected report independently, and keeps
successful outputs if another report fails.
When `notify.distributor.enabled` and batch notification are enabled,
Weatherreporter sends one Distributor upload only after every selected output
exists. If an item fails, the batch notification is skipped and successful
files remain at their selected destinations. A batch notification failure also
leaves all successfully published report files in place. Distributor source
files are those operator-owned Markdown outputs; rendered bundle paths and
delivery status appear in the result, not in a local notification receipt.
For a single report, Distributor notification follows the atomic output write.
See the [configuration reference](config.md) for pipeline, bundle,
idempotency-key, and per-report path templates.
## Local Prompt Profile Override ## Local Prompt Profile Override
@@ -36,20 +65,11 @@ set its `endpoint` and `model` for the local server, and configure the copy as
completely replaces the embedded definition; it does not affect a report that completely replaces the embedded definition; it does not affect a report that
selects another profile ID. selects another profile ID.
For example, install the profile file at a known absolute path and set: Prompt and profile validation occurs before weather collection. A malformed
profile file, missing required credential, or unsupported selected backend
```yaml stops the command before collection. A reachable profile can still fail later
promptkit: if its local model endpoint is unavailable; Weatherreporter does not switch to
profile_file: /etc/weatherreporter/weather-light-local-profile.yml a remote profile.
```
Prompt inspection occurs before weather collection. A malformed profile file,
missing required credential, or unsupported selected backend stops the command
before collection. A reachable profile can still fail later if its local model
endpoint is unavailable; Weatherreporter does not switch to a remote profile.
See the [configuration reference](config.md) for field definitions. For a
provider failure, start with the command error and enable secure prompt debug
capture when content-rich diagnostics are required.
## Optional Prompt Debug Capture ## Optional Prompt Debug Capture
@@ -59,153 +79,41 @@ Use `--llm-debug-dir` only when content-rich prompt diagnostics are required:
weatherreporter generate today --llm-debug-dir /var/tmp/weatherreporter-debug weatherreporter generate today --llm-debug-dir /var/tmp/weatherreporter-debug
``` ```
The directory must be absolute and is initialized before prompt inspection or The directory must be absolute. Requested captures are written with restrictive
weather collection. Capture files are stored outside the managed workspace, permissions beneath the supplied directory, organized by report and run. They
with restrictive permissions, under the report ID, valid date, and RunID. can contain rendered prompts and generated output, so limit access to trusted
They can contain rendered prompts and generated output, so the normal metadata, operators and remove the captures when they are no longer needed. Normal output,
CLI summary, and routine logs contain only the optional directory path—not summaries, and routine logs omit that sensitive content. Debug capture is never
their content. A capture-write failure stops that run before later work can created for an ordinary command without `--llm-debug-dir`.
continue.
Run a scheduled batch with the same configured collection: If capture creation or writing fails, the affected run fails rather than
silently continuing without the requested diagnostics.
## Diagnosing Failures
Start with the command error and JSON summary. For a report generation failure,
the selected destination was not replaced; for a notification failure, inspect
the completed destination and the notification result. For a batch failure,
use the per-report statuses and retain successful output files. Enable explicit
debug capture only when content-rich Promptkit diagnostics are necessary.
Weatherreporter does not retain runs for later inspection, resume failed work,
or provide automatic cleanup, archival, remote state, daemon operation, or
automatic storm monitoring.
## Manual Cleanup Of Legacy Workspaces
Older installations may have a directory named `workspace` containing reports,
snapshots, prompt inputs, or notification records from previous versions.
Current commands neither read nor update it. After confirming that no separate
retention requirement applies, remove that specific legacy directory manually;
do not use a broad cleanup command that could remove current operator outputs.
For example, from the directory that contains the old directory:
```sh ```sh
weatherreporter run morning --out-dir ./reports --llm-debug-dir /var/tmp/weatherreporter-debug rm -rf ./workspace
``` ```
Each batch validates its configured prompt/profile candidates, then collects once before it plans reports. Morning runs Today, Tomorrow, This removal cannot be recovered by Weatherreporter. Keep or archive any
and every eligible dated Daily Report; evening runs Tomorrow and the same historical files that are still needed before deleting them.
eligible Daily Reports. Eligible Daily dates begin after tomorrow and require
complete hourly coverage for their entire local civil day. A batch continues
after an individual report fails and returns an aggregate failure when any
report or batch notification fails.
`--out-dir` writes extra copies such as `today.md`, `tomorrow.md`, and
`daily-YYYY-MM-DD.md`. These copies are never upload sources. Batch report
copies and notification behavior are summarized in the CLI result; use the
[CLI reference](cli.md) for its exact JSON and stderr contract.
## Managed Workspace
The default workspace root is `workspace`. Artifact paths use the report
definition's artifact group, the valid-period start date in the effective
timezone, and the RunID:
```text
workspace/
reports/<artifact_group>/<YYYY-MM-DD>/report.<run_id>.md
snapshots/<artifact_group>/<YYYY-MM-DD>/modules.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/metadata.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/generated_text_raw.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/prompt_execution.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/generated_text.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/render_context.<run_id>.json
data-packages/<artifact_group>/<YYYY-MM-DD>/data_package.<run_id>.yaml
preflight/<artifact_group>/<YYYY-MM-DD>/prompt_preparation.<run_id>.json
notifications/<artifact_group>/<YYYY-MM-DD>/distributor.<run_id>.json
notifications/batches/<batch>/<YYYY-MM-DD>/distributor.<batch_run_id>.json
```
The generated-text and render-context artifacts are written for every completed
single-report generation.
A report's metadata links the module snapshot, data package, preparation and
execution receipts, managed report, generated-text artifacts, and any available single-report
notification artifact. These current-version receipts are implementation
details rather than durable interfaces. Use the active command's error and
explicit secure debug capture for prompt diagnosis. Batch
notification artifacts are separate batch-level records under
`notifications/batches`.
RunIDs begin with the UTC generation timestamp and report ID. A Daily RunID
also contains its local valid date so multiple Daily reports in one batch have
different managed paths. Batch notification RunIDs contain the UTC batch start
timestamp and batch name.
## Distributor Notification
When `notify.distributor.enabled` is enabled, a successful `generate`
uploads only the managed Markdown report after final metadata has been saved.
The extra copy from `--out` is never uploaded. A notification attempt writes
a redacted debug artifact at
`notifications/<artifact_group>/<YYYY-MM-DD>/distributor.<run_id>.json`; its
path is then recorded in report metadata.
Batches suppress per-report notification. When both Distributor and its batch
notification are enabled, Weatherreporter submits one multi-report upload after
every planned report succeeds. If any report fails, it records a top-level
`skipped` notification with reason `one or more reports failed` and does not
call Distributor. If batch notification is disabled, a batch does not fall back
to individual uploads.
A batch notification attempt writes
`notifications/batches/<batch>/<YYYY-MM-DD>/distributor.<batch_run_id>.json`.
A notification failure makes the batch fail but does not change successful
individual report items into failed items. The debug artifacts contain rendered
identifiers, managed source and bundle paths, upload and status results, and
redacted errors; they do not contain tokens.
## Inspecting Stored Runs
Inspection is read-only: it neither collects weather data nor invokes
Promptkit or Distributor. Start by finding a RunID:
```sh
weatherreporter inspect reports --limit 10
weatherreporter inspect metadata RUN_ID
```
| Command | Reads |
| --- | --- |
| `inspect reports` | Metadata files under the workspace snapshots tree. |
| `inspect metadata RUN_ID` | Metadata located by RunID. |
| `inspect modules RUN_ID` | The module snapshot path recorded in metadata. |
| `inspect data-package RUN_ID` | The data-package path recorded in metadata. |
| `inspect prior RUN_ID` | The run metadata, then compatible earlier metadata for its comparison policy. |
| `inspect sources RUN_ID` | Source provenance and warnings in the run metadata. |
A missing snapshots directory produces no listed reports. An unknown or empty
RunID is an error; use `inspect reports` to obtain a valid value.
New runs write `weatherreporter.metadata.v2`, including preparation and
execution references once those receipts exist. `inspect metadata` also reads
historic V1 records; their legacy preflight and generated-text-result fields
remain visible for compatibility, but Weatherreporter does not write them for
new runs.
## Recovery
Keep the workspace when a run fails: artifacts reached before the failure
remain available where they can be safely persisted.
- A preparation failure can leave its classified receipt and metadata.
- A report-generation failure can leave the managed report, module snapshot,
data package, and metadata.
- A completed prompt validation rejection leaves raw text, an execution receipt,
and metadata. Later generated-text failures can also leave validated text and
a render-context artifact, depending on where they stopped.
- A single-report notification failure preserves the report and final metadata,
including its notification artifact when it was written.
- A batch notification failure preserves each report's artifacts and adds the
top-level batch notification artifact.
Use the action summary and its error first. For prompt or provider
diagnosis, prefer an explicitly enabled secure debug capture; current-version
receipt paths may provide supplemental context when available. For a batch
failure, inspect the summary first, then inspect the affected report RunIDs or
the batch notification path. Do not remove the whole workspace as a first
response; retain it until the failure is understood.
## Operational Caveats
- Workspace files and generated reports can contain
sensitive operational context. Set appropriate filesystem permissions and do
not publish them unintentionally.
- Weatherreporter uses one configured Weather API endpoint and local workspace
state.
- Promptkit profile resolution does not discover local endpoints or fail over
between local and remote profiles.
- It does not provide automatic resume, cleanup, archival, remote state, daemon
operation, or automatic storm monitoring.

View File

@@ -10,9 +10,10 @@ package inventory; focused documents in `docs/internal/` own implementation deta
Weatherreporter is a deterministic weather-report CLI. It collects normalized Weatherreporter is a deterministic weather-report CLI. It collects normalized
weather data, derives facts and modules, builds a curated YAML data package, weather data, derives facts and modules, builds a curated YAML data package,
compares prior snapshots, executes exact-version Promptkit prompts, validates executes exact-version Promptkit prompts, validates structured generated prose,
structured generated prose, and renders repository-owned Markdown. Completed and renders repository-owned Markdown in memory. Completed Markdown is
managed Markdown may be uploaded through Distributor. atomically published to an operator-owned output destination and may then be
uploaded through Distributor.
The supported report products are Daily, Today, Tomorrow, and Hourly. A batch The supported report products are Daily, Today, Tomorrow, and Hourly. A batch
collects once, validates its complete candidate prompt/profile set before collects once, validates its complete candidate prompt/profile set before
@@ -25,14 +26,12 @@ after every planned report succeeds.
- `internal/cli` owns command parsing, help, summaries, and one executor - `internal/cli` owns command parsing, help, summaries, and one executor
construction per action. construction per action.
- `internal/config` owns defaults, loading, validation, and secret loading. - `internal/config` owns defaults, loading, validation, and secret loading.
- `internal/app` owns workflow order, partial results, and notification - `internal/app` owns in-memory workflow order, partial results, atomic output
coordination through project-owned contracts. publication, and notification coordination through project-owned contracts.
- Deterministic domain packages own weather derivation, report periods, modules, - Deterministic domain packages own weather derivation, report periods, modules,
generated-text validation, and template contexts. generated-text validation, and template contexts.
- `internal/adapters/weatherapi`, `internal/adapters/promptkit`, and - `internal/adapters/weatherapi`, `internal/adapters/promptkit`, and
`internal/adapters/distributor` own their external dependency mechanics. `internal/adapters/distributor` own their external dependency mechanics.
- `internal/state` owns workspace paths, V2 metadata, atomic persistence, and
read-only inspection.
Dependency-specific Promptkit types remain inside its adapter. The application Dependency-specific Promptkit types remain inside its adapter. The application
does not parse flags, construct provider clients, or render provider output does not parse flags, construct provider clients, or render provider output
@@ -41,28 +40,29 @@ directly.
## Prompt Execution Invariants ## Prompt Execution Invariants
- Prompts receive curated module packages, never unbounded raw weather payloads. - Prompts receive curated module packages, never unbounded raw weather payloads.
- Every execution inspects the exact prompt version and output contract before - Every execution validates the exact prompt version and output contract before
collection. The selected profile is configured explicitly or declared by the collection. The selected profile is configured explicitly or declared by the
prompt; unsupported direct-key profiles and missing reported credentials fail prompt; unsupported direct-key profiles and missing reported credentials fail
before collection. before collection.
- Prepared execution persists safe preparation provenance before provider work. - Prompt and profile validation completes before weather collection. Raw output
Completed execution persists safe execution provenance; raw output is is validated before template rendering.
validated before template rendering.
- Generated text fills defined prose slots only. Deterministic facts remain - Generated text fills defined prose slots only. Deterministic facts remain
authoritative and repository-owned templates produce all managed Markdown. authoritative and repository-owned templates produce all managed Markdown.
- Sensitive rendered prompts, schemas, input bodies, provider endpoints, and - Sensitive rendered prompts, schemas, input bodies, provider endpoints, and
credentials never enter normal metadata, summaries, logs, or workspace credentials never enter normal summaries or logs. They are written only to
artifacts. They are written only to an explicit secure debug root when an explicit secure debug root when requested.
requested.
## State, Notification, And Testing Invariants ## Output, Notification, And Testing Invariants
- Managed writes are atomic where practical and stay beneath the configured - Normal execution is stateless: it keeps weather data, prompt input, generated
workspace root. Reached artifacts remain inspectable after later failures. text, and render context in memory and creates no application-owned durable
- New records use `weatherreporter.metadata.v2`; V1 records remain readable for state.
inspection compatibility. - Markdown writes are atomic at an operator-selected destination. A
- Distributor uploads use only the managed Markdown report, never output copies pre-publication failure does not replace an existing destination; a
or workspace scans. Notification follows report and final metadata success. notification failure does not remove a newly published output.
- Distributor uploads use only the published Markdown output, never a scan of
local files. Single notification follows publication; batch notification
follows publication of every selected report.
- Default tests are deterministic, offline, and use Promptkit/provider fakes - Default tests are deterministic, offline, and use Promptkit/provider fakes
rather than live provider calls. See the [testing policy](testing.md). rather than live provider calls. See the [testing policy](testing.md).

View File

@@ -85,8 +85,8 @@ mechanisms, not secret values.
| Release procedure | `docs/release.md` | Version policy, release preparation, validation, tagging, automated publication, verification, failure handling, and release ordering. | General contributor workflow, product contracts, release-specific change summaries, and implementation history. | | Release procedure | `docs/release.md` | Version policy, release preparation, validation, tagging, automated publication, verification, failure handling, and release ordering. | General contributor workflow, product contracts, release-specific change summaries, and implementation history. |
| Release notes | `docs/releases/` | One versioned, changelog-style summary for each release, including compatibility and operator action. The file at the tagged commit supplies the corresponding Gitea release body. | Current CLI, configuration, operations, integration, architecture, and internal contracts; release procedure; implementation plans. | | Release notes | `docs/releases/` | One versioned, changelog-style summary for each release, including compatibility and operator action. The file at the tagged commit supplies the corresponding Gitea release body. | Current CLI, configuration, operations, integration, architecture, and internal contracts; release procedure; implementation plans. |
| CLI contract | `docs/cli.md` | Commands, arguments, flags, invocation semantics, stdout and stderr behavior, summaries, and exit behavior. | Configuration field definitions, complete operating procedures, runtime filesystem layout, and command implementation. | | CLI contract | `docs/cli.md` | Commands, arguments, flags, invocation semantics, stdout and stderr behavior, summaries, and exit behavior. | Configuration field definitions, complete operating procedures, runtime filesystem layout, and command implementation. |
| Configuration contract | `docs/config.md` | Discovery and precedence, fields, defaults, secrets, validation rules, and user-selectable values. | Complete example files, CLI syntax, runtime state lifecycle, and loading implementation. | | Configuration contract | `docs/config.md` | Discovery and precedence, fields, defaults, secrets, validation rules, and user-selectable values. | Complete example files, CLI syntax, output lifecycle, and loading implementation. |
| Operations | `docs/operations.md` | Normal workflows, physical workspace layout, artifacts and metadata, inspection, notification behavior, diagnosis, recovery, cleanup, permissions, and operational caveats. | Complete CLI syntax, configuration field definitions, logical external contracts, and implementation mechanics. | | Operations | `docs/operations.md` | Normal output handling, atomic replacement, notification behavior, diagnosis, explicit debug capture, manual legacy-workspace cleanup, permissions, and operational caveats. | Complete CLI syntax, configuration field definitions, logical external contracts, and implementation mechanics. |
| Report template surface | `docs/templates.md` | Implemented template files and partials, render-context fields, editing rules, and maintainer-facing template examples. | Weather derivation, module implementation, generated-text validation internals, and operator procedures. | | Report template surface | `docs/templates.md` | Implemented template files and partials, render-context fields, editing rules, and maintainer-facing template examples. | Weather derivation, module implementation, generated-text validation internals, and operator procedures. |
| External and durable integration contracts | `docs/integrations/` | Weather API, Promptkit, Distributor, external formats and protocols, durable logical paths and schemas, compatibility behavior, and upstream or downstream responsibilities. | Physical runtime placement and lifecycle, internal transformations, CLI syntax, and configuration defaults. | | External and durable integration contracts | `docs/integrations/` | Weather API, Promptkit, Distributor, external formats and protocols, durable logical paths and schemas, compatibility behavior, and upstream or downstream responsibilities. | Physical runtime placement and lifecycle, internal transformations, CLI syntax, and configuration defaults. |
| Internal subsystem behavior | `docs/internal/` | Implementation flow, internal collaborators and state transitions, package-local guarantees and failures, and relevant tests. | Global architecture invariants, user-facing contracts, external schemas, operator procedures, and future package plans. | | Internal subsystem behavior | `docs/internal/` | Implementation flow, internal collaborators and state transitions, package-local guarantees and failures, and relevant tests. | Global architecture invariants, user-facing contracts, external schemas, operator procedures, and future package plans. |
@@ -113,8 +113,8 @@ parallel package or behavior references.
CLI documentation answers how to invoke Weatherreporter and what its command CLI documentation answers how to invoke Weatherreporter and what its command
interface does. Configuration documentation answers what settings mean. interface does. Configuration documentation answers what settings mean.
Operations answers what happens to runtime state and how to operate or recover Operations answers how to handle operator-owned outputs and runtime failures,
the application, including diagnosis and safe responses to runtime failures. including diagnosis, explicit debug capture, and safe legacy cleanup.
When a workflow crosses these topics, place the complete procedure with the When a workflow crosses these topics, place the complete procedure with the
document that owns the task and link to the other contracts. Do not duplicate document that owns the task and link to the other contracts. Do not duplicate

View File

@@ -96,8 +96,8 @@ Use each test type where it protects a distinct risk:
- Integration tests use real deterministic collaborators when correctness - Integration tests use real deterministic collaborators when correctness
depends on their interaction, while replacing live or nondeterministic depends on their interaction, while replacing live or nondeterministic
external boundaries. external boundaries.
- App and CLI tests protect representative assembled generation, batch, - App and CLI tests protect representative assembled generation, batch, atomic
inspection, persistence, and notification workflows. output, and notification workflows.
- Fixtures must be minimal, synthetic, versioned with the behavior they - Fixtures must be minimal, synthetic, versioned with the behavior they
exercise, and free of credentials or private data. exercise, and free of credentials or private data.
- Golden files are appropriate only when the complete output is intentionally - Golden files are appropriate only when the complete output is intentionally
@@ -199,9 +199,9 @@ Each behavior should have a clear test owner:
- Config tests own loading, precedence, defaults, secrets, and validation. - Config tests own loading, precedence, defaults, secrets, and validation.
- Domain tests own weather transformations and invariants. - Domain tests own weather transformations and invariants.
- Adapter tests own HTTP, Promptkit/provider, and upload boundaries. - Adapter tests own HTTP, Promptkit/provider, and upload boundaries.
- Orchestrator tests own workflow ordering, persistence, partial success, and - Orchestrator tests own workflow ordering, output publication, partial success,
failure propagation. and failure propagation.
- State tests own path derivation, atomic artifacts, lookup, and round trips. - Filesystem tests own atomic writes and destination-preservation behavior.
- Template and generated-text tests own schemas, render contexts, and rendered - Template and generated-text tests own schemas, render contexts, and rendered
output contracts. output contracts.
@@ -219,8 +219,8 @@ observation:
3. Use stubs when a dependency only needs controlled responses. 3. Use stubs when a dependency only needs controlled responses.
4. Use mocks when the interaction itself is contractual. 4. Use mocks when the interaction itself is contractual.
Mocks are appropriate for requirements such as uploading exactly once, saving Mocks are appropriate for requirements such as uploading exactly once,
metadata before notification, propagating cancellation to Promptkit, or notifying only after output publication, propagating cancellation to Promptkit, or
avoiding an external call after an earlier workflow failure. Do not use mocks avoiding an external call after an earlier workflow failure. Do not use mocks
merely to isolate every object or reproduce the implementation's call graph. merely to isolate every object or reproduce the implementation's call graph.