Reconcile internal stateless documentation

This commit is contained in:
2026-08-01 20:16:47 +00:00
parent bd34ec57f8
commit 71a2eae87b
18 changed files with 78 additions and 347 deletions

View File

@@ -58,8 +58,8 @@ application to record.
Run and idempotency records are in-memory. Completed records expire according
to Distributor's `server.http.retention`, and a Distributor restart removes
retained status and idempotency state. Status polling decisions and persistence
of notification artifacts are internal orchestration behavior; see the
retained status and idempotency state. Status polling decisions are internal
orchestration behavior; see the
[Distributor adapter](../../internal/distributor-adapter.md) and
[application orchestration](../../internal/app-orchestration.md).

View File

@@ -8,15 +8,15 @@ the upload call returns.
## File Mappings
Every mapping pairs a managed Markdown report source with one bundle-relative
path. A single-report notification maps its one managed report to each rendered
Every mapping pairs an operator-owned Markdown output with one bundle-relative
path. A single-report notification maps its published output to each rendered
path configured for that report. A batch notification combines mappings for
every included managed report and rejects duplicate bundle paths.
every included published output and rejects duplicate bundle paths.
The report source is never an `--out` copy or an arbitrary workspace scan. The
application selects it and renders notification paths; see the [operations guide](../../operations.md)
for the managed-upload rule and the [Distributor adapter](../../internal/distributor-adapter.md)
for the adapter boundary.
The report source is the output selected for that command; the application does
not scan local directories. It renders notification paths after publication;
see the [operations guide](../../operations.md) and the
[Distributor adapter](../../internal/distributor-adapter.md) for the boundary.
Bundle paths must be clean, relative, slash-separated paths. They cannot be
empty or absolute, contain backslashes, empty segments, `.` or `..`, or use

View File

@@ -16,7 +16,7 @@ For each notification, Weatherreporter calls `UploadFiles` with:
- the rendered pipeline ID;
- the rendered bundle ID as the source manifest ID;
- the report or batch generation time as `Created`;
- the managed-report-to-bundle-path mappings described in the
- the published-output-to-bundle-path mappings described in the
[bundle mapping contract](pkg-bundle.md); and
- a rendered idempotency key.
@@ -38,8 +38,8 @@ adapter translates it to its own conflict error without exposing the token.
The adapter then calls `Status` for the accepted run. A terminal `failed`
status is a notification failure. A status lookup failure or a timeout before a
terminal status remains attached to the otherwise accepted upload as diagnostic
status information. Polling cadence, final failure handling, redaction, and
notification artifact persistence are internal behavior documented in the
status information. Polling cadence, final failure handling, and redaction are
internal behavior documented in the
[Distributor adapter](../../internal/distributor-adapter.md) and
[application orchestration](../../internal/app-orchestration.md).

View File

