Plan the stateless execution refactor

This commit is contained in:
2026-08-01 19:16:44 +00:00
parent 7d591487e4
commit 7f5a9c0357
3 changed files with 1027 additions and 306 deletions

View File

@@ -1,39 +1,38 @@
# Ephemeral Operational State Roadmap # Stateless Execution Roadmap
Status: Accepted feature direction; implementation has not started. Status: Accepted.
## Purpose ## Purpose
Weatherreporter should treat generated weather reports and their intermediate Weatherreporter should be a stateless report transformation pipeline. Each
artifacts as short-lived operational material rather than a durable audit invocation fetches current inputs from the Weather API, derives deterministic
history. Forecasts and current conditions change continuously, and the normal facts, executes Promptkit, renders Markdown, and writes or distributes the
response to an old or failed report is to generate a new report, not to completed report. It does not retain application-owned history or operational
reconstruct the provenance of the old one. state between invocations.
The application should retain only the bounded state needed to publish the Weather reports are ephemeral products rather than business records. Forecasts
current report, calculate Recent Changes against the last successfully and current conditions change continuously, and the normal response to an old
published report for the same valid period, and complete the current or failed report is to generate a new one rather than recover, replay, or
invocation safely. Detailed LLM diagnostics should remain an explicit, inspect the prior generation.
operator-controlled exception outside ordinary workspace state.
This roadmap defines the intended state lifecycle, compatibility policy, and This roadmap defines the desired lifecycle, output contract, compatibility
architectural boundaries. A separate implementation plan will define the policy, and architectural boundaries.
ordered work after the roadmap is complete.
## User Intent ## User Intent
The state model should reflect these product expectations: The target design reflects these product expectations:
- weather reports are ephemeral products, not business records; - each invocation is independent and requires no prior Weatherreporter state;
- old report provenance has no continuing operational value once conditions - routine operation creates only the requested report outputs;
and forecasts have changed; - reports are written somewhere useful even when the operator omits an
- regenerating is preferable to recovering, replaying, or inspecting an old explicit output flag;
generation; - Weatherreporter does not maintain forecast history merely to compare runs;
- routine operation should not accumulate unbounded run-addressed artifacts; - regenerating replaces a same-named output atomically instead of creating an
- Recent Changes remains useful, but needs only one prior successful snapshot archive;
for the same report and valid period; and - Distributor receives the completed report produced by the current
- sensitive prompt and response capture remains opt-in and explicitly managed invocation; and
by the operator. - sensitive diagnostics are retained only through an explicit,
operator-controlled debug option.
## Current State ## Current State
@@ -41,337 +40,286 @@ Each generation currently writes a run-addressed collection containing a
module snapshot, data package, prompt preparation receipt, prompt execution module snapshot, data package, prompt preparation receipt, prompt execution
receipt, raw generated text, validated generated text, render context, managed receipt, raw generated text, validated generated text, render context, managed
report, metadata, and optional notification receipt. Successful and failed report, metadata, and optional notification receipt. Successful and failed
runs accumulate beneath the workspace. runs accumulate beneath the configured workspace.
Metadata links the collection and supports lookup by RunID. The CLI can list Metadata links these artifacts and supports lookup by RunID. The CLI can list
historical runs and inspect their metadata, modules, data packages, prior historical runs and inspect their metadata, modules, data packages, prior
snapshots, and source provenance. New metadata uses the V2 format while the snapshots, and source provenance. The reader retains V1 compatibility while
reader retains V1 compatibility. Prompt artifacts are validated against new runs write V2 metadata.
current report and prompt definitions when saved and loaded.
Most of this persistence exists for retrospective inspection and failure Weatherreporter also loads a compatible prior module snapshot for Daily,
recovery. Dedicated prompt preparation and execution load operations have no Today, and Tomorrow and compares it with the current snapshot. Configurable
ordinary production consumer. The important exception is module snapshot thresholds determine whether structured Recent Changes are included in the
state: generation actively loads the most recent compatible snapshot to build Promptkit data package. This is the only current product behavior that depends
the deterministic Recent Changes input for Daily, Today, and Tomorrow. on state from an earlier invocation.
## Desired End State ## Desired End State
Weatherreporter has three distinct state classes: Weatherreporter has no durable application-managed workspace. Its dataflow is:
| State class | Lifecycle | Purpose | ```text
| --- | --- | --- | Weather API input
| Invocation workspace | Temporary and unpublished | Hold intermediate values while one report or batch is running. | -> deterministic facts and modules
| Current published state | Bounded and replaceable | Hold the current managed report and the minimal deterministic snapshot or manifest needed for normal operation. | -> Promptkit data package and generated text
| Secure LLM debug capture | Explicitly enabled and operator-managed | Diagnose prompt rendering or provider output when the operator deliberately requests sensitive capture. | -> repository-owned Markdown rendering
-> operator-owned report output
-> optional Distributor upload
```
Ordinary generation uses an invocation-scoped temporary directory on the same Intermediate values remain in memory wherever practical. A narrowly scoped
filesystem as the managed workspace when atomic publication requires it. temporary file may be used when an external interface requires a file path,
Prompt preparation, prompt execution, raw generated text, validated generated but it exists only for the active invocation and is removed on return.
text, render contexts, data packages, and notification receipts may exist Temporary material is not a supported recovery or inspection surface.
there while needed, but they are not published as durable historical
artifacts.
A successful report atomically replaces the current published state for its RunIDs may remain as in-process correlation identifiers in action summaries,
logical report key and valid period. A failed attempt leaves the last errors, Distributor idempotency values, and explicit debug paths. They do not
successfully published report and comparison snapshot unchanged. Ordinary identify a collection that Weatherreporter can locate or decode later.
temporary artifacts are removed after both success and handled failure;
cleanup failure is reported safely but must not replace the primary generation
error.
RunIDs remain useful as in-process correlation identifiers in action results, Configuration files, operator-owned report outputs, and explicitly requested
logs, provider provenance, and optional debug paths. They no longer identify a debug captures are inputs or outputs, not Weatherreporter state.
durable collection that Weatherreporter promises to locate or decode later.
## Published Report Policy ## Report Output Contract
The managed Markdown report remains the authoritative upload source during an Every successful report generation writes one operator-owned Markdown output.
invocation. The intended default is to retain only the current managed report An explicit output option selects its destination. When no explicit destination
for each logical report key and valid period, replacing it atomically after a is supplied, Weatherreporter uses the process working directory captured at
new report has been fully rendered and validated. invocation start.
An explicit `--out` or `--out-dir` copy remains operator-owned output outside Default single-report filenames are:
the managed-state lifecycle. Weatherreporter does not delete, rotate, or
rewrite those copies except when the same explicit destination is selected by
a later invocation.
Distributor continues to receive only a completed managed Markdown report. | Report | Default output |
Notification success or failure does not create a durable notification | --- | --- |
history. A notification failure leaves the newly published report available | Daily | `daily-YYYY-MM-DD.md`, using the report's valid local date |
and returns a safe error through the current action result. | Today | `today.md` |
| Tomorrow | `tomorrow.md` |
| Hourly | `hourly.md` |
## Recent Changes State `--out PATH` replaces the default destination for `generate`; it no longer
means an extra copy of a separately managed report. Relative paths are resolved
from the invocation's working directory.
Recent Changes must be preserved without preserving general report history. For `run`, `--out-dir PATH` selects the report-output directory and the current
For Daily, Today, and Tomorrow, Weatherreporter retains at most one compatible working directory is the default when it is omitted. Existing batch filenames
module snapshot for each logical report key and valid period. remain: `today.md`, `tomorrow.md`, and `daily-YYYY-MM-DD.md`. Successful items
in a partially failed batch retain their outputs.
The retained snapshot represents the last successfully published report. A Output publication is atomic. A completed generation may atomically replace an
new invocation reads it before constructing Recent Changes and replaces it existing file at the selected path, but a failed or canceled generation must
only when the new managed report has been successfully validated, rendered, not truncate or partially replace it. Weatherreporter does not rotate, archive,
and published. A failed generation therefore does not become the baseline for expire, or otherwise manage an output after publication.
the next report and cannot hide changes that the user has not yet seen.
Hourly does not currently use the comparison strategy and should not retain a The JSON action summary reports the final output path. It does not expose paths
comparison snapshot solely for symmetry. State whose valid period has ended to transient intermediates. `--quiet` continues to suppress the action summary,
and can no longer participate in a supported comparison is eligible for safe not report creation.
cleanup.
## Temporary Workspace And Failure Semantics ## Distributor Contract
Temporary state must remain beneath a narrowly owned application directory and Distributor uploads use the completed Markdown output from the active
use safe path construction, restrictive permissions where content is invocation. There is no separate durable managed-report copy and no workspace
sensitive, and atomic writes where practical. Publication must not expose a scan.
partially rendered report or a snapshot that does not correspond to the
published report.
Normal results retain bounded error information and paths only for artifacts For a single report, local output publication completes before notification.
that remain meaningful after the command: a previously or newly published A notification failure leaves the report output intact and returns a safe
report, an explicit operator output, or an enabled secure debug capture. error through the active result. It does not create a notification receipt.
Temporary intermediate paths are not emitted as if they were durable recovery
locations. A failed command is retried by starting a new generation.
Process interruption may leave an uncommitted temporary directory. Such a Batches continue to suppress per-report notification and attempt their
directory is never considered published state, is never selected for Recent batch-level upload only after every planned report succeeds. A report failure
Changes, and may be removed by a documented safe cleanup mechanism. Cleanup leaves other successful output files intact, skips the batch upload, and
must distinguish inactive temporary directories from concurrent active returns an aggregate failure. Distributor status remains active-workflow
invocations and must never recursively target the workspace root or an information rather than retained Weatherreporter history.
unresolved configuration path.
## Inspection And Metadata Policy ## Recent Changes Deprecation And Removal
Run-history discovery and inspection are not part of the desired product The local Recent Changes feature is deprecated by this accepted direction and
contract. The historical `inspect reports`, `inspect metadata`, `inspect is removed when the stateless execution change lands. Its low practical value
modules`, `inspect data-package`, `inspect prior`, and `inspect sources` does not justify retaining a historical state subsystem.
surfaces are candidates for removal together rather than preservation through
a new storage representation.
Any manifest retained for atomic publication or Recent Changes is current Removal includes:
operational state, not an archival metadata record. It should contain only the
identity, valid period, safe paths, and deterministic snapshot information
needed to validate and use that current state. It does not need to preserve
prompt messages, generated prose intermediates, source provenance, provider
provenance, notification history, or a catalog of prior runs.
The application does not promise cross-version decoding of ordinary workspace - prior-snapshot discovery and compatibility rules;
state. A new release may replace or ignore incompatible current-state files, - the `internal/changes` comparison implementation;
provided it fails safely, never mistakes stale state for a compatible Recent - report-registry comparison strategies and compatible-prior declarations;
Changes baseline, and documents any operator action required during upgrade. - `recent_change` configuration and threshold validation;
- Recent Changes values in application results, prompt inputs, fixtures, and
tests;
- the `recent_changes` Promptkit data-package stanza; and
- prompt instructions that refer to supplied recent changes.
## Prompt Execution And Debugging Removing the prompt-input field is a breaking prompt contract change. The data
package schema advances from `weatherreporter.data_package.v3` to
`weatherreporter.data_package.v4`, and all four prompt definitions advance from
version `1.1.0` to `2.0.0` together.
Generated-text schemas and report templates do not change; neither has a
direct dependency on Recent Changes.
Weatherreporter does not retain an empty compatibility field and does not keep
a local fallback comparator. Reports simply omit change commentary after this
feature is removed.
A future upstream Weather API change product may allow Weatherreporter to
reintroduce structured change commentary without local state. That work is
recorded in [Future Roadmap](future.md#upstream-forecast-change-product) and is
not a prerequisite for this refactor.
## Debugging
Prompt inspection before weather collection and prepared execution remain Prompt inspection before weather collection and prepared execution remain
runtime safety requirements. They do not require durable preparation or runtime safety requirements. Preparation details, effective profile and model,
execution receipts. validation outcomes, source warnings, and safe errors remain available to the
active workflow and its action summary where useful.
The selected logical profile, effective backend and model, validation outcome, The existing `--llm-debug-dir PATH` option remains the explicit exception to
and safe classified error remain available to the active workflow and its CLI stateless output. When supplied, it may retain rendered prompts, schemas, input
summary where useful. Weatherreporter does not retain them as long-term report bodies, generated bodies, and effective parameters according to its secure
provenance after the invocation completes. capture contract. The operator selects and manages that location;
Weatherreporter does not clean or archive it. Credentials remain excluded.
The existing explicit secure debug root remains outside ordinary state and may Adding a broader logging framework or an implicit persistent debug directory
retain rendered prompts, schemas, input bodies, generated bodies, and effective is outside this feature. A future rename or generalization to `--debug` should
parameters according to its documented contract. Weatherreporter does not be considered separately so this state refactor does not expand the sensitive
automatically clean that operator-selected location. Credentials must remain capture contract incidentally.
excluded from debug capture.
## Removed State And Inspection Contracts
The target removes:
- the `workspace` configuration section and its directory settings;
- durable module snapshots, data packages, preparation and execution receipts,
raw and validated generated text, render contexts, run metadata, managed
reports, and notification receipts;
- historical artifact path fields from action results and summaries;
- V1 and V2 metadata models, readers, validators, and compatibility behavior;
- state lookup, prior selection, and run-history discovery; and
- `inspect reports`, `inspect metadata`, `inspect modules`,
`inspect data-package`, `inspect prior`, and `inspect sources`.
No replacement inspection command or current-state manifest is introduced.
The active action summary, final output, command error, and opt-in debug capture
are the supported diagnostic surfaces.
State-independent atomic file helpers may remain outside a state abstraction.
The target architecture should not preserve `internal/state` merely as a
compatibility wrapper after its state responsibilities disappear.
## Compatibility And Upgrade Policy ## Compatibility And Upgrade Policy
This is an intentional breaking change to the workspace and inspection This is an intentional breaking change to the CLI, configuration, prompt-input,
contracts. Weatherreporter does not need to migrate historical V1 or V2 workspace, and inspection contracts. Weatherreporter does not migrate old V1
metadata, prompt receipts, intermediate generated-text artifacts, or managed or V2 metadata or other historical artifacts.
reports into the new representation.
Legacy workspace trees must not be silently interpreted as current published Legacy workspace trees are ignored. Weatherreporter must not discover,
state. They also must not be deleted automatically merely because a new interpret, or automatically delete them. Release notes and operations
version starts: an operator may have placed or referenced files there despite documentation identify the obsolete configuration and commands and provide a
the absence of a continuing application compatibility promise. Release notes precise manual cleanup procedure for operators who want to remove the legacy
and operations documentation must explain whether legacy data can be removed workspace.
manually and identify the exact safe target.
The change should land in a release whose notes clearly identify removed CLI Existing report files explicitly written through `--out` or `--out-dir` remain
commands, obsolete paths and schemas, the new bounded state behavior, and any operator-owned and are never treated as legacy workspace material.
upgrade action. Because Weatherreporter remains pre-1.0, the ordinary semantic
version policy may carry this breaking change without inventing a migration The change should land in a release whose notes identify the removed Recent
framework. Changes behavior, configuration fields, inspection commands, artifact paths,
and metadata compatibility; the new default output destinations; and any
operator action required during upgrade.
## Required Architecture Decision Record ## Required Architecture Decision Record
The implemented feature must include an Accepted ADR recording the durable The target state includes an Accepted ADR recording the durable decision to
architectural decision to use ephemeral operational state. The ADR is not part make Weatherreporter stateless.
of this roadmap-writing pass and should not be created until implementation is
being prepared.
The ADR should record: The ADR should record:
- the mismatch between run-addressed provenance storage and the ephemeral - the mismatch between run-addressed provenance storage and ephemeral weather
weather-report lifecycle; reports;
- the decision to retain bounded current report and comparison state rather - the decision to remove local change detection rather than retain state for a
than historical runs; rarely used report section;
- the distinction between temporary invocation state, published operational - the transformation-pipeline model and operator-owned output boundary;
state, explicit output copies, and secure debug capture; - the absence of historical inspection and backward-compatibility guarantees;
- the removal of historical inspection and backward-compatibility guarantees; - atomic output and failure behavior;
- atomic publication and failed-run behavior; - the separation of explicit debug capture from ordinary execution;
- the alternatives considered, including retaining the current archive, - the upstream-service path for any future forecast comparison; and
adding time-based retention, or keeping a bounded run history; and - alternatives considered, including the former bounded-current-state design,
- consequences for CLI compatibility, workspace layout, testing, operations, time-based retention, and a bounded run history.
and future schema changes.
Once accepted, the ADR owns the decision rationale. The architecture policy Once accepted, the ADR owns the rationale. Architecture owns the resulting
owns the resulting current invariant, while focused state, CLI, operations, stateless invariant, while CLI, operations, configuration, integrations, and
and integration documents own the implemented contracts. focused internal documents own implemented contracts.
## Scope ## Scope
The completed feature includes: The completed feature includes:
- an invocation-scoped temporary workspace for intermediate generation state; - removal of local Recent Changes and all prior-run dependencies;
- atomic publication of the current managed report and its minimal operational - removal of the durable workspace, artifact persistence, metadata
state; compatibility, and historical inspection surfaces;
- a bounded comparison snapshot representing the last successfully published - in-memory or invocation-temporary processing with safe cleanup;
report for each supported report key and valid period; - atomic operator-owned output for every successful report;
- safe cleanup behavior for normal completion, handled failure, and abandoned - current-working-directory defaults and explicit output overrides;
temporary workspaces; - preservation of report generation, batch membership, Promptkit execution,
- removal of durable prompt preparation, prompt execution, generated-text, Distributor delivery, action summaries, and opt-in secure debug capture;
render-context, data-package, notification, and run-metadata history; - removal or simplification of state-only packages, fields, configuration,
- removal of run-history inspection commands and their application/state fixtures, tests, and documentation;
contracts; - exact-version prompt updates for the breaking input-contract change;
- removal of V1 metadata compatibility and current-version coupling for - deterministic offline tests for output atomicity, failure isolation, default
historical prompt artifacts by removing the historical artifact contract; path selection, Distributor sequencing, and absence of durable state;
- preservation of active-command partial status, safe errors, and paths to - an Accepted ADR documenting the decision; and
genuinely retained published, operator-owned, or debug outputs; - canonical documentation describing the implemented contract and clear
- preservation of explicit output copies, Distributor upload behavior, and release-note requirements for the release that publishes it.
opt-in secure LLM debug capture;
- risk-appropriate offline tests for atomic publication, comparison baselines,
failure isolation, cleanup safety, concurrent invocation safety, and absence
of unbounded state growth;
- an Accepted ADR documenting the architectural decision; and
- updates to canonical architecture, CLI, operations, configuration,
integration, internal, testing, and release documentation
where their contracts change.
## Non-Goals ## Non-Goals
This feature does not include: This feature does not include:
- a general-purpose cache, database, archival service, or retention engine; - the future upstream forecast-change API or reintroduced change commentary;
- replaying or resuming interrupted generation; - a cache, database, archive, retention engine, manifest, or resume mechanism;
- migrating legacy artifacts into the new representation; - migration or automatic deletion of legacy workspace artifacts;
- retaining a bounded number of historical runs for convenience; - retaining a bounded report or snapshot history;
- automatic upload or archival of state to remote storage; - changing weather derivation, report periods, report membership, generated
- collecting additional provider telemetry or weather-source provenance; prose schemas, profile selection, or the provider model ladder;
- changing report content, prompt text, schemas, profile selection, weather - changing Distributor's remote API or bundle-content contract;
derivation, or batch membership; - deleting or managing operator-owned report and debug outputs;
- deleting operator-owned `--out`, `--out-dir`, or secure debug files; - a general logging or observability subsystem; or
- changing Distributor's report-content contract; or - live external services in the default test suite.
- making live external services part of the default test suite.
## Safety And Testing Policy ## Safety And Testing Policy
The state refactoring must preserve Weatherreporter's existing path-safety and Tests should emphasize observable stateless behavior rather than removed file
atomicity expectations while reducing the amount of durable state. Tests choreography. Important risks requiring durable offline coverage include:
should emphasize observable lifecycle guarantees rather than private file
choreography.
Important risks requiring durable offline coverage include: - a failed or canceled generation truncating or replacing an existing output;
- default paths resolving somewhere other than the invocation working
directory;
- Daily output using the wrong valid local date;
- a batch item overwriting another planned output;
- a notification attempt occurring before its report output is complete;
- one batch failure deleting or corrupting another report's successful output;
- summaries exposing nonexistent transient paths;
- temporary files surviving an ordinary success or handled failure;
- default operation recreating a workspace or historical artifact tree; and
- debug capture leaking credentials or being created without explicit opt-in.
- a failed or canceled generation replacing a previously published report or Tests remain deterministic, offline, credential-free, and use real temporary
comparison baseline; directories plus narrow external-boundary fakes. Existing tests whose only
- a partially written report becoming visible as current; purpose is to preserve removed state, metadata, inspection, or Recent Changes
- Recent Changes selecting an incompatible report, valid period, or failed contracts should be deleted rather than translated into assertions about
attempt; private replacement mechanics.
- cleanup deleting published, operator-owned, debug, or concurrently active
files;
- batch partial success corrupting the state of another report;
- notification failure rolling back or obscuring a successfully published
report;
- stale or incompatible current state being treated as valid; and
- repeated successful and failed runs causing unbounded ordinary workspace
growth.
Tests remain deterministic, offline, credential-free, and based on real
temporary filesystems plus narrow external-boundary fakes. Race-enabled tests
are required where publication, cleanup, or concurrent invocation behavior
shares mutable filesystem state.
## Relationship To Domain-Specific Profiles
The implemented domain-specific profiles do not add historical compatibility
or durable-provenance commitments. Profile inspection, selection, override
precedence, and effective model resolution remain active-workflow behavior and
survive the state change. Existing prompt artifacts need not remain readable
after this refactor and must not constrain the target architecture.
## Completion Criteria ## Completion Criteria
The roadmap's target state is achieved when: The target state is achieved when:
- ordinary runs no longer create durable run-addressed artifact collections; - a clean invocation requires no prior Weatherreporter-created files;
- a successful report atomically replaces only the corresponding current - ordinary runs leave only their selected Markdown outputs;
published state; - omitted output flags resolve to the documented filenames in the current
- failed and canceled attempts leave the prior published report and Recent working directory;
Changes baseline unchanged; - failed and canceled attempts preserve any existing destination file;
- Daily, Today, and Tomorrow compare against at most one compatible snapshot - no local prior-run comparison or Recent Changes contract remains;
from the last successfully published report; - no workspace configuration, run-history command, metadata compatibility, or
- expired comparison and published state can be removed safely without durable intermediate-artifact contract remains;
touching operator-owned or active files; - Distributor uses only completed current-invocation outputs;
- Hourly does not retain an unused comparison snapshot; - debug files are created only through explicit secure capture;
- historical inspection commands and V1/V2 archival compatibility code are - repeated successful and failed runs do not create application-owned history;
removed; - the test suite proves the stateless, atomic-output, batch, notification, and
- temporary, published, explicit-output, and debug paths have distinct and security boundaries offline;
documented ownership and cleanup rules; - an Accepted ADR records the architectural decision; and
- Distributor and active-command summaries continue to receive the completed
report and safe status information they require;
- the default suite proves atomicity, bounded growth, cleanup safety, batch
isolation, and comparison correctness offline;
- an Accepted ADR records the architectural decision and alternatives; and
- canonical current-state documentation describes only the implemented - canonical current-state documentation describes only the implemented
lifecycle. stateless lifecycle.
## Open Questions
### Lifetime of the current managed report
Recommendation: retain one current managed report per logical report key and
valid period until it is replaced or its valid period expires. This preserves
the current default behavior for invocations without `--out` while bounding
growth.
Alternative: treat the managed report as temporary and retain output only when
the operator supplies `--out` or `--out-dir`. This minimizes state further but
makes a successful default invocation produce no durable report for the user
and complicates Distributor sequencing.
### Historical inspection replacement
Recommendation: remove the run-history inspection commands without adding a
replacement initially. Current command summaries, current managed files, and
opt-in debug capture cover the remaining supported workflows.
Alternative: add a narrow `inspect current REPORT` command backed only by the
current operational manifest. This provides discoverability without history,
but it creates a new public surface and may preserve metadata complexity that
the refactor is intended to remove.
### Abandoned temporary workspace cleanup
Recommendation: use an explicitly owned temporary subtree with per-invocation
ownership markers and a conservative age threshold. Normal cleanup removes the
current invocation synchronously; opportunistic cleanup removes only marked,
inactive directories old enough that they cannot reasonably belong to a live
invocation.
Alternative: perform only synchronous cleanup and document manual removal of
directories left by process termination. This minimizes destructive code and
concurrency risk, but crashed processes can still accumulate unbounded files.
### Legacy workspace cleanup
Recommendation: ignore legacy run-addressed trees and document a precise,
manual one-time cleanup procedure. Do not automatically delete them during
startup or upgrade.
Alternative: add an explicit cleanup command that previews and then removes
recognized legacy artifacts. This is more convenient for large installations
but introduces a destructive command and a legacy-format classifier that must
be maintained and tested.

View File

@@ -3,6 +3,40 @@
This roadmap contains future work only. Each section identifies its planning This roadmap contains future work only. Each section identifies its planning
status; current behavior is documented outside `docs/roadmap/`. status; current behavior is documented outside `docs/roadmap/`.
## Upstream Forecast Change Product
Status: Proposed upstream feature request; unimplemented.
Weatherreporter's local Recent Changes feature is deprecated for removal by
the accepted [stateless execution roadmap](ephemeral-state.md). Forecast
version history and comparison are better owned by the Weather API, where the
underlying forecast issuances can be retained and compared consistently for
all consumers.
A future Weather API feature should expose a structured change product with:
- explicit current and baseline forecast issuance timestamps or identifiers;
- documented baseline selection, such as a requested comparison timestamp,
preceding issuance, or fixed rolling period;
- location, timezone, and half-open valid-period identity;
- typed changed values with previous and current values and units;
- stable change categories for temperature, precipitation probability and
timing, wind gusts, alerts, and aggregate hazards;
- an API-owned significance classification or enough structured information
for a stateless consumer to apply a documented presentation threshold; and
- deterministic ordering, missing-baseline behavior, and source metadata.
The API should compare forecast versions, not track a Weatherreporter client's
"previous run." It should not require consumer identity, mutable cursors, or
Weatherreporter-managed history. A missing baseline should be a normal empty
result rather than an error.
Once a stable upstream contract exists, a separate Weatherreporter roadmap may
reintroduce change commentary by collecting that product and mapping it into a
curated prompt-facing module. There must be no local snapshot fallback. The
ordinary Weatherreporter process must remain stateless, and the upstream
feature should have deterministic fixtures before adoption.
## Automatic Storm Monitoring ## Automatic Storm Monitoring
Status: Proposed and unimplemented. Status: Proposed and unimplemented.
@@ -14,7 +48,9 @@ Possible direction:
1. Detect candidate storm events from alerts, forecast discussion, weather 1. Detect candidate storm events from alerts, forecast discussion, weather
story context, hourly thresholds, and material forecast changes. story context, hourly thresholds, and material forecast changes.
2. Evaluate candidates through Promptkit or another narrow evaluator adapter. 2. Evaluate candidates through Promptkit or another narrow evaluator adapter.
3. Persist storm lifecycle state. 3. Keep any required storm lifecycle state in the upstream service or another
explicitly designed external owner rather than silently reintroducing a
Weatherreporter workspace.
4. Generate or update a storm report only when a meaningful event is present. 4. Generate or update a storm report only when a meaningful event is present.
5. Suppress ordinary low-impact thunder or rain chances. 5. Suppress ordinary low-impact thunder or rain chances.
@@ -54,8 +90,7 @@ Status: Proposed and unimplemented.
Possible future modules: Possible future modules:
- `hourly_table` for compact valid-period hourly facts - `hourly_table` for compact valid-period hourly facts
- `forecast_delta` if a separate stanza is useful beyond current Recent - `forecast_delta` after an upstream forecast-change product exists
Changes
- `weekend_planning` if weekend-specific planning guidance needs a dedicated - `weekend_planning` if weekend-specific planning guidance needs a dedicated
deterministic stanza deterministic stanza
- `storm_window_summary` if manual or automatic storm reports need a dedicated - `storm_window_summary` if manual or automatic storm reports need a dedicated
@@ -79,7 +114,7 @@ contracts](../internal/facts.md), [module internals](../internal/module.md), and
- keep broad reusable calculations in `DerivedFacts` - keep broad reusable calculations in `DerivedFacts`
- keep prompt-facing field shape inside module builders - keep prompt-facing field shape inside module builders
- use typed options for configurable module behavior - use typed options for configurable module behavior
- keep module snapshots structured and deterministic for Recent Changes - keep module output structured and deterministic
## Distributor Notification Enhancements ## Distributor Notification Enhancements
@@ -92,10 +127,8 @@ behavior is documented in the [Distributor adapter guide](../internal/distributo
unimplemented: unimplemented:
- `failure_policy: warn` - `failure_policy: warn`
- uploading metadata, module snapshots, data packages, or preflight artifacts
- durable upload retry queues - durable upload retry queues
- distributor-specific CLI flags - distributor-specific CLI flags
- distributor workspace scanning
- destination routing, Markdown-to-HTML transformation, public URLs, or nginx - destination routing, Markdown-to-HTML transformation, public URLs, or nginx
layout inside weatherreporter layout inside weatherreporter
@@ -138,6 +171,7 @@ maintenance costs make the added abstraction worthwhile:
- global test helper package - global test helper package
- logging subsystem - logging subsystem
Any future implementation should preserve the existing public CLI, artifact Any future implementation should preserve the public CLI, report-output
paths, report identities, module boundaries, and adapter boundaries unless a contract, report identities, module boundaries, and adapter boundaries in
separate roadmap explicitly changes them. effect when that work begins unless a separate roadmap explicitly changes
them.

View File

@@ -0,0 +1,739 @@
# Stateless Execution Implementation Plan
Status: Ready for implementation.
## Purpose
This plan implements the accepted [Stateless Execution
Roadmap](ephemeral-state.md). That roadmap is authoritative for product intent,
policy choices, and the desired end state. This document owns implementation
order, concrete code changes, and verification gates.
The target is a Weatherreporter process whose ordinary invocations require no
prior application state and leave only operator-owned Markdown outputs. Local
Recent Changes, the managed workspace, historical artifacts and metadata, and
the `inspect` command family are removed. Explicit secure Promptkit debug
capture remains operator-owned.
## Implementation Rules
1. Implement the stages in numeric order. Do not merge or release an
intermediate stage as a completed stateless-execution feature.
2. Keep the repository buildable and `go test ./...` passing at every stage.
Use focused tests while iterating, then run the stage's listed commands.
3. Follow the architecture, documentation, and testing policies under
`docs/policy/`. Delete tests that protect intentionally removed contracts;
do not mechanically rewrite them to preserve obsolete structures.
4. Do not retain compatibility shims for `workspace`, `recent_change`,
historical metadata, inspection commands, prompt artifact paths, or the
`recent_changes` prompt field. Strict configuration loading should reject
removed fields.
5. Preserve prompt inspection before weather collection, batch-wide prompt
inspection before collection, exact profile selection, structured-output
validation, repository-owned rendering, deterministic report periods,
batch membership, safe error classification, and Distributor bundle paths.
6. Preserve the existing `--llm-debug-dir PATH` interface and security
properties. Do not introduce an implicit debug location or a general
logging subsystem.
7. Do not contact live Weather API, Promptkit provider, or Distributor
services in repository tests.
8. Do not create release notes until a release version is selected. The
durable documentation stage must record the compatibility and operator
actions that future release notes need to summarize.
## Target Contracts
These decisions are fixed for implementation:
- `generate` always writes exactly one operator-owned Markdown file.
- `--out PATH` selects that file. Without `--out`, the destination is in the
working directory captured at invocation start:
`daily-YYYY-MM-DD.md`, `today.md`, `tomorrow.md`, or `hourly.md`.
- `run` writes each successful report beneath `--out-dir PATH`, or beneath the
captured working directory when the flag is omitted. Daily batch filenames
remain date-qualified.
- CLI-resolved output paths are cleaned absolute paths. App-level action
requests receive an absolute working directory plus an optional operator
override and reject invalid or empty resolved destinations before weather
collection.
- A generation publishes its selected output atomically. Failure or
cancellation before publication leaves an existing destination unchanged.
- Single-report notification occurs after local output publication. Batch
notification occurs only after every planned report succeeds. Distributor
reads the selected output files; there is no second managed copy.
- Action summaries retain identity, valid period, safe effective
profile/backend/model information, source warnings, final output path,
optional debug path, notification status, and a safe error. They contain no
historical or transient artifact paths.
- RunIDs remain active correlation and idempotency values only.
- The prompt data-package schema becomes
`weatherreporter.data_package.v4`, with no `recent_changes` member. All four
embedded prompts become exact version `2.0.0`.
- Ordinary execution creates no `workspace` tree, metadata, receipts,
snapshots, data packages, generated-text intermediates, render-context
files, notification artifacts, or run index.
## Stage 1: Record The Stateless Architecture Decision
### Goal
Create the durable decision record before changing the architecture, without
describing unimplemented behavior as current behavior elsewhere.
### Work
1. Create `docs/adr/` if it does not exist and add
`docs/adr/0001-stateless-execution.md` as an Accepted ADR using the format
required by `docs/policy/documentation.md`.
2. Record:
- why run-addressed provenance conflicts with ephemeral weather reports;
- removal of local Recent Changes rather than retention of state for it;
- the stateless transformation pipeline and operator-owned output boundary;
- atomic output and notification ordering;
- explicit debug capture as the only retained diagnostic-file exception;
- removal of inspection and backward-compatible workspace decoding;
- the upstream Weather API path for future forecast comparison; and
- alternatives: the former bounded-current-state design, time-based
retention, and bounded run history.
3. Link the ADR to the feature roadmap for scope, while keeping the ADR focused
on durable rationale rather than implementation stages.
4. Do not update current-state architecture or user documentation in this
stage.
### Tests
Run:
```sh
git diff --check
```
Verify every repository-relative ADR link resolves.
### Exit Gate
An Accepted ADR records the exact decision and consequences; no production
behavior or current-state documentation has changed.
## Stage 2: Remove Recent Changes From The Prompt Contract
### Goal
Stop generating or sending local comparison results while the existing
workspace remains temporarily available for unrelated artifacts.
### Work
1. Remove `RecentChanges` from `promptinput.BuildRequest` and
`promptinput.Package`, delete the prompt-input `RecentChanges` wrapper, and
remove the `internal/changes` dependency from `internal/promptinput`.
2. Advance `promptinput.SchemaVersion` from
`weatherreporter.data_package.v3` to `weatherreporter.data_package.v4`.
Update marshal, load, validation, round-trip, ordering, and fixture tests so
v4 has no `recent_changes` key and v3 is rejected.
3. In app orchestration, stop finding a prior snapshot, loading it, invoking a
comparator, or placing Recent Changes in `ReportResult` or prompt input.
Continue building the current module snapshot because it is still needed
in memory for prompt input and rendering, and may still be persisted by the
transitional workflow.
4. Remove Recent Changes fields and assertions from app workflow fakes and
tests. Delete prior-run workflow cases whose only purpose was local change
detection.
5. Change all four report-definition prompt versions and embedded prompt YAML
versions from `1.1.0` to `2.0.0`.
6. Remove the common system-prompt reference to supplied recent changes.
Review every prompt body to ensure none instructs the model to infer or
discuss changes from an absent comparison field.
7. Update prompt-asset and adapter integration fixtures to use exact version
`2.0.0`. Do not change generated-text output schemas or report templates;
neither directly depends on Recent Changes.
### Tests
Run:
```sh
go test ./internal/promptinput ./internal/promptassets ./internal/report
go test ./internal/app ./internal/adapters/promptkit
go test ./...
git diff --check
```
Add or retain focused tests proving that serialized v4 packages omit
`recent_changes` entirely and every embedded prompt resolves at `2.0.0`.
### Exit Gate
No generated prompt package or active app workflow contains Recent Changes,
while report generation and the still-transitional persistence workflow
continue to function.
## Stage 3: Delete Dormant Local Comparison Policy
### Goal
Remove comparison code and configuration that no active report workflow uses.
### Work
1. Delete `internal/changes` and its tests.
2. Remove `RecentChangeConfig`, `Config.RecentChange`, its defaults,
validation, YAML handling, test fixtures, and maintained example values.
3. Add a strict-loading regression test showing that a top-level
`recent_change:` stanza is now rejected as unknown. Do not silently ignore
the obsolete field.
4. Remove stale Recent Changes imports, helpers, test builders, and comments
throughout app, config, prompt input, facts, forecast, briefing, generated
text, and report code.
5. Leave report comparison declarations and state prior-lookup code only where
the still-supported historical `inspect prior` path requires them. They are
removed with inspection in Stage 8; do not invent a new consumer.
### Tests
Run:
```sh
go test ./internal/config ./internal/app ./internal/promptinput
go test ./...
git diff --check
```
### Exit Gate
No active generation code or configuration surface implements local change
detection, and the legacy field fails strict configuration loading.
## Stage 4: Establish The Operator-Owned Output Contract
### Goal
Make every successful action select and atomically write its final output even
while the old managed workspace still exists behind the workflow.
### Work
1. Add an injectable `WorkingDir string` to `cli.Runner`. When empty,
production calls `os.Getwd` once per action; tests supply an absolute
temporary directory without calling `os.Chdir`.
2. Pass the captured absolute working directory through `GenerateRequest` and
`BatchRequest`. Resolve relative `--out` and `--out-dir` values against it
and clean the resulting absolute paths.
3. Centralize output filenames rather than duplicating them in CLI and app:
- Daily uses `daily-YYYY-MM-DD.md` with the resolved valid-period start in
the effective report timezone;
- Today, Tomorrow, and Hourly use `today.md`, `tomorrow.md`, and
`hourly.md`;
- dynamic Daily batch items use the same date-qualified rule.
Rename `report.Definition.BatchOutputName` to `OutputName` and rename
app-internal “output copy” fields/helpers to “output” terminology. Preserve
the external Distributor template variable `batch_output_name` and populate
it from the selected output filename.
4. When `--out` is absent, resolve the single-report default after the report
period is known. When `--out-dir` is absent, use the captured working
directory for all batch items.
5. Require a non-empty absolute final output path before collection. Reject a
filesystem root or a destination that resolves to a directory. Let atomic
publication create missing parent directories for a valid file path.
6. Continue using `fileutil.WriteFileAtomic` or an equivalently narrow helper.
An existing destination may be replaced only after the complete new report
has been written and closed successfully.
7. Change help and flag descriptions so `--out` and `--out-dir` select report
destinations rather than “extra copies.”
8. Update app and CLI tests for defaults, explicit absolute and relative
overrides, Daily date naming, batch naming, existing-file preservation on
failure, and absolute summary paths.
### Tests
Run:
```sh
go test ./internal/report ./internal/fileutil
go test ./internal/app ./internal/cli
go test ./...
git diff --check
```
### Exit Gate
Every successful single or batch item has one selected operator output path,
omitted flags use the captured working directory, and failed publication
cannot corrupt an existing destination.
## Stage 5: Separate Explicit Debug Capture From State
### Goal
Preserve secure opt-in Promptkit diagnostics without retaining a dependency on
the package that owns the obsolete workspace.
### Work
1. Move `internal/state/debug_writer.go` and its focused tests to
`internal/promptdebug`. Move rather than duplicate the implementation.
2. Preserve:
- empty-path disablement without filesystem access;
- absolute non-root destination validation;
- safe report/date/RunID path segments;
- directory mode `0700` and file mode `0600`;
- endpoint sanitization and parameter redaction;
- credential exclusion; and
- preparation-callback failure preventing provider execution.
3. Update app imports and debug tests to use the new package. Do not move
ordinary artifacts into the debug package.
4. Leave the transitional `DataPackagePath` execution fields intact while
persisted receipts still validate them. Stage 7 removes those fields with
their final consumer.
### Tests
Run:
```sh
go test ./internal/promptdebug ./internal/promptexec
go test ./internal/adapters/promptkit ./internal/app ./internal/cli
go test ./...
git diff --check
```
### Exit Gate
Debug capture is independent of `internal/state`, and its security and
preparation-callback behavior are unchanged.
## Stage 6: Remove Notification Persistence
### Goal
Make Distributor delivery an active-workflow result that consumes final output
files and writes no Weatherreporter receipt.
### Work
1. Refactor `notifyReport` and `notifyBatch` so they do not accept a
`state.Store` and do not call any `SaveDistributorNotification` operation.
Delete notification-artifact conversion and persistence helpers from app.
2. For single reports, build the notification request from the resolved report
identity, active RunID/timestamps, and selected `OutputPath`. Remove
“managed report” terminology from code and safe errors.
3. For batches, use each successful item's `OutputPath` as the Distributor
source. Preserve bundle-path rendering, duplicate bundle-path rejection,
batch inclusion metadata, all-success gating, and one batch upload.
4. Remove `NotificationPath` and batch notification `Path` fields from app
results and CLI summaries. Preserve remote run, pipeline, bundle,
idempotency, status, timing, and safe-error fields.
5. Preserve ordering:
- local atomic publication precedes a single notification;
- a notification failure leaves the output and returns a failure;
- batch notification is skipped after any report failure;
- successful batch items remain successful when only batch notification
fails.
6. Delete tests that assert notification receipt files. Replace them with
focused interaction tests proving source paths, ordering, skip behavior,
one-call behavior, and failure propagation.
### Tests
Run:
```sh
go test ./internal/app ./internal/adapters/distributor
go test ./internal/cli
go test ./...
git diff --check
```
### Exit Gate
Distributor behavior uses operator outputs and returns active status without
creating notification artifacts or depending on state.
## Stage 7: Replace The Persisted Generation Workflow
### Goal
Convert the shared single-report generation path into a state-free in-memory
pipeline used by both `generate` and `run`.
### Work
1. Replace the persistence-oriented `promptReportWorkflow` with a cohesive
workflow that:
- initializes a safe partial `ReportResult` from `report.Resolved`;
- builds collected and derived facts;
- builds the module snapshot in memory;
- builds `briefing.Metadata` and the v4 prompt package in memory;
- marshals YAML in memory;
- executes Promptkit with the existing preparation callback;
- writes requested preparation and execution debug captures only;
- requires a completed passed Promptkit validation;
- validates and decodes generated text;
- builds the render context and renders Markdown in memory;
- atomically writes the selected output; and
- notifies only after publication when notification is enabled.
2. Delete all ordinary calls that save module snapshots, data packages,
prompt preparation/execution, raw output, validated output, render context,
metadata, or managed reports.
3. Remove `DataPackagePath` from `promptexec.ExecuteRequest`,
`promptexec.Preparation`, `promptexec.Execution`, and debug artifact
mappings. Change the Promptkit adapter input from `InlineWithURI` using a
filesystem path to `promptkit.Inline`; the input remains copied inline and
its hashes remain available. Advance the changed debug schema identifiers
from `weatherreporter.prompt_preparation_debug.v1` and
`weatherreporter.prompt_execution_debug.v1` to their corresponding `v2`
identifiers without adding compatibility readers.
4. Preserve failure classification and context. A debug-write error remains an
invalid-configuration failure and the preparation callback must still stop
the provider when it fails. Operational provider failure and completed
validation rejection remain distinct.
5. Redesign `ReportResult` as an active result rather than an artifact index.
Retain only:
- report ID/name, prompt ID/version, RunID, generation time, timezone, and
valid period;
- selected profile ID, backend ID, and model name once inspected;
- source warnings;
- validation status when execution reached validation;
- final `OutputPath` once publication succeeds;
- `LLMDebugPath` when explicitly created; and
- notification result.
Do not retain module snapshots, prompt packages, generated bodies, render
contexts, state metadata, or transient paths in the result.
6. Make the CLI generate summary map directly from this active result and
remove `ReportPath`, `MetadataPath`, `DataPackagePath`,
`PreparationPath`, `ExecutionPath`, `GeneratedTextRawPath`,
`GeneratedTextPath`, `RenderContextPath`, and `NotificationPath`.
7. Apply the same safe identity/profile/warning/output fields to
`BatchReportResult`. Keep batch failure accounting and sequential execution.
8. Remove `Store` from `GenerateRequest` and `BatchRequest`. Remove
`defaultStore` and all persistence-only finalization helpers in this stage.
9. Keep app tests behavioral. Replace receipt/checkpoint assertions with a
compact matrix covering success, each consequential failure boundary,
partial results, inspection-before-collection, output atomicity, effective
profile propagation, debug capture, and notification sequencing.
### Tests
Run:
```sh
go test ./internal/app
go test ./internal/cli ./internal/adapters/promptkit
go test ./...
git diff --check
```
### Exit Gate
Single and batch generation share a state-free pipeline, ordinary success
leaves only selected outputs, and no app production path imports
`internal/state`.
## Stage 8: Remove Historical Inspection And Prior Compatibility
### Goal
Delete public and internal surfaces whose only purpose is reading prior runs.
### Work
1. Delete `internal/app/inspect.go` and all inspection request/result types and
focused tests.
2. Remove the top-level `inspect` dispatch, parsers, `--limit` handling,
command tables, help text, and CLI tests for:
`reports`, `metadata`, `modules`, `data-package`, `prior`, and `sources`.
`inspect` becomes an unknown command; do not retain a tombstone command.
3. Remove report `ComparisonStrategy`, comparison constants,
`CompatiblePriorIDs`, compatibility helpers, and registry tests.
4. Remove `FindPriorSnapshot`, `PriorSnapshot`, prior compatibility helpers,
and their tests from the still-transitional state package so it continues
to compile until full deletion.
5. Remove state load/list methods that existed only for CLI inspection where
doing so is clean and local. Do not spend effort preserving a smaller
historical reader that Stage 9 will delete.
6. Ensure `generate` and `run` parsing, help, summaries, and error behavior
remain intact.
### Tests
Run:
```sh
go test ./internal/report ./internal/app ./internal/cli ./internal/state
go test ./...
go run ./cmd/weatherreporter --help
git diff --check
```
Assert that `inspect` is rejected as an unknown command and no inspection
subcommand appears in help.
### Exit Gate
No public or app-level historical inspection contract remains, and report
definitions contain no prior-run compatibility policy.
## Stage 9: Delete The Workspace And State Subsystem
### Goal
Remove the now-unreferenced durable-state implementation and configuration.
### Work
1. Delete the remaining `internal/state` package and all of its tests. Do not
preserve metadata structs, artifact schemas, validators, path builders,
filesystem stores, or compatibility readers in another package.
2. Remove `WorkspaceConfig`, `Config.Workspace`, workspace defaults,
validation, YAML fixtures, and test helpers.
3. Add strict-loading coverage showing that a top-level `workspace:` stanza is
rejected as unknown. Existing legacy configuration is intentionally not
accepted.
4. Remove workspace and Recent Changes sections from maintained examples.
Keep every example complete, secret-free, and accepted by the production
loader.
5. Remove dead app code exposed by the deletion, including `FetchBundle`,
`FetchAndSaveBundle`, store helpers, artifact conversion helpers, copy
helpers, imports, and persistence-only test infrastructure. Neither fetch
helper currently has a production caller.
6. Keep state-independent atomic output helpers in `internal/fileutil`, update
their package comments to describe operator-owned outputs, and delete the
now-unused `CopyFileAtomic` helper.
7. Verify production Go code contains no import of `internal/state` and no
construction of a directory named `workspace`.
### Tests
Run:
```sh
go test ./internal/config ./internal/fileutil ./internal/app ./internal/cli
go test ./...
git diff --check
```
### Exit Gate
`internal/state` and `workspace` configuration no longer exist, legacy fields
fail strict loading, and normal execution has no application-owned durable
state mechanism.
## Stage 10: Consolidate Stateless Behavioral Coverage
### Goal
Review the rewritten suite as a whole and retain a lean set of tests that
protect the new risks without preserving deleted implementation choreography.
### Work
1. Audit app and CLI tests that were rewritten in earlier stages. Consolidate
overlapping cases and delete helpers whose only value was constructing
stores, metadata, artifact paths, or prior snapshots.
2. Ensure durable offline coverage at the narrowest stable boundary for:
- default and explicit absolute output selection;
- relative override resolution from an injected working directory;
- Daily valid-date filenames and distinct multi-day batch outputs;
- preservation of an existing destination on generation, rendering,
output-write, or cancellation before publication;
- retention of the newly published output when notification fails;
- no output on pre-publication failure;
- successful items surviving partial batch failure;
- batch notification only after all outputs exist;
- Distributor source and bundle paths;
- inspection/profile validation before weather collection;
- safe effective profile/backend/model and source warnings in summaries;
- absence of historical/transient paths in JSON summaries;
- no ordinary debug directory creation;
- secure explicit debug capture and credential redaction; and
- no default workspace or intermediate artifacts after repeated successes
and failures.
3. Use real temporary directories and real internal rendering/file helpers.
Fake only Weather API collection, Promptkit/provider execution, clocks, and
Distributor delivery.
4. Avoid tests of private phase ordering unless the ordering is a stated
external requirement. Do not replace deleted state tests with broad
filesystem snapshots.
### Tests
Run:
```sh
go test ./internal/app ./internal/cli
go test ./internal/fileutil ./internal/promptdebug
go test ./...
git diff --check
```
### Exit Gate
The suite protects stateless product behavior and consequential failure
boundaries without retaining obsolete state-oriented fixtures or redundant
mock choreography.
## Stage 11: Publish User, Operator, And Policy Documentation
### Goal
Publish the user-visible, operational, and normative stateless contracts in
their canonical owners.
### Work
1. Update `README.md` so the shortest useful command relies on the documented
current-directory output and links to canonical CLI and operations details.
2. Update `docs/cli.md` with:
- removal of `inspect`;
- default and explicit output behavior;
- absolute `outputPath` summaries;
- retained identity/profile/model/warning/debug/notification fields; and
- removal of historical artifact path fields.
3. Update `docs/config.md` and maintained examples to remove `workspace` and
`recent_change`. Keep Promptkit debug and notification configuration in
their existing canonical owners.
4. Rewrite `docs/operations.md` around operator-owned outputs, atomic
replacement, batch partial success, Distributor ordering, explicit debug
capture, and precise manual legacy-workspace cleanup. Remove all inspection,
metadata, receipt, recovery, and managed-workspace procedures.
5. Update `docs/policy/architecture.md` to make stateless execution,
in-memory processing, operator-owned atomic outputs, and state-free
notification normative. Remove `internal/state` and prior-comparison
ownership and persistence invariants.
6. Update `docs/policy/documentation.md` so Operations owns output lifecycle,
diagnosis, legacy cleanup, and explicit debug handling rather than physical
workspace and inspection contracts.
7. Update `docs/policy/testing.md` where its examples assign behavior to state
tests or name persistence/inspection as current app workflow contracts.
Preserve its general risk-based guidance.
8. Update `docs/development.md` package inventory and task guide for the
stateless package layout, removed inspection workflow, and operator-output
boundary. Route detailed subsystem work to its canonical internal or
integration document rather than duplicating it.
9. Leave `docs/releases/v0.9.0.md` unchanged as a historical record. Do not
create a new release note without a selected version. Confirm that the
future note must call out removed commands and fields, default outputs,
prompt contract changes, and manual legacy cleanup.
### Tests
Run:
```sh
go test ./...
go run ./cmd/weatherreporter --help
git diff --check
```
Check every changed repository-relative link, maintained YAML example, command,
flag, field, and output filename against executable sources.
### Exit Gate
User, operator, policy, development, and example documentation describe the
implemented stateless contract, and historical release notes remain unchanged.
## Stage 12: Reconcile Internal And Integration Documentation
### Goal
Bring maintainer-facing subsystem and external-contract documentation into
line with the implemented package boundaries without duplicating user-facing
contracts.
### Work
1. Delete `docs/internal/state.md` and `docs/internal/changes.md` and repair all
incoming links.
2. Update app orchestration internals for the in-memory workflow, partial
active results, atomic output, notification order, and batch isolation.
3. Update CLI internals for working-directory capture, destination resolution,
stateless summaries, and removal of inspection dispatch.
4. Update prompt-input internals for v4 without `recent_changes`, report
registry internals for output naming without comparison policy, and module
and generated-text internals only where their actual contracts changed.
5. Update Promptkit adapter internals and
`docs/integrations/promptkit.md` for inline input without a filesystem URI,
exact prompt version `2.0.0`, active safe provenance, and explicit debug
capture.
6. Update Distributor adapter and integration documents so source files are
operator outputs and notification state is not retained. Preserve the
remote API and bundle-path contract.
7. Review weather-data, collection, template, and other internal/integration
documents for stale references, but edit only documents whose owned
contracts changed.
8. Do not mark either roadmap implemented in this stage; Stage 13 owns that
status transition after the repository-wide gate. Do not turn either
roadmap into a second current-state reference.
### Tests
Run:
```sh
go test ./...
git diff --check
```
Validate every changed repository-relative link and verify each named package,
schema, prompt version, field, and integration path against executable sources.
### Exit Gate
No current internal or integration document describes local comparison,
historical state, inspection, managed-report sources, or durable prompt
provenance, and roadmap status accurately reflects completion.
## Stage 13: Run The Repository Exit Gate
### Goal
Verify the complete refactor as one coherent change and remove any remaining
legacy coupling before declaring implementation complete.
### Work
1. Run `gofmt` on every changed Go file and review the complete diff for stale
compatibility code, unnecessary abstractions, accidental content capture,
or user-owned unrelated changes.
2. Search production code, tests, examples, and current-state documentation
for obsolete `internal/state` imports, `workspace` and `recent_change`
configuration, `recent_changes` prompt input, comparison strategy fields,
inspection commands, managed-report terminology, and removed artifact-path
summary fields. Historical `v0.9.0` release notes and roadmap discussion of
removed behavior are allowed.
3. Verify the built help contains only `generate` and `run` action families
plus top-level help/version behavior.
4. Verify from focused offline CLI tests that commands run in a clean temporary
working directory and leave only expected Markdown outputs unless a debug
directory was explicitly supplied.
5. Confirm no test, example, or default path depends on the developer machine,
live credentials, or external services.
6. Mark the roadmap and plan complete only after all gates pass. Do not create
or tag a release in this implementation plan.
### Tests
Run:
```sh
git diff --name-only --diff-filter=ACM -- '*.go' | xargs -r gofmt -w
go test ./...
go test -race ./...
go vet ./...
go build ./...
go run ./cmd/weatherreporter --help
git diff --check
```
### Exit Gate
Weatherreporter builds and passes its deterministic offline suite; ordinary
actions are stateless and leave only selected outputs; debug and Distributor
boundaries remain safe; documentation matches implementation; and no required
work remains.
## Open Questions
None. The roadmap supplies all product and policy decisions required to
implement these stages.