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
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.