@@ -1,15 +1,10 @@
# Promptkit Integration
Weatherreporter uses Promptkit for all generated-text reports. The four logical
prompts are `weather.daily_generated_text`, `weather.today_generated_text`,
`weather.tomorrow_generated_text`, and `weather.hourly_generated_text`, each at
version `1.1.0`. Their prompt assets, generated-text JSON Schemas, and
Weatherreporter profile catalog are embedded by `internal/promptassets`.
Weatherreporter uses Promptkit for all generated-text reports. The four logical prompts are `weather.daily_generated_text`, `weather.today_generated_text`, `weather.tomorrow_generated_text`, and `weather.hourly_generated_text`, each at version `2.0.0`. Their prompt assets, generated-text JSON Schemas, and Weatherreporter profile catalog are embedded by `internal/promptassets`.
## Logical profile catalog
## Logical Profile Catalog
Prompt definitions select a stable Weatherreporter profile ID. The embedded
definitions currently use Promptkit's `openrouter` backend:
Prompt definitions select a stable Weatherreporter profile ID. The embedded definitions currently use Promptkit's `openrouter` backend:
| Profile ID | Model | Reasoning effort | Timeout | Service tier | Default reports |
| --- | --- | --- | --- | --- | --- |
@@ -17,44 +12,23 @@ definitions currently use Promptkit's `openrouter` backend:
| `weather-balanced` | `~google/gemini-flash-latest` | `high` | 240 seconds | `flex` | Daily, Today, Tomorrow |
| `weather-deep` | `~anthropic/claude-sonnet-latest` | `high` | 240 seconds | `flex` | None |
The `~` prefix is part of each OpenRouter rolling-alias model ID. The embedded
profiles intentionally omit endpoints, credentials, temperature, `top_p`, and
output-token limits.
The `~` prefix is part of each OpenRouter rolling-alias model ID. The embedded profiles intentionally omit endpoints, credentials, temperature, `top_p`, and output-token limits.
## Selection, lookup, and active execution
## Selection And Active Execution
Before collection, Weatherreporter inspects the exact prompt version and output
contract. A nonblank `promptkit.profile` selects one profile ID for every
report in the command; otherwise the prompt's declared default selects it.
Promptkit resolves the selected definition in this order:
Before weather collection, Weatherreporter validates the exact prompt version, output contract, and selected profile. A nonblank `promptkit.profile` selects one profile ID for every report in the command; otherwise the prompt's declared default selects it. Promptkit resolves the selected definition in this order:
1. explicit in-memory profiles used by an embedding consumer or test;
2. the configured `profile_file` or `profile_dir`;
3. Weatherreporter's embedded fallback profiles; and
4. Promptkit's built-in catalog.
A source falls through only when the selected ID is absent. Each source
supplies a complete definition, so profile fields are not merged. A malformed
matching operator definition is an error and does not fall back.
A source falls through only when the selected ID is absent. Each source supplies a complete definition, so profile fields are not merged. A malformed matching operator definition is an error and does not fall back.
Profiles that require a direct API key are unsupported; a profile that reports
`APIKeyEnv` requires a nonblank value in that environment variable. Inspection,
preparation, and execution retain the selected logical profile ID and resolved
backend and model through Weatherreporter's project-owned contract. Ordinary
errors, summaries, logs, and workspace state exclude endpoints, credentials,
rendered messages, schemas, request bodies, response bodies, and complete
parameter maps.
Profiles that require a direct API key are unsupported; a profile that reports `APIKeyEnv` requires a nonblank value in that environment variable. Active results retain the selected logical profile ID and resolved backend and model. Ordinary errors, summaries, logs, and outputs exclude endpoints, credentials, rendered messages, schemas, request bodies, response bodies, and complete parameter maps.
Execution receives the already-persisted YAML package, prepares it once, and returns structured
JSON that Weatherreporter validates before rendering its own Markdown template. Preparation and
execution receipts are project-owned, safe provenance records. Content-rich diagnostics are
opt-in through `--llm-debug-dir`; see [operations](../operations.md) for retention and permissions.
Promptkit receives the YAML data package as an inline input and returns structured JSON that Weatherreporter validates before rendering its own Markdown template. Safe active provenance remains in memory. Content-rich diagnostics are opt-in through `--llm-debug-dir`; see [operations](../operations.md) for retention and permissions.
The generated-text schemas require `summary`, `forecast_discussion`, and
`precipitation_timing`, and reject additional properties. Prompts return an empty string for
`precipitation_timing` when the deterministic package contains no precipitation windows.
The generated-text schemas require `summary`, `forecast_discussion`, and `precipitation_timing`, and reject additional properties. Prompts return an empty string for `precipitation_timing` when the deterministic package contains no precipitation windows.
Prompt/profile configuration and the maintained local override example are
owned by the [configuration reference](../config.md). Adapter construction and
mapping are documented in the [Promptkit adapter internals](../internal/promptkit-adapter.md).
Durable metadata compatibility is described in [state internals](../internal/state.md).
Prompt/profile configuration and the maintained local override example are owned by the [configuration reference](../config.md). Adapter construction and mapping are documented in the [Promptkit adapter internals](../internal/promptkit-adapter.md).

View File

