100 lines
5.3 KiB
Markdown
100 lines
5.3 KiB
Markdown
# Architecture Policy
|
|
|
|
## Purpose
|
|
|
|
This policy defines Weatherreporter's system shape, ownership, dependency direction,
|
|
and safety invariants. The [development guide](../development.md) owns the
|
|
package inventory; focused documents in `docs/internal/` own implementation detail.
|
|
|
|
## System Shape
|
|
|
|
Weatherreporter is a deterministic weather-report CLI. It collects normalized
|
|
weather data, derives facts and modules, builds a curated YAML data package,
|
|
executes exact-version Promptkit prompts, validates structured generated prose,
|
|
and renders repository-owned Markdown in memory. Completed Markdown is
|
|
atomically published to an operator-owned output destination and may then be
|
|
uploaded through Distributor.
|
|
|
|
An explicit profile comparison prepares one report input once, executes the
|
|
same exact prompt and data package across selected profiles concurrently, and
|
|
atomically publishes one operator-owned comparison bundle. It remains local:
|
|
it does not create application state or send a Distributor notification.
|
|
|
|
The supported report products are Daily, Today, Tomorrow, and Hourly. A batch
|
|
collects once, validates its complete candidate prompt/profile set before
|
|
collection, then determines and validates every planned output destination
|
|
before executing reports sequentially with one executor. It continues after
|
|
independent report failures and sends a batch notification only after every
|
|
planned report succeeds.
|
|
|
|
## Ownership And Boundaries
|
|
|
|
- `internal/cli` owns command parsing, help, summaries, and one executor
|
|
construction per action.
|
|
- `internal/config` owns defaults, loading, validation, and secret loading.
|
|
- `internal/app` owns in-memory workflow order, partial results, atomic output
|
|
publication, and notification coordination through project-owned contracts.
|
|
- `internal/comparison` owns comparison identity, durable logical bundle
|
|
validation, safe destination recognition, and atomic bundle publication.
|
|
- Deterministic domain packages own weather derivation, report periods, modules,
|
|
generated-text validation, and template contexts.
|
|
- `internal/adapters/weatherapi`, `internal/adapters/promptkit`, and
|
|
`internal/adapters/distributor` own their external dependency mechanics.
|
|
|
|
Dependency-specific Promptkit types remain inside its adapter. The application
|
|
does not parse flags, construct provider clients, or render provider output
|
|
directly.
|
|
|
|
## Prompt Execution Invariants
|
|
|
|
- Prompts receive curated module packages, never unbounded raw weather payloads.
|
|
- Every execution validates the exact prompt version and output contract before
|
|
collection. The selected profile is configured explicitly or declared by the
|
|
prompt; unsupported direct-key profiles and missing reported credentials fail
|
|
before collection.
|
|
- Prompt and profile validation completes before weather collection. Raw output
|
|
is validated before template rendering.
|
|
- Comparison validates every explicit profile before collection, prepares one
|
|
immutable report input, and delegates backend capacity to Promptkit rather
|
|
than adding an application-wide execution limit.
|
|
- Generated text fills defined prose slots only. Deterministic facts remain
|
|
authoritative and repository-owned templates produce all Markdown output.
|
|
- Sensitive rendered prompts, schemas, input bodies, provider endpoints, and
|
|
credentials never enter normal summaries or logs. They are written only to
|
|
an explicit secure debug root when requested.
|
|
|
|
## Output, Notification, And Testing Invariants
|
|
|
|
- Normal execution is stateless: it keeps weather data, prompt input, generated
|
|
text, and render context in memory and creates no application-owned durable
|
|
state.
|
|
- Markdown writes are atomic at an operator-selected destination. A
|
|
pre-publication failure, including cancellation observed immediately before
|
|
publication, does not replace an existing destination; a notification failure
|
|
does not remove a newly published output.
|
|
- A single-report final destination is either absent or a regular file.
|
|
Symlinks and special filesystem objects are rejected during preflight and
|
|
rechecked immediately before the atomic replacement.
|
|
- Configuration or explicit CLI input selects that operator-owned destination;
|
|
it does not create an application-owned state boundary.
|
|
- Comparison bundles are flat, versioned operator outputs. Their guarded
|
|
replacement accepts only a recognized current bundle; cancellation and every
|
|
pre-publication failure preserve a prior bundle, while individual profile
|
|
failures can publish a complete partial bundle.
|
|
- 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. Batch counters describe report
|
|
outcomes only; a failed batch notification is represented separately at the
|
|
batch level.
|
|
- Comparison never invokes Distributor notification.
|
|
- Profile comparison supports operator review only: it does not score, rank,
|
|
select, resample, or replay profile executions.
|
|
- Default tests are deterministic, offline, and use Promptkit/provider fakes
|
|
rather than live provider calls. See the [testing policy](testing.md).
|
|
|
|
## Non-Goals
|
|
|
|
Weatherreporter is not a weather-data ingestion service, general LLM
|
|
orchestration framework, plugin platform, HTTP service, multi-user job system,
|
|
or a replacement for Promptkit or Distributor.
|