diff --git a/docs/roadmap/ephemeral-state.md b/docs/roadmap/ephemeral-state.md index 47398eb..5cc9eea 100644 --- a/docs/roadmap/ephemeral-state.md +++ b/docs/roadmap/ephemeral-state.md @@ -1,39 +1,38 @@ -# Ephemeral Operational State Roadmap +# Stateless Execution Roadmap -Status: Accepted feature direction; implementation has not started. +Status: Accepted. ## Purpose -Weatherreporter should treat generated weather reports and their intermediate -artifacts as short-lived operational material rather than a durable audit -history. Forecasts and current conditions change continuously, and the normal -response to an old or failed report is to generate a new report, not to -reconstruct the provenance of the old one. +Weatherreporter should be a stateless report transformation pipeline. Each +invocation fetches current inputs from the Weather API, derives deterministic +facts, executes Promptkit, renders Markdown, and writes or distributes the +completed report. It does not retain application-owned history or operational +state between invocations. -The application should retain only the bounded state needed to publish the -current report, calculate Recent Changes against the last successfully -published report for the same valid period, and complete the current -invocation safely. Detailed LLM diagnostics should remain an explicit, -operator-controlled exception outside ordinary workspace state. +Weather reports are ephemeral products rather than business records. Forecasts +and current conditions change continuously, and the normal response to an old +or failed report is to generate a new one rather than recover, replay, or +inspect the prior generation. -This roadmap defines the intended state lifecycle, compatibility policy, and -architectural boundaries. A separate implementation plan will define the -ordered work after the roadmap is complete. +This roadmap defines the desired lifecycle, output contract, compatibility +policy, and architectural boundaries. ## 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; -- old report provenance has no continuing operational value once conditions - and forecasts have changed; -- regenerating is preferable to recovering, replaying, or inspecting an old - generation; -- routine operation should not accumulate unbounded run-addressed artifacts; -- Recent Changes remains useful, but needs only one prior successful snapshot - for the same report and valid period; and -- sensitive prompt and response capture remains opt-in and explicitly managed - by the operator. +- each invocation is independent and requires no prior Weatherreporter state; +- routine operation creates only the requested report outputs; +- reports are written somewhere useful even when the operator omits an + explicit output flag; +- Weatherreporter does not maintain forecast history merely to compare runs; +- regenerating replaces a same-named output atomically instead of creating an + archive; +- Distributor receives the completed report produced by the current + invocation; and +- sensitive diagnostics are retained only through an explicit, + operator-controlled debug option. ## 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 receipt, raw generated text, validated generated text, render context, managed 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 -snapshots, and source provenance. New metadata uses the V2 format while the -reader retains V1 compatibility. Prompt artifacts are validated against -current report and prompt definitions when saved and loaded. +snapshots, and source provenance. The reader retains V1 compatibility while +new runs write V2 metadata. -Most of this persistence exists for retrospective inspection and failure -recovery. Dedicated prompt preparation and execution load operations have no -ordinary production consumer. The important exception is module snapshot -state: generation actively loads the most recent compatible snapshot to build -the deterministic Recent Changes input for Daily, Today, and Tomorrow. +Weatherreporter also loads a compatible prior module snapshot for Daily, +Today, and Tomorrow and compares it with the current snapshot. Configurable +thresholds determine whether structured Recent Changes are included in the +Promptkit data package. This is the only current product behavior that depends +on state from an earlier invocation. ## Desired End State -Weatherreporter has three distinct state classes: +Weatherreporter has no durable application-managed workspace. Its dataflow is: -| State class | Lifecycle | Purpose | -| --- | --- | --- | -| Invocation workspace | Temporary and unpublished | Hold intermediate values while one report or batch is running. | -| Current published state | Bounded and replaceable | Hold the current managed report and the minimal deterministic snapshot or manifest needed for normal operation. | -| Secure LLM debug capture | Explicitly enabled and operator-managed | Diagnose prompt rendering or provider output when the operator deliberately requests sensitive capture. | +```text +Weather API input + -> deterministic facts and modules + -> Promptkit data package and generated text + -> repository-owned Markdown rendering + -> operator-owned report output + -> optional Distributor upload +``` -Ordinary generation uses an invocation-scoped temporary directory on the same -filesystem as the managed workspace when atomic publication requires it. -Prompt preparation, prompt execution, raw generated text, validated generated -text, render contexts, data packages, and notification receipts may exist -there while needed, but they are not published as durable historical -artifacts. +Intermediate values remain in memory wherever practical. A narrowly scoped +temporary file may be used when an external interface requires a file path, +but it exists only for the active invocation and is removed on return. +Temporary material is not a supported recovery or inspection surface. -A successful report atomically replaces the current published state for its -logical report key and valid period. A failed attempt leaves the last -successfully published report and comparison snapshot unchanged. Ordinary -temporary artifacts are removed after both success and handled failure; -cleanup failure is reported safely but must not replace the primary generation -error. +RunIDs may remain as in-process correlation identifiers in action summaries, +errors, Distributor idempotency values, and explicit debug paths. They do not +identify a collection that Weatherreporter can locate or decode later. -RunIDs remain useful as in-process correlation identifiers in action results, -logs, provider provenance, and optional debug paths. They no longer identify a -durable collection that Weatherreporter promises to locate or decode later. +Configuration files, operator-owned report outputs, and explicitly requested +debug captures are inputs or outputs, not Weatherreporter state. -## Published Report Policy +## Report Output Contract -The managed Markdown report remains the authoritative upload source during an -invocation. The intended default is to retain only the current managed report -for each logical report key and valid period, replacing it atomically after a -new report has been fully rendered and validated. +Every successful report generation writes one operator-owned Markdown output. +An explicit output option selects its destination. When no explicit destination +is supplied, Weatherreporter uses the process working directory captured at +invocation start. -An explicit `--out` or `--out-dir` copy remains operator-owned output outside -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. +Default single-report filenames are: -Distributor continues to receive only a completed managed Markdown report. -Notification success or failure does not create a durable notification -history. A notification failure leaves the newly published report available -and returns a safe error through the current action result. +| Report | Default output | +| --- | --- | +| Daily | `daily-YYYY-MM-DD.md`, using the report's valid local date | +| 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 Daily, Today, and Tomorrow, Weatherreporter retains at most one compatible -module snapshot for each logical report key and valid period. +For `run`, `--out-dir PATH` selects the report-output directory and the current +working directory is the default when it is omitted. Existing batch filenames +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 -new invocation reads it before constructing Recent Changes and replaces it -only when the new managed report has been successfully validated, rendered, -and published. A failed generation therefore does not become the baseline for -the next report and cannot hide changes that the user has not yet seen. +Output publication is atomic. A completed generation may atomically replace an +existing file at the selected path, but a failed or canceled generation must +not truncate or partially replace it. Weatherreporter does not rotate, archive, +expire, or otherwise manage an output after publication. -Hourly does not currently use the comparison strategy and should not retain a -comparison snapshot solely for symmetry. State whose valid period has ended -and can no longer participate in a supported comparison is eligible for safe -cleanup. +The JSON action summary reports the final output path. It does not expose paths +to transient intermediates. `--quiet` continues to suppress the action summary, +not report creation. -## Temporary Workspace And Failure Semantics +## Distributor Contract -Temporary state must remain beneath a narrowly owned application directory and -use safe path construction, restrictive permissions where content is -sensitive, and atomic writes where practical. Publication must not expose a -partially rendered report or a snapshot that does not correspond to the -published report. +Distributor uploads use the completed Markdown output from the active +invocation. There is no separate durable managed-report copy and no workspace +scan. -Normal results retain bounded error information and paths only for artifacts -that remain meaningful after the command: a previously or newly published -report, an explicit operator output, or an enabled secure debug capture. -Temporary intermediate paths are not emitted as if they were durable recovery -locations. A failed command is retried by starting a new generation. +For a single report, local output publication completes before notification. +A notification failure leaves the report output intact and returns a safe +error through the active result. It does not create a notification receipt. -Process interruption may leave an uncommitted temporary directory. Such a -directory is never considered published state, is never selected for Recent -Changes, and may be removed by a documented safe cleanup mechanism. Cleanup -must distinguish inactive temporary directories from concurrent active -invocations and must never recursively target the workspace root or an -unresolved configuration path. +Batches continue to suppress per-report notification and attempt their +batch-level upload only after every planned report succeeds. A report failure +leaves other successful output files intact, skips the batch upload, and +returns an aggregate failure. Distributor status remains active-workflow +information rather than retained Weatherreporter history. -## Inspection And Metadata Policy +## Recent Changes Deprecation And Removal -Run-history discovery and inspection are not part of the desired product -contract. The historical `inspect reports`, `inspect metadata`, `inspect -modules`, `inspect data-package`, `inspect prior`, and `inspect sources` -surfaces are candidates for removal together rather than preservation through -a new storage representation. +The local Recent Changes feature is deprecated by this accepted direction and +is removed when the stateless execution change lands. Its low practical value +does not justify retaining a historical state subsystem. -Any manifest retained for atomic publication or Recent Changes is current -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. +Removal includes: -The application does not promise cross-version decoding of ordinary workspace -state. A new release may replace or ignore incompatible current-state files, -provided it fails safely, never mistakes stale state for a compatible Recent -Changes baseline, and documents any operator action required during upgrade. +- prior-snapshot discovery and compatibility rules; +- the `internal/changes` comparison implementation; +- report-registry comparison strategies and compatible-prior declarations; +- `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 -runtime safety requirements. They do not require durable preparation or -execution receipts. +runtime safety requirements. Preparation details, effective profile and model, +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, -and safe classified error remain available to the active workflow and its CLI -summary where useful. Weatherreporter does not retain them as long-term report -provenance after the invocation completes. +The existing `--llm-debug-dir PATH` option remains the explicit exception to +stateless output. When supplied, it may retain rendered prompts, schemas, input +bodies, generated bodies, and effective parameters according to its secure +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 -retain rendered prompts, schemas, input bodies, generated bodies, and effective -parameters according to its documented contract. Weatherreporter does not -automatically clean that operator-selected location. Credentials must remain -excluded from debug capture. +Adding a broader logging framework or an implicit persistent debug directory +is outside this feature. A future rename or generalization to `--debug` should +be considered separately so this state refactor does not expand the sensitive +capture contract incidentally. + +## 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 -This is an intentional breaking change to the workspace and inspection -contracts. Weatherreporter does not need to migrate historical V1 or V2 -metadata, prompt receipts, intermediate generated-text artifacts, or managed -reports into the new representation. +This is an intentional breaking change to the CLI, configuration, prompt-input, +workspace, and inspection contracts. Weatherreporter does not migrate old V1 +or V2 metadata or other historical artifacts. -Legacy workspace trees must not be silently interpreted as current published -state. They also must not be deleted automatically merely because a new -version starts: an operator may have placed or referenced files there despite -the absence of a continuing application compatibility promise. Release notes -and operations documentation must explain whether legacy data can be removed -manually and identify the exact safe target. +Legacy workspace trees are ignored. Weatherreporter must not discover, +interpret, or automatically delete them. Release notes and operations +documentation identify the obsolete configuration and commands and provide a +precise manual cleanup procedure for operators who want to remove the legacy +workspace. -The change should land in a release whose notes clearly identify removed CLI -commands, obsolete paths and schemas, the new bounded state behavior, and any -upgrade action. Because Weatherreporter remains pre-1.0, the ordinary semantic -version policy may carry this breaking change without inventing a migration -framework. +Existing report files explicitly written through `--out` or `--out-dir` remain +operator-owned and are never treated as legacy workspace material. + +The change should land in a release whose notes identify the removed Recent +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 -The implemented feature must include an Accepted ADR recording the durable -architectural decision to use ephemeral operational state. The ADR is not part -of this roadmap-writing pass and should not be created until implementation is -being prepared. +The target state includes an Accepted ADR recording the durable decision to +make Weatherreporter stateless. The ADR should record: -- the mismatch between run-addressed provenance storage and the ephemeral - weather-report lifecycle; -- the decision to retain bounded current report and comparison state rather - than historical runs; -- the distinction between temporary invocation state, published operational - state, explicit output copies, and secure debug capture; -- the removal of historical inspection and backward-compatibility guarantees; -- atomic publication and failed-run behavior; -- the alternatives considered, including retaining the current archive, - adding time-based retention, or keeping a bounded run history; and -- consequences for CLI compatibility, workspace layout, testing, operations, - and future schema changes. +- the mismatch between run-addressed provenance storage and ephemeral weather + reports; +- the decision to remove local change detection rather than retain state for a + rarely used report section; +- the transformation-pipeline model and operator-owned output boundary; +- the absence of historical inspection and backward-compatibility guarantees; +- atomic output and failure behavior; +- the separation of explicit debug capture from ordinary execution; +- the upstream-service path for any future forecast comparison; and +- alternatives considered, including the former bounded-current-state design, + time-based retention, and a bounded run history. -Once accepted, the ADR owns the decision rationale. The architecture policy -owns the resulting current invariant, while focused state, CLI, operations, -and integration documents own the implemented contracts. +Once accepted, the ADR owns the rationale. Architecture owns the resulting +stateless invariant, while CLI, operations, configuration, integrations, and +focused internal documents own implemented contracts. ## Scope The completed feature includes: -- an invocation-scoped temporary workspace for intermediate generation state; -- atomic publication of the current managed report and its minimal operational - state; -- a bounded comparison snapshot representing the last successfully published - report for each supported report key and valid period; -- safe cleanup behavior for normal completion, handled failure, and abandoned - temporary workspaces; -- removal of durable prompt preparation, prompt execution, generated-text, - render-context, data-package, notification, and run-metadata history; -- removal of run-history inspection commands and their application/state - contracts; -- removal of V1 metadata compatibility and current-version coupling for - historical prompt artifacts by removing the historical artifact contract; -- preservation of active-command partial status, safe errors, and paths to - genuinely retained published, operator-owned, or debug outputs; -- preservation of explicit output copies, Distributor upload behavior, and - 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. +- removal of local Recent Changes and all prior-run dependencies; +- removal of the durable workspace, artifact persistence, metadata + compatibility, and historical inspection surfaces; +- in-memory or invocation-temporary processing with safe cleanup; +- atomic operator-owned output for every successful report; +- current-working-directory defaults and explicit output overrides; +- preservation of report generation, batch membership, Promptkit execution, + Distributor delivery, action summaries, and opt-in secure debug capture; +- removal or simplification of state-only packages, fields, configuration, + fixtures, tests, and documentation; +- exact-version prompt updates for the breaking input-contract change; +- deterministic offline tests for output atomicity, failure isolation, default + path selection, Distributor sequencing, and absence of durable state; +- an Accepted ADR documenting the decision; and +- canonical documentation describing the implemented contract and clear + release-note requirements for the release that publishes it. ## Non-Goals This feature does not include: -- a general-purpose cache, database, archival service, or retention engine; -- replaying or resuming interrupted generation; -- migrating legacy artifacts into the new representation; -- retaining a bounded number of historical runs for convenience; -- automatic upload or archival of state to remote storage; -- collecting additional provider telemetry or weather-source provenance; -- changing report content, prompt text, schemas, profile selection, weather - derivation, or batch membership; -- deleting operator-owned `--out`, `--out-dir`, or secure debug files; -- changing Distributor's report-content contract; or -- making live external services part of the default test suite. +- the future upstream forecast-change API or reintroduced change commentary; +- a cache, database, archive, retention engine, manifest, or resume mechanism; +- migration or automatic deletion of legacy workspace artifacts; +- retaining a bounded report or snapshot history; +- changing weather derivation, report periods, report membership, generated + prose schemas, profile selection, or the provider model ladder; +- changing Distributor's remote API or bundle-content contract; +- deleting or managing operator-owned report and debug outputs; +- a general logging or observability subsystem; or +- live external services in the default test suite. ## Safety And Testing Policy -The state refactoring must preserve Weatherreporter's existing path-safety and -atomicity expectations while reducing the amount of durable state. Tests -should emphasize observable lifecycle guarantees rather than private file -choreography. +Tests should emphasize observable stateless behavior rather than removed file +choreography. Important risks requiring durable offline coverage include: -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 - comparison baseline; -- a partially written report becoming visible as current; -- Recent Changes selecting an incompatible report, valid period, or failed - attempt; -- 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. +Tests remain deterministic, offline, credential-free, and use real temporary +directories plus narrow external-boundary fakes. Existing tests whose only +purpose is to preserve removed state, metadata, inspection, or Recent Changes +contracts should be deleted rather than translated into assertions about +private replacement mechanics. ## 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 successful report atomically replaces only the corresponding current - published state; -- failed and canceled attempts leave the prior published report and Recent - Changes baseline unchanged; -- Daily, Today, and Tomorrow compare against at most one compatible snapshot - from the last successfully published report; -- expired comparison and published state can be removed safely without - touching operator-owned or active files; -- Hourly does not retain an unused comparison snapshot; -- historical inspection commands and V1/V2 archival compatibility code are - removed; -- temporary, published, explicit-output, and debug paths have distinct and - documented ownership and cleanup rules; -- 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 +- a clean invocation requires no prior Weatherreporter-created files; +- ordinary runs leave only their selected Markdown outputs; +- omitted output flags resolve to the documented filenames in the current + working directory; +- failed and canceled attempts preserve any existing destination file; +- no local prior-run comparison or Recent Changes contract remains; +- no workspace configuration, run-history command, metadata compatibility, or + durable intermediate-artifact contract remains; +- Distributor uses only completed current-invocation outputs; +- debug files are created only through explicit secure capture; +- repeated successful and failed runs do not create application-owned history; +- the test suite proves the stateless, atomic-output, batch, notification, and + security boundaries offline; +- an Accepted ADR records the architectural decision; and - canonical current-state documentation describes only the implemented - 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. + stateless lifecycle. diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md index 5b88f75..aabb088 100644 --- a/docs/roadmap/future.md +++ b/docs/roadmap/future.md @@ -3,6 +3,40 @@ This roadmap contains future work only. Each section identifies its planning 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 Status: Proposed and unimplemented. @@ -14,7 +48,9 @@ Possible direction: 1. Detect candidate storm events from alerts, forecast discussion, weather story context, hourly thresholds, and material forecast changes. 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. 5. Suppress ordinary low-impact thunder or rain chances. @@ -54,8 +90,7 @@ Status: Proposed and unimplemented. Possible future modules: - `hourly_table` for compact valid-period hourly facts -- `forecast_delta` if a separate stanza is useful beyond current Recent - Changes +- `forecast_delta` after an upstream forecast-change product exists - `weekend_planning` if weekend-specific planning guidance needs a dedicated deterministic stanza - `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 prompt-facing field shape inside module builders - 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 @@ -92,10 +127,8 @@ behavior is documented in the [Distributor adapter guide](../internal/distributo unimplemented: - `failure_policy: warn` -- uploading metadata, module snapshots, data packages, or preflight artifacts - durable upload retry queues - distributor-specific CLI flags -- distributor workspace scanning - destination routing, Markdown-to-HTML transformation, public URLs, or nginx layout inside weatherreporter @@ -138,6 +171,7 @@ maintenance costs make the added abstraction worthwhile: - global test helper package - logging subsystem -Any future implementation should preserve the existing public CLI, artifact -paths, report identities, module boundaries, and adapter boundaries unless a -separate roadmap explicitly changes them. +Any future implementation should preserve the public CLI, report-output +contract, report identities, module boundaries, and adapter boundaries in +effect when that work begins unless a separate roadmap explicitly changes +them. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md new file mode 100644 index 0000000..5c3176a --- /dev/null +++ b/docs/roadmap/implementation.md @@ -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.