@@ -1,48 +1,24 @@
# Application Orchestration Internals
`internal/app` owns top-level generation, batch, collection, inspection, and
notification ordering after the CLI has parsed arguments and loaded configuration.
`internal/app` owns stateless report generation, batch execution, atomic output publication, and notification coordination after `internal/cli` has parsed arguments and loaded configuration. The user contract is owned by the [CLI reference](../cli.md) and [operations guide](../operations.md).
## Generation
## Single-Report Flow
`GenerateDetailed` resolves one of the four report definitions, initializes an
optional debug root, and inspects the exact Promptkit prompt/profile before it
collects weather or writes managed state. A configured global profile selects
every report in the action; otherwise the exact prompt selects its default
logical profile. Inspection keeps only the selected profile ID and effective
backend/model needed by the project-owned execution contract. It then builds facts and modules,
saves the YAML data package, persists preparation metadata from the executor
callback, executes the prepared prompt, saves execution provenance and raw
output, validates generated text, renders Markdown, and optionally copies or
notifies from the managed report.
`GenerateDetailed` resolves the requested report and output destination, then initializes an optional explicit debug writer. It validates the exact Promptkit prompt and selected profile before collecting weather data. The resolved profile, backend, and model are carried in the active result.
After a completed prompt run, each successfully written downstream artifact is
atomically added to the execution record before the corresponding metadata
rewrite. Later failures therefore leave the original Promptkit outcome and its
last durable set of reached paths inspectable.
The workflow builds facts, a module snapshot, briefing metadata, and the YAML prompt package in memory. It executes Promptkit, validates the returned generated text, builds a render context, and renders Markdown. `fileutil` atomically writes the completed Markdown to the selected output path. Only after that write succeeds does single-report notification run.
Failure results retain all safe paths reached so far. Validation rejection
persists raw output and execution provenance but does not render a report.
Failures return an active partial result with safe identity, profile, warning, validation, debug, and output information when available. A failure before publication leaves an existing destination unchanged. A notification failure retains the newly published output.
## Batches
`RunBatchDetailed` constructs a single debug writer and uses the request's
single executor. Before collection it inspects Today, Tomorrow, and Daily for
morning, or Tomorrow and Daily for evening, deduplicating inspection of a
shared selected profile. It then collects once, plans eligible Daily dates, and calls the
same prompt-generation core sequentially for each planned report. Per-report
notification is suppressed; a failed report does not stop later reports.
`RunBatchDetailed` captures one output directory, creates at most one explicit debug writer, and uses one executor. Before collection it validates the prompt and profile candidates for the selected batch. It collects once, calculates the data-dependent plan, and invokes the same generation core sequentially for each planned report.
Batch notification is skipped when disabled or when any report failed.
Successful notification uses the completed managed report paths only. Batch
items retain preparation, execution, and optional debug paths when reached.
Each item has an independent result. A failed item does not stop later items; successful items retain their published output paths. Per-report notification is suppressed during a batch. Batch notification runs only after every planned report has published successfully. It is skipped when any item failed.
## Inspection And Boundaries
## Boundaries And Verification
Inspection loads persisted state only. It does not collect weather, invoke
Promptkit, or upload reports. The app coordinates project-owned contracts but
does not parse flags, load YAML, implement transport, construct provider SDKs,
or define report-period policy.
The package does not parse flags, load YAML, implement transport, construct provider SDKs, or define report-period policy. Prompt, profile, weather, and Distributor implementations remain behind project-owned contracts.
Focused checks:

View File

