Refresh documentation foundation and repair links

This commit is contained in:
2026-07-31 00:50:48 +00:00
parent 3aaddda676
commit 82acb8dc1a
10 changed files with 1451 additions and 669 deletions

View File

@@ -1,125 +1,212 @@
# Architecture
# Architecture Policy
This document defines the development principles for this Go project. It is inward-facing: developers and LLM coding agents should use it to preserve the projects shape, boundaries, and invariants as the code evolves.
## Purpose
## weatherreporter
`weatherreporter` is a deterministic weather briefing and report-preparation application. It consumes normalized weather data from the internal weatherfeeder-backed API, derives report-specific module snapshots and prompt packages, compares module snapshots against prior runs, and invokes an external prompt runner to produce human-facing reports.
This policy defines Weatherreporter's system shape, normative ownership,
dependency direction, architectural invariants, safety properties, and
non-goals. Developers and coding agents should use it to preserve the
application's boundaries as the implementation evolves.
The application should keep meteorological data selection, daypart grouping, threshold detection, forecast-period resolution, and recent-change comparison inside Go domain packages. LLM prompts should receive curated module-based prompt packages rather than raw unbounded source payloads wherever practical.
The [development guide](../development.md) owns the current package inventory
and contributor workflow. Focused documents under `docs/internal/` own
implemented subsystem mechanics. This policy owns the rules those packages and
mechanics must preserve.
Report types must be defined through a registry or equivalent mechanism. Each report definition should declare its report ID, prompt ID, valid-period resolver, module composition, comparison strategy, and output naming behavior. Avoid scattering report-type conditionals across CLI and orchestration code.
## System Shape
Generated reports must be associated with explicit metadata, including report type, location, generation time, valid period, source product timestamps or hashes, module snapshot path, and output path. Recent Changes must be based on structured snapshot comparison rather than comparison of rendered Markdown report text.
Weatherreporter is a deterministic weather briefing and report-preparation CLI.
It consumes normalized weather data, derives report facts and module snapshots,
builds curated prompt packages, compares structured snapshots with prior runs,
invokes Scriptorium for bounded generated text, renders managed Markdown
reports, persists inspectable artifacts, and can upload completed reports
through Distributor.
`scriptorium` is an external adapter, not domain logic. Subprocess execution must be isolated under `internal/adapters/scriptorium`, use context-aware execution, avoid shell interpolation, capture actionable stderr, and keep scriptorium-specific flags from leaking into domain packages.
The application is intentionally a small, explicit, dependency-light Go
program. Add abstraction only when it protects a real boundary, makes an
important invariant testable, or supports an implemented extension point.
`distributor` is also an external adapter. Upload behavior must be isolated
under `internal/adapters/distributor`, dependency types from the distributor
module must not leak outside that adapter, and the selected upload source must
be the managed Markdown report rather than optional output copies or broad
workspace scans.
The primary flow is:
## Project Shape
1. CLI parsing and configuration resolution;
2. report or batch resolution;
3. normalized weather collection;
4. deterministic fact derivation and module construction;
5. structured prior-snapshot comparison;
6. curated prompt input and generated-text processing;
7. managed Markdown rendering and metadata persistence; and
8. optional notification using managed report artifacts.
Default to a small, explicit, dependency-light Go application. Keep the design modular enough to test and change safely, but do not add abstraction unless it protects a real boundary or enables a real extension point.
Inspection is a separate read-only flow over persisted state. It must not
collect weather data, invoke Scriptorium, or upload reports.
Business/domain logic should live outside CLI, transport, and external-adapter packages.
## Ownership And Dependency Direction
### Entry Point And CLI
The binary entry point should do no business work beyond constructing and
running the CLI. CLI code owns commands, arguments, flags, help, output
formatting, and conversion into application requests.
CLI packages must not own meteorological decisions, report composition,
artifact layout, Recent Changes comparison, external transport, or subprocess
construction.
### Configuration
Configuration loading, built-in defaults, overrides, secret loading, and
validation belong to `internal/config`. Operational values shared across
packages must be explicit configuration or constants owned by the responsible
package, not hidden in CLI or adapter code.
The exact configuration contract belongs in the
[configuration reference](../config.md). Other architecture documents should
state ownership and safety rules rather than repeat fields, defaults, or
precedence.
### Application Orchestration
`internal/app` owns top-level use cases and workflow order. It composes report
resolution, collection, domain transformations, state, rendering, and optional
notification through narrow project-owned contracts.
The application layer may coordinate components and convert between their
contracts. It must not absorb CLI parsing, HTTP transport, subprocess argument
construction, filesystem layout, weather derivation algorithms, template
execution, or adapter-specific dependency types.
### Domain And Report Logic
Meteorological selection, forecast-period resolution, daypart grouping,
threshold detection, fact derivation, report composition, module construction,
generated-text validation, and Recent Changes comparison belong in deterministic
Go domain packages.
Domain packages must not depend on CLI parsing, process execution, remote
transport, or concrete external-library types. Given the same normalized
inputs, configuration, valid period, prior snapshot, and clock, domain behavior
should be reproducible.
Report selection must go through the report registry or an equivalent
centralized mechanism. A report definition owns its identity, prompt and
rendering mode, valid-period resolver, module composition, comparison strategy,
artifact grouping, and output naming. Do not scatter report-ID conditionals
through CLI, orchestration, or adapters.
### External Adapters
External integrations use adapter boundaries under `internal/adapters`.
Adapters own transport and protocol mechanics; application and domain packages
own decisions.
- The Weather API adapter owns HTTP request construction, timeouts, retries,
response-envelope handling, decoding, and endpoint compatibility.
- The Scriptorium adapter owns argument construction, context-aware subprocess
execution, stdout and stderr capture, exit interpretation, and result
decoding. It must avoid shell interpolation.
- The Distributor adapter owns dependency-specific bundle and upload types,
client construction, request execution, status handling, and redaction.
External dependency types must not leak beyond the adapter that integrates
them. Adapters should expose narrow project-owned inputs and outputs so an
integration can be tested or replaced without changing domain logic.
### State And Embedded Assets
`internal/state` owns managed workspace paths, durable metadata, atomic
artifact persistence, prior lookup, and inspection reads. Other packages should
request state operations rather than reconstruct managed paths independently.
Schemas, prompts, Markdown templates, and partials should live as separate
repository assets and be embedded by the package that owns their execution or
lookup. Keep weather derivation and path construction out of templates.
## Architectural Invariants
### Weather Truth And Generated Text
- Normalized source data and deterministic Go derivation are authoritative for
weather facts.
- LLM prompts receive curated module-based packages rather than raw,
unbounded source payloads.
- Generated text is limited to defined prose slots, validated before use, and
rendered through typed or otherwise explicit contexts.
- Templates arrange validated prose and deterministic facts; they do not
perform meteorological derivation.
### Reports And Comparison
- Report behavior is resolved through centralized definitions.
- Recent Changes is computed from structured module snapshots, never by
comparing rendered Markdown.
- Batch workflows collect normalized weather data once and reuse that
collection for planning and report generation.
- Report metadata links identity, generation time, valid period, source
provenance, and the managed artifacts produced for the run.
### Managed State And Notification
- Durable structured writes are atomic where practical.
- Managed paths remain beneath the configured workspace root.
- Operations that delete, move, overwrite, or copy files use narrow, explicit
paths; destructive cleanup is opt-in.
- Intermediate artifacts reached before a later failure remain inspectable
where practical.
- Distributor uploads use managed Markdown reports, never optional output
copies or broad workspace scans.
- Notification occurs only after the managed report and required metadata have
been successfully produced.
### Security, Errors, And Cancellation
- Secrets must not appear in logs, errors, persisted artifacts, examples, or
user-facing output.
- Errors preserve actionable operation, report, RunID, path, endpoint, or
subprocess context without exposing secrets or unnecessarily large payloads.
- External calls, subprocesses, storage operations, and multi-step workflows
accept or propagate `context.Context` where cancellation or timeout is
meaningful.
- Adapter failures preserve useful status, stderr, or response context at the
boundary and are translated into project-owned errors before crossing into
unrelated packages.
## Dependency Policy
Prefer the Go standard library where practical.
Prefer the Go standard library. Add an external dependency only when it
materially improves correctness, security, interoperability, or
maintainability. A dependency used for a small convenience does not justify its
lifetime upgrade and compatibility cost.
Use external dependencies only when justified by correctness, security, interoperability, or substantial complexity reduction. Good reasons include complex security-sensitive behavior, such as HTML sanitization, or widely used de facto standards, such as YAML parsing.
Keep dependency-specific types inside the package that intentionally adopts
the dependency. The application should remain understandable and testable
without requiring framework-wide abstractions or live external services.
Avoid dependencies for small conveniences. Do not let external dependency types leak across internal package boundaries unless the dependency is itself the explicit public contract of that package.
## Verification And Documentation
## Package Layout
Core behavior must be testable without live Weather API, Scriptorium, or
Distributor services. The [testing policy](testing.md) owns test philosophy,
sufficiency, boundaries, and test-double guidance.
Use this layout unless the project has a documented reason to differ:
Documentation must follow the
[documentation policy](documentation.md). Update the canonical user,
operator, integration, internal, and example documentation in the same change
as the behavior it describes. Future or proposed behavior belongs under
`docs/roadmap/`; significant durable decisions may be recorded as ADRs.
- `internal/app`: application orchestration and top-level use cases.
- `internal/cli`: CLI command definitions, flags, argument parsing, and command wiring.
- `internal/config`: configuration structs, defaults, loading, precedence, and validation.
- `internal/adapters/<name>`: adapters for external CLIs, APIs, databases, object stores, or libraries.
- `internal/api`: HTTP API handlers and request/response types, when the application exposes an HTTP API.
- `internal/transport/http`: HTTP client code, when the application calls HTTP services.
## Non-Goals
Package-private implementation constants may live near the package that owns them, preferably in `constants.go` when useful.
Weatherreporter is not:
## Configuration
- a source weather-data ingestion or normalization service;
- a general-purpose LLM orchestration framework;
- an application in which an LLM selects authoritative weather facts or report
policy;
- a plugin framework with dynamically discovered report or module behavior;
- an HTTP service or multi-user distributed job system;
- a replacement for Scriptorium or Distributor protocol ownership; or
- a system that hides operational state exclusively inside opaque logs or
remote services.
Centralize configuration loading, processing, precedence, defaults, and validation in `internal/config`.
The goal is to make configuration discoverable and avoid implicit or hidden operational values. User-visible defaults and cross-package operational defaults should be defined in `internal/config/defaults.go`.
Configuration precedence is:
1. CLI flags
2. configuration file
3. built-in defaults
Prefer YAML configuration unless the project has a strong reason to use another format. Config files should be discovered at `/usr/local/etc/<app_name>/config.yml`, with a CLI override via `--config`.
Configuration files should not contain raw secrets unless the application is explicitly designed for that. Prefer environment variables or secret files for secrets. File-backed secrets are loaded through `secrets.directory`; secret values must not be logged, persisted, or included in user-facing output.
## Adapters and External Integrations
Use a hexagonal architecture style for external integrations.
External adapters belong under `internal/adapters/<name>`. If an adapter uses an external dependency, that dependencys interface must not leak outside the adapter package. Other packages should interact only with the adapters API, so the dependency can be swapped, upgraded, or removed without touching unrelated code.
Adapters should be thin. Domain decisions belong in application/domain packages, not inside adapter glue.
## Components and Registries
When the application has major workflow components, each component should live
near the package that owns its contract and have explicit inputs and outputs.
The orchestrator should compose components in an explicit order using a default
sequence, dependency graph, or documented orchestration rule.
If users can select components, validators, renderers, or adapters, selection
should go through a registry or equivalent mechanism rather than scattered
conditionals.
## Embedded Assets
Store embedded JSON schemas, Markdown prompts, templates, and similar assets as separate files, not inline string literals, unless there is a strong reason otherwise.
## Errors and Logging
Errors should be actionable and preserve context. Wrap errors with operation and path/resource context. CLI code should convert internal errors into concise user-facing messages.
Errors and logs must not expose secrets.
Use structured logging where practical. Logs should describe operations, paths, external calls, retries, and failure causes, but should not include large user data by default.
## Context, Timeouts, and Cancellation
Long-running operations should accept `context.Context`. External calls,
subprocesses, HTTP requests, storage operations, and multi-step workflows should
respect cancellation and timeouts.
## State, Files, and Safety
If the application writes durable state, writes should be atomic where
practical. Multi-step workflows should preserve enough state to support
inspection and retry diagnosis after failure.
Code that deletes, moves, or overwrites files must use narrow, explicit paths. Avoid broad parent-directory operations. Cleanup that can cause data loss must be opt-in.
## Testing
Core logic should be testable without real external services. Use fakes, fixtures, or local test doubles for adapters where practical.
Config examples should be load-tested. Important CLI workflows should have
parser or command tests. Component contracts should have focused tests that do
not require running the full application unless end-to-end coverage is
intentional.
## Documentation
Documentation should follow the project documentation policy. Keep user docs focused on implemented behavior. Put future, planned, or aspirational work only under `docs/roadmap/`.
When changing architecture, config, CLI behavior, adapters, or component
contracts, update the relevant docs and examples in the same change.
New requirements may justify revisiting a non-goal. A change that alters system
shape, dependency direction, a safety property, or another architectural
invariant should be recorded deliberately in this policy or an ADR rather than
introduced implicitly.