@@ -66,4 +66,4 @@ go test ./internal/briefing
```
Builders emit structured facts, never report prose. The app collects their
outputs into a module snapshot, and state persists that snapshot.
outputs into an in-memory module snapshot for prompt input and rendering.

View File

@@ -1,56 +0,0 @@
# Changes Internals
`internal/changes` deterministically compares a compatible prior module
snapshot with the current snapshot. It returns compact structured changes for
prompt input; it never reads state, finds a prior report, renders Markdown, or
compares generated text. Snapshot construction belongs to
[module internals](module.md), and prior-snapshot discovery belongs to
[state internals](state.md).
## Comparison inputs and output
Each comparator receives a prior snapshot, a current snapshot, and
`Thresholds`. A `Change` has a stable type and message plus previous and
current values where useful. Changes are sorted by type and then message, so
the same inputs always yield the same order.
Threshold values are supplied by application orchestration from the
[Recent Changes configuration](../config.md#recent_change); this package does
not load configuration or choose defaults. Numeric changes are emitted when
the absolute difference meets the configured threshold. Precipitation also
requires a change between its low, possible, likely, and high categories.
## Strategies
| Comparator | Required snapshot data | Compared values |
| --- | --- | --- |
| `CompareDaily` | `derived_daily_summary`, `derived_daypart_summaries` | Low and high temperature, daily precipitation probability and timing, peak gust, alerts, and aggregate indicators |
For daily comparison, `alert_digest` and `precip_timing` are optional: alerts
are compared when present, and timing is compared only when both snapshots
contain it.
The application selects a comparator only after state lookup establishes a
compatible prior snapshot. Daily, Today, and Tomorrow use the daily comparator.
Hourly reports do not produce a Recent Changes list.
## Missing data and failures
Required stanzas that are absent or cannot be decoded return an error with the
snapshot and stanza context. Optional stanzas may be absent. A snapshot with no
eligible predecessor is not a comparison failure: the caller supplies an empty
change list without invoking this package.
The package has no filesystem, transport, CLI, renderer, or persistence
behavior. It does not decide report compatibility or retain snapshots.
## Verification and invariants
Focused tests cover the daily strategy, threshold boundaries, indicator and
alert changes, and missing required stanzas:
```sh
go test ./internal/changes
```
Recent Changes always compare structured snapshot values, never report prose.

View File

@@ -1,26 +1,14 @@
# CLI Internals
`internal/cli` parses terminal arguments, loads configuration, constructs app
requests, and translates app results to bounded JSON summaries. The user
contract belongs in the [CLI reference](../cli.md).
`internal/cli` parses terminal arguments, loads configuration, constructs app requests, and translates app results to bounded JSON summaries. The public contract belongs in the [CLI reference](../cli.md).
The root `--version` flag reports the build version supplied by
`internal/buildinfo`. Tagged release builds replace its development default at
link time.
The root `--version` flag reports the build version supplied by `internal/buildinfo`. Tagged release builds replace its development default at link time.
For each `generate` or `run` action, `Runner` constructs one project-owned
Promptkit executor after configuration loads. It passes the executor and any
`--llm-debug-dir` request into the app. `run` accepts the debug flag as well
as `generate`; the app, not the CLI, secures and initializes the debug root.
For each `generate` or `run` action, `Runner` constructs one project-owned Promptkit executor after configuration loads. It captures an absolute working directory, resolves a relative output override against it, and passes the working directory, resolved override, and any `--llm-debug-dir` request to the app. With no override, the app derives the report filename in that working directory. `run` uses the same resolution rule for `--out-dir`.
Summaries include identity, status, safe artifact paths, and notification
provenance. They intentionally exclude module values, YAML package bodies, raw
generated text, rendered prompts, schemas, endpoints, credentials, and full
Distributor payloads. A failed action with a partial result still emits its
safe summary before its error is returned.
The CLI dispatches only generation and batch actions. It has no persisted-run or inspection dispatch. Summaries include report identity, status, output path, effective profile/backend/model, source warnings, validation, requested debug path, and notification result when available. They intentionally exclude prompt input, raw generated text, render context, endpoints, credentials, and full Distributor payloads. A failed action with a partial result still emits its safe summary before its error is returned.
CLI code owns no report policy, weather collection, persistence, provider
execution, or notification policy. Focused checks:
CLI code owns no report policy, weather collection, output publication, provider execution, or notification policy. Focused checks:
```sh
go test ./internal/cli

View File

@@ -47,7 +47,7 @@ status, and `RunStatus`, including pipeline ID, lifecycle timestamps, report,
and remote error details.
Status lookup or polling errors are preserved in `UploadResult.StatusError` so
the caller can record an accepted-but-unconfirmed delivery. A terminal failed
the caller can report an accepted-but-unconfirmed delivery. A terminal failed
run returns that result and an error. Upload failures return no result. Upstream
idempotency conflicts become the local `IdempotencyConflictError`, which adds
endpoint, pipeline, bundle, idempotency, and file-path context while redacting

View File

@@ -60,5 +60,5 @@ go test ./internal/facts
```
Facts are derived once for a resolved report from already collected data.
They remain reusable structured values: prompt wording, state persistence,
prior-report comparison, and template presentation are owned elsewhere.
They remain reusable structured values for prompt input and template
presentation, which are owned elsewhere.

View File

@@ -46,9 +46,7 @@ UTC when these APIs are called directly. Optional narrative, discussion, and
alerts remain absent when their normalized products are absent.
Forecast thresholds used for brief indicators and precipitation timing are
implementation rules. User-configurable Recent Changes thresholds are applied
by [changes internals](changes.md), whose defaults are documented in
[configuration](../config.md).
implementation rules.
## Verification and invariants

View File

@@ -34,8 +34,8 @@ template iteration rather than maps.
Optional source stanzas become nil or fallback context fields. Missing required
stanzas, type-decoding failures, invalid metadata, or a generated-text type
that does not match the chosen handler fail before template execution. Prompt
packages, raw Promptkit output, state persistence, and template asset lookup
remain outside this package.
packages, raw Promptkit output handling, and template asset lookup remain
outside this package.
## Verification and invariants

View File

@@ -1,7 +1,7 @@
# Module Contract Internals
`internal/module` defines the stable envelope between report composition,
module builders, snapshots, comparisons, templates, and prompt packages. It
module builders, in-memory snapshots, templates, and prompt packages. It
does not define a report, execute a builder, or choose prompt-export policy;
those responsibilities belong to [report registry](report-registry.md) and
[briefing](briefing.md).
@@ -11,10 +11,10 @@ those responsibilities belong to [report registry](report-registry.md) and
Each `Output` has a module ID, stanza name, rich `Value`, and runtime-only
`PromptValue`. `DataPackageValue` returns the prompt value when present and
otherwise the rich value. This permits custom prompt exports without shrinking
the template and inspection value.
the template value.
`NewSnapshot` builds the ordered `weatherreporter.modules.v1` snapshot and
validates it. Snapshot JSON persists IDs, stanza names, and rich values only;
validates it. Its JSON representation contains IDs, stanza names, and rich values only;
`PromptValue` is deliberately excluded. `StanzaValue` decodes a named rich
stanza into a caller-supplied type, reporting a missing stanza separately from
a decoding error.
@@ -47,7 +47,7 @@ are validated by the briefing registry.
## Rich and prompt-facing values
Rich values remain available to snapshots, comparisons, and render contexts.
Rich values remain available to module snapshots and render contexts.
Briefing attaches custom prompt exports only for current conditions, hourly
forecast, and derived daypart summaries; all other current builders use
pass-through values. The prompt package owns how exported stanzas are grouped

View File

@@ -1,29 +1,16 @@
# Prompt Input Internals
`internal/promptinput` converts report metadata, an ordered module snapshot,
Recent Changes, and source warnings into the YAML `data_package` consumed by
Promptkit. It owns this package's schema, grouping, serialization, loading,
and validation—not weather collection, module construction, path choice, or
provider execution.
`internal/promptinput` converts report metadata, an ordered module snapshot, and source warnings into the YAML `data_package` supplied inline to Promptkit. It owns the package schema, grouping, serialization, loading, and validation; it does not choose an output destination, collect weather, execute a provider, or retain packages after a command ends.
## Package construction
## Package Construction
`Build` produces `weatherreporter.data_package.v3`. It copies the run ID;
report ID, variant, prompt ID, generation time, timezone, local current date,
and valid period; ordered briefing stanzas; Recent Changes; and source
warnings. A nil Recent Changes slice becomes an empty `items` list.
`Build` produces `weatherreporter.data_package.v4`. It copies the run ID; report ID, variant, prompt ID, generation time, timezone, local current date, and valid period; ordered briefing stanzas; and source warnings. Prompt input contains no historical comparison section.
Briefing starts as a flat snapshot order and stanza-value map. `Build` uses
each output's `DataPackageValue`, so runtime prompt exports take precedence and
rich values are used only as a fallback. Prompt exports are selected by the
[briefing registry](briefing.md), while the rich-versus-prompt contract is in
[module internals](module.md).
Briefing is a flat ordered set of stanza values. `Build` uses each output's `DataPackageValue`, so curated prompt exports take precedence and rich values are used only as a fallback. Prompt exports are selected by the [briefing registry](briefing.md), while the rich-versus-prompt contract is in [module internals](module.md).
## YAML ordering and grouping
## YAML Ordering And Validation
Serialization keeps `metadata` directly under `briefing`. Every other known
stanza is placed in exactly one category, emitted in category order and in its
original snapshot order within that category:
Serialization keeps `metadata` directly under `briefing`. Every other known stanza is placed in one category and emitted in category order while preserving its original module order:
| Category | Current stanzas |
| --- | --- |
@@ -32,30 +19,10 @@ original snapshot order within that category:
| `narrative_products` | narrative forecast, discussions, and weather story |
| `raw_data` | current conditions and hourly forecast |
This YAML presentation does not alter the flat snapshot model. `LoadYAML`
accepts the same category layout and reconstructs flat `Order` and `Values`,
rejecting misplaced, duplicate, unknown, or uncategorized stanzas.
`LoadYAML` accepts this layout and reconstructs the flat order and values. It rejects misplaced, duplicate, unknown, or uncategorized stanzas. `Validate` requires the v4 schema version, report identity and period fields, and at least one ordered briefing stanza. `MarshalYAML` and `LoadYAML` validate their result. `Save` remains a reusable atomic-file helper for callers that explicitly need one; normal application execution passes marshalled YAML directly to Promptkit.
## Validation and persistence
`Validate` requires the current schema version, run and report identifiers,
prompt ID, generation timestamp, timezone, current local date, valid period,
and at least one ordered briefing stanza. It rejects duplicate stanza names,
missing values, and a missing category for every non-metadata stanza.
`MarshalYAML` and `LoadYAML` validate their result. `Save` writes the serialized
YAML atomically; managed workspace paths are owned by [state internals](state.md).
Generated-text artifacts and template render contexts are later workflow
artifacts, not members of this package.
## Verification and invariants
Focused tests cover construction, curated exports, category ordering, YAML
round trips, invalid layout, validation, and atomic saves:
Focused tests cover construction, curated exports, category ordering, YAML round trips, invalid layout, validation, and atomic saves:
```sh
go test ./internal/promptinput
```
The package is narrower than a template render context and never infers changes
from report prose.

View File

@@ -1,26 +1,12 @@
# Promptkit Adapter Internals
`internal/adapters/promptkit` maps Weatherreporter's project-owned executor contract to Promptkit.
The CLI maps `promptkit` configuration to a `PromptExecutorConfig` and constructs one executor
per action. Promptkit dependency types do not escape the adapter.
`internal/adapters/promptkit` maps Weatherreporter's project-owned executor contract to Promptkit. The CLI maps `promptkit` configuration to a `PromptExecutorConfig` and constructs one executor per action. Promptkit dependency types do not escape the adapter.
The adapter supplies Weatherreporter's embedded prompt, schema, and fallback
profile filesystems to each engine. Promptkit remains responsible for resolving
the configured operator profile source, application fallback catalog, and its
built-in catalog; the adapter does not parse profile YAML, merge sources, or
probe endpoints.
The adapter supplies Weatherreporter's embedded prompt, schema, and fallback profile filesystems to each engine. Promptkit resolves configured operator profile sources, the embedded fallback catalog, and its built-in catalog; the adapter does not parse profile YAML, merge sources, or probe endpoints.
The adapter exposes exact prompt and profile inspection plus prepared execution.
It maps Promptkit inspection values to project-owned prompt input,
output-contract, logical profile identity, effective backend/model,
preparation, execution, validation, and optional debug values. It classifies
adapter failures without copying provider secrets or unbounded response bodies
into application errors or normal state.
The adapter exposes exact prompt and profile validation plus prepared execution. It maps safe prompt identity, logical profile, effective backend/model, preparation, execution, validation, and optional debug values into `promptexec`. `Execute` passes the YAML package as an inline Promptkit input; it does not construct a filesystem URI or write a package file.
The app calls the executor's preparation callback before provider execution to persist safe preparation
provenance. Completed executions are then persisted as safe execution provenance and raw generated text
is validated by `internal/generatedtext`. The adapter does not write workspace state, render Markdown,
choose report definitions, or send Distributor notifications.
The application uses the preparation callback to record active safe provenance in memory and optionally writes content-rich diagnostics only through an explicit debug writer. The adapter returns raw output for application validation and rendering. It does not retain application state, render Markdown, choose report definitions, or send Distributor notifications.
Focused tests:
@@ -28,5 +14,4 @@ Focused tests:
go test ./internal/adapters/promptkit ./internal/cli ./internal/app
```
The public logical prompt/profile/schema contract is owned by the
[Promptkit integration guide](../integrations/promptkit.md).
The public logical prompt/profile/schema contract is owned by the [Promptkit integration guide](../integrations/promptkit.md).

View File

@@ -1,72 +1,30 @@
# Report Registry Internals
`internal/report` owns the registry of report identities and the data declared
for each one: resolution, prompt identity and version, comparison policy,
artifact group, output-copy name, default module composition, and Distributor
path declarations. The public command syntax is owned by the
[CLI reference](../cli.md); configuration aliases and overrides are owned by
the [configuration reference](../config.md).
`internal/report` owns report identities, valid-period resolution, exact prompt identity and version, output names, default module composition, and Distributor path declarations. Public command syntax belongs in the [CLI reference](../cli.md); configuration aliases and overrides belong in the [configuration reference](../config.md).
## Definitions and resolution
## Definitions And Resolution
Each `Definition` declares a stable ID and display name, prompt ID, generation
version, template and generated-text schema IDs, valid-period resolver,
comparison strategy, artifact group, batch-copy filename, Distributor path
templates, generation eligibility, compatible prior IDs, default modules, and
batch eligibility flags. `Resolved` combines that definition with the valid
period and run metadata for one invocation.
Each `Definition` declares a stable ID and display name, prompt ID and version, template and generated-text schema IDs, valid-period resolver, default output name, Distributor path templates, module list, and fixed batch eligibility. `Resolved` combines a definition with one valid period and run identity.
| Report ID | Prompt version | Default profile | Period policy | Comparison | Registry batch flag | Output copy |
| --- | --- | --- | --- | --- | --- | --- |
| `daily` | `1.1.0` | `weather-balanced` | Explicit local civil day | Same valid date | Dynamic Daily inclusion is app-owned | `daily.md` |
| `today` | `1.1.0` | `weather-balanced` | Selected or current local civil day | Same valid date | Morning | `today.md` |
| `tomorrow` | `1.1.0` | `weather-balanced` | Next local civil day | Same valid date | Evening | `tomorrow.md` |
| `hourly` | `1.1.0` | `weather-light` | Rolling six-hour interval | Rolling window | — | `hourly.md` |
| Report ID | Prompt version | Default profile | Period policy | Fixed batch flag | Default output |
| --- | --- | --- | --- | --- | --- |
| `daily` | `2.0.0` | `weather-balanced` | Explicit local civil day | Dynamic Daily inclusion is app-owned | `daily-YYYY-MM-DD.md` |
| `today` | `2.0.0` | `weather-balanced` | Selected or current local civil day | Morning | `today.md` |
| `tomorrow` | `2.0.0` | `weather-balanced` | Next local civil day | Evening | `tomorrow.md` |
| `hourly` | `2.0.0` | `weather-light` | Rolling six-hour interval | — | `hourly.md` |
Each report pairs its ID and prompt version with matching template and schema
IDs. Exact template fields and schema assets belong to [report templates](../templates.md)
and [generated-text internals](generatedtext.md). Prompt assets own default
profile selection; the registry deliberately stores no provider setting. The
[Promptkit integration guide](../integrations/promptkit.md) owns profile
definitions and resolution.
Daily derives its filename from the resolved valid-period start in the effective timezone, so multiple Daily items have distinct destinations. Exact template fields and schema assets belong to [report templates](../templates.md) and [generated-text internals](generatedtext.md). Prompt assets own default profile selection; the registry stores no provider setting.
All valid periods are half-open.
## Collaborators And Boundaries
## Registry collaborators
`DefaultRegistry`, `Lookup`, `Resolve`, and report-name helpers prevent callers from duplicating report identity rules. Registry overrides clone a recognized definition and replace its module list. `DistributorPathTemplates` are consumed by app orchestration; their rendered external bundle-path contract is documented in the [Distributor bundle guide](../integrations/distributor/pkg-bundle.md).
`DefaultRegistry` is the only source of the four report definitions.
`Lookup`, `Resolve`, and report-name helpers prevent callers from duplicating
report identity rules. Registry overrides clone a definition and replace its
module list only after the report ID is recognized.
`morning` and `evening` are registry-owned batch names. Fixed flags declare Today and Tomorrow eligibility; app orchestration determines data-dependent Daily membership and the actual batch plan.
The definition's `DistributorPathTemplates` are internal declarations consumed
by app orchestration. Their rendered external bundle paths and compatibility
contract are documented in the [Distributor bundle guide](../integrations/distributor/pkg-bundle.md), not repeated here.
The registry never collects weather data, parses CLI flags, writes output, executes Promptkit, or delivers a report.
`morning` and `evening` are registry-owned batch names. Registry flags declare
fixed report eligibility; app orchestration determines data-dependent Daily
membership and produces the actual batch plan.
## Module composition and failures
Each definition supplies an ordered `[]module.ConfigItem`; the complete
report-to-module mapping is maintained in [module internals](module.md).
`ArtifactGroup`, `BatchOutputName`, and comparison compatibility
are likewise consumed by state and orchestration rather than recomputed there.
Unknown report IDs or batch names return errors. The registry never collects
weather data, builds modules, parses CLI flags, writes state, executes
Promptkit, or delivers a report.
## Verification and invariants
Focused tests cover definition completeness, command and alias lookup, period
resolution, run IDs, path declarations, composition defaults, and override
validation:
Focused tests cover definition completeness, command and alias lookup, period resolution, run IDs, output names, composition defaults, and override validation:
```sh
go test ./internal/report
```
All report selection goes through the registry, and the registry is the source
of truth for report identity—not rendered report text or app-local constants.

View File

@@ -1,58 +0,0 @@
# State Internals
`internal/state` owns safe workspace paths, atomic artifact writes, metadata,
prior-snapshot lookup, and read-only inspection. Operators should use the
[operations guide](../operations.md) for lifecycle and retention.
## Artifact Paths
For each run, paths are grouped by artifact group and valid start date:
| Artifact | Location |
| --- | --- |
| Module snapshot | `snapshots/<group>/<date>/modules.<run-id>.json` |
| Metadata | `snapshots/<group>/<date>/metadata.<run-id>.json` |
| Data package | `data-packages/<group>/<date>/data_package.<run-id>.yaml` |
| Prompt preparation | `preflight/<group>/<date>/prompt_preparation.<run-id>.json` |
| Prompt execution | `snapshots/<group>/<date>/prompt_execution.<run-id>.json` |
| Raw generated text | `snapshots/<group>/<date>/generated_text_raw.<run-id>.json` |
| Validated generated text | `snapshots/<group>/<date>/generated_text.<run-id>.json` |
| Render context | `snapshots/<group>/<date>/render_context.<run-id>.json` |
| Managed report | `reports/<group>/<date>/report.<run-id>.md` |
| Notification | `notifications/<group>/<date>/distributor.<run-id>.json` |
Batch notification records are `notifications/batches/<batch>/<local-date>/distributor.<batch-run-id>.json`.
## Metadata And Debug Storage
New metadata is `weatherreporter.metadata.v2` and gains preparation and
execution paths only after those artifacts are saved. Legacy V1 records remain
readable; their historic preflight and generated-text-result fields are mapped
to the corresponding preparation and execution views during inspection. New
runs never write V1 records.
Prompt preparation and execution records are validated on both save and load.
They require exact report/prompt identity, complete timing, internally
consistent provenance, and status-appropriate validation or bounded classified
errors. Completed preparation and execution provenance retain the selected
logical profile ID and resolved backend/model, but never profile endpoints or
credentials. Completed execution provenance keeps Promptkit's run identity
distinct from the Weatherreporter run identity.
For a completed prompt run, the execution record is atomically replaced after
each downstream artifact is saved. Its path set therefore records the raw and
normalized generated text, render context, managed report, requested output
copy, and notification artifact actually reached without changing the original
Promptkit outcome.
`PromptDebugWriter` is separate from workspace state. An empty root disables
it. An enabled absolute root is checked for safe directories and symlinks, then
stores `preparation.json` and `execution.json` beneath
`<root>/<report-id>/<valid-date>/<run-id>/`. Directories are `0700`; files are
atomic `0600`. Normal state discovery does not read this root.
Focused checks:
```sh
go test ./internal/state
```

View File

@@ -1,7 +1,7 @@
# Weather Data Internals
`internal/weatherdata` owns the normalized, wire-independent weather bundle
that passes from collection through rendering and persistence. The Weather API
that passes from collection through rendering. The Weather API
adapter translates provider responses into these types; its request, response,
and availability contract is documented in the
[Weather API integration guide](../integrations/weatherapi.md).
@@ -54,8 +54,7 @@ local provenance and whole-run consumers see it. A policy that treats a missing
source as an error returns no partial bundle.
Warnings describe data completeness, not rendering or delivery failures.
Those failures are recorded by the application and state layers; see
[application orchestration](app-orchestration.md) and [state internals](state.md).
Those failures are reported by [application orchestration](app-orchestration.md).
## Boundaries and verification