382 lines
16 KiB
Markdown
382 lines
16 KiB
Markdown
# Stateless Execution Implementation Plan
|
|
|
|
Status: Complete.
|
|
|
|
## Purpose
|
|
|
|
This plan implements the accepted [Stateless Execution
|
|
Roadmap](ephemeral-state.md). The roadmap is authoritative for product intent,
|
|
policy choices, and the desired end state. This document records the completed
|
|
migration and records the remediation work completed during post-implementation
|
|
review.
|
|
|
|
Stages 1-18 are complete and are summarized below.
|
|
|
|
## Implementation Rules
|
|
|
|
1. Keep the repository buildable and `go test ./...` passing after every stage.
|
|
2. Follow all policies under `docs/policy/`, especially the architecture,
|
|
documentation, and risk-based testing requirements.
|
|
3. Preserve the accepted stateless contracts: no application-owned durable
|
|
workspace, no local Recent Changes comparison, one operator-owned output per
|
|
successful report, atomic publication, and explicit-only prompt debug
|
|
capture.
|
|
4. Preserve prompt and profile inspection before weather collection, exact
|
|
prompt versions, structured-output validation, repository-owned rendering,
|
|
deterministic report periods, batch membership, and Distributor upload of
|
|
published Markdown files.
|
|
5. Keep default tests deterministic and offline. Do not contact live Weather
|
|
API, Promptkit provider, or Distributor services.
|
|
6. Use behavior-focused regression tests at the narrowest stable boundary.
|
|
Avoid tests that merely encode private helper structure or call order.
|
|
7. Update canonical documentation in the same stage as any user-visible or
|
|
architectural behavior change. Do not create release notes until a release
|
|
version is selected.
|
|
8. Do not modify or reinterpret the Accepted stateless-execution ADR. A changed
|
|
architectural decision would require a new ADR; the remaining work does not
|
|
require one.
|
|
|
|
## Fixed Remediation Decisions
|
|
|
|
The following decisions are complete and require no further product input:
|
|
|
|
- A canceled generation must not publish or replace its selected output if
|
|
cancellation is observable before atomic publication begins.
|
|
- A batch must validate every planned report destination before starting any
|
|
report's Promptkit execution or output publication. Dynamic Daily
|
|
destinations may be validated after weather collection and batch planning,
|
|
because those dates are not known earlier.
|
|
- `BatchResult.Total`, `Succeeded`, and `Failed` count reports only. A batch
|
|
notification failure changes overall batch status and exit behavior through
|
|
the top-level notification result; it does not increment `Failed`.
|
|
- Batch report items do not expose per-report notification fields because batch
|
|
reports deliberately suppress per-report notification.
|
|
- Completed roadmap prose must distinguish the former persistent architecture
|
|
from current stateless behavior, and repository hygiene must no longer hide
|
|
an accidentally recreated root-level `workspace` directory.
|
|
|
|
## Completed Stages
|
|
|
|
### Stage 1: Record The Stateless Architecture Decision — Complete
|
|
|
|
Added the Accepted ADR recording the stateless transformation pipeline,
|
|
operator-owned output boundary, removal of local comparison and historical
|
|
inspection, atomic publication, and explicit debug-capture exception.
|
|
|
|
### Stage 2: Remove Recent Changes From The Prompt Contract — Complete
|
|
|
|
Removed Recent Changes from prompt input, advanced the data package to
|
|
`weatherreporter.data_package.v4`, and advanced all four embedded prompts to
|
|
exact version `2.0.0`.
|
|
|
|
### Stage 3: Delete Dormant Local Comparison Policy — Complete
|
|
|
|
Removed the local comparison implementation and `recent_change` configuration;
|
|
strict configuration loading now rejects the obsolete field.
|
|
|
|
### Stage 4: Establish The Operator-Owned Output Contract — Complete
|
|
|
|
Made every successful report publish one atomic Markdown output, added
|
|
current-working-directory defaults and explicit destination overrides, and
|
|
centralized report output naming.
|
|
|
|
### Stage 5: Separate Explicit Debug Capture From State — Complete
|
|
|
|
Moved secure opt-in Promptkit diagnostics into `internal/promptdebug` without
|
|
introducing implicit diagnostics or ordinary artifact persistence.
|
|
|
|
### Stage 6: Remove Notification Persistence — Complete
|
|
|
|
Removed notification receipts and changed Distributor delivery to consume the
|
|
published operator-owned output from the active workflow.
|
|
|
|
### Stage 7: Replace The Persisted Generation Workflow — Complete
|
|
|
|
Converted single and batch generation to in-memory orchestration and removed
|
|
ordinary persistence of snapshots, prompt packages, generated text, render
|
|
contexts, metadata, and managed reports.
|
|
|
|
### Stage 8: Remove Historical Inspection And Prior Compatibility — Complete
|
|
|
|
Removed the `inspect` command family, historical lookup, prior-run selection,
|
|
and metadata compatibility surfaces.
|
|
|
|
### Stage 9: Delete The Workspace And State Subsystem — Complete
|
|
|
|
Removed `internal/state`, workspace configuration, state-only helpers, and
|
|
legacy artifact models. Strict loading rejects the obsolete `workspace` stanza.
|
|
|
|
### Stage 10: Consolidate Stateless Behavioral Coverage — Complete
|
|
|
|
Replaced state-oriented fixtures with focused offline coverage of generation,
|
|
batching, atomic output, partial success, notification ordering, prompt
|
|
inspection, summaries, and explicit debug capture.
|
|
|
|
### Stage 11: Publish User, Operator, And Policy Documentation — Complete
|
|
|
|
Updated the CLI, operations, architecture, configuration, and documentation
|
|
policy owners for stateless operation and manual legacy-workspace cleanup.
|
|
|
|
### Stage 12: Reconcile Internal And Integration Documentation — Complete
|
|
|
|
Updated focused internal and integration documents to describe in-memory
|
|
orchestration, published-output notification sources, and the absence of
|
|
historical inspection.
|
|
|
|
### Stage 13: Run The Repository Exit Gate — Complete
|
|
|
|
Ran the complete offline test, race, vet, build, help, formatting, stale-string,
|
|
and documentation review gates and marked the initial migration implemented.
|
|
|
|
## Stage 14: Prevent Publication After Cancellation — Complete
|
|
|
|
### Goal
|
|
|
|
Close the cancellation window between successful Promptkit execution and
|
|
atomic output publication.
|
|
|
|
### Work
|
|
|
|
1. In the report workflow, check the active context after validation and
|
|
rendering have completed and immediately before calling the atomic file
|
|
writer.
|
|
2. If `ctx.Err()` is `context.Canceled`, wrap it in a
|
|
`promptexec.Canceled` error; if it is `context.DeadlineExceeded`, wrap it in
|
|
a `promptexec.DeadlineExceeded` error. Return that classified error through
|
|
the existing report-error surface. Preserve `errors.Is` behavior for the
|
|
underlying context error; do not collapse either case into a generic
|
|
rendering or output error.
|
|
3. Do not remove an output that was published before a later cancellation.
|
|
Cancellation observed after publication remains subject to the existing
|
|
notification and result behavior.
|
|
4. Add a focused app regression test whose fake executor returns valid output
|
|
but cancels the context before returning. Prove that generation fails and a
|
|
pre-existing destination remains byte-for-byte unchanged. This test must not
|
|
depend on the fake executor voluntarily returning a cancellation error.
|
|
5. Ensure the same workflow check protects every single-report and batch item;
|
|
do not add duplicate cancellation logic in CLI or batch orchestration.
|
|
|
|
### Tests
|
|
|
|
Run:
|
|
|
|
```sh
|
|
go test ./internal/app
|
|
go test ./...
|
|
go test -race ./internal/app
|
|
git diff --check
|
|
```
|
|
|
|
### Exit Gate
|
|
|
|
Cancellation observable before publication prevents the atomic write, the
|
|
selected destination remains unchanged, and cancellation identity is retained.
|
|
|
|
## Stage 15: Preflight Every Planned Batch Output — Complete
|
|
|
|
### Goal
|
|
|
|
Ensure a structural destination error cannot appear midway through a batch
|
|
after earlier reports have already been published.
|
|
|
|
### Work
|
|
|
|
1. After weather collection and `planBatchRun` have produced the complete
|
|
dynamic report set, resolve and validate the output path for every planned
|
|
report before executing the first report prompt.
|
|
2. Store each validated absolute output path with its planned report for use by
|
|
the generation loop. Do not recompute or revalidate destinations inside the
|
|
loop.
|
|
3. Treat any invalid path, including an existing directory at a report's final
|
|
filename, as a batch preflight error. Return before Promptkit execution and
|
|
before publication of any batch item. Weather collection may already have
|
|
occurred because eligible Daily dates depend on collected coverage.
|
|
4. Keep missing parent-directory creation in the atomic publication helper;
|
|
preflight must not create report files or introduce a new managed directory
|
|
lifecycle.
|
|
5. Add a focused app test using a real temporary output directory where a later
|
|
planned filename, such as `tomorrow.md`, already exists as a directory.
|
|
Assert that prompt inspection still occurs before collection, the executor's
|
|
prompt-execution method is never called, and no earlier report output is
|
|
created or replaced.
|
|
6. Retain the existing independent report-failure behavior after successful
|
|
preflight: a provider, validation, rendering, or publication failure for one
|
|
report remains an item failure, later items continue, and successful outputs
|
|
remain available.
|
|
|
|
### Tests
|
|
|
|
Run:
|
|
|
|
```sh
|
|
go test ./internal/app
|
|
go test ./internal/fileutil
|
|
go test ./...
|
|
git diff --check
|
|
```
|
|
|
|
### Exit Gate
|
|
|
|
Every selected batch destination is validated before any batch report executes,
|
|
and a destination collision cannot yield an unreported partial batch.
|
|
|
|
## Stage 16: Separate Report Counts From Batch Notification Status — Complete
|
|
|
|
### Goal
|
|
|
|
Restore coherent batch counters while preserving failed status and non-zero
|
|
exit behavior when the batch notification fails.
|
|
|
|
### Work
|
|
|
|
1. Define and enforce the invariant
|
|
`Total == Succeeded + Failed == len(Reports)` after report execution.
|
|
`Succeeded` and `Failed` count only report-item statuses.
|
|
2. Remove the increment of `BatchResult.Failed` when `notifyBatch` returns an
|
|
error. Preserve the failed top-level `BatchNotificationResult`, including
|
|
its safe error and identity fields.
|
|
3. Update the `RunBatch` wrapper to return `BatchError` when either a report
|
|
failed or the top-level batch notification failed. Keep
|
|
`RunBatchDetailed` returning the populated result according to its existing
|
|
detailed-result contract.
|
|
4. Retain CLI behavior in which the batch summary status is failed and the
|
|
command exits unsuccessfully for a batch notification failure, even though
|
|
all report counters show success.
|
|
5. Make `BatchError` use report counts only for report-failure wording and its
|
|
existing notification-specific wording when the reports succeeded but the
|
|
notification failed.
|
|
6. Add focused app and CLI tests for a batch whose reports all publish
|
|
successfully but whose batch notifier fails. Assert:
|
|
- `Total == Succeeded == len(Reports)` and `Failed == 0`;
|
|
- every output remains present;
|
|
- the top-level notification status is `failed`;
|
|
- the summary status is `failed`;
|
|
- the returned error describes notification failure rather than claiming a
|
|
report failed; and
|
|
- the action exits unsuccessfully.
|
|
|
|
### Tests
|
|
|
|
Run:
|
|
|
|
```sh
|
|
go test ./internal/app ./internal/cli
|
|
go test ./...
|
|
git diff --check
|
|
```
|
|
|
|
### Exit Gate
|
|
|
|
Batch report counters are internally consistent, while notification failure
|
|
still produces a failed summary, safe diagnostic, retained outputs, and
|
|
non-zero command result.
|
|
|
|
## Stage 17: Remove Impossible Per-Report Notification State — Complete
|
|
|
|
### Goal
|
|
|
|
Align batch result types and stderr output with the architecture in which
|
|
per-report notification is suppressed and delivery is represented once at the
|
|
batch level.
|
|
|
|
### Work
|
|
|
|
1. Remove `NotificationStatus`, `NotificationRunID`,
|
|
`NotificationPipelineID`, and `NotificationError` from
|
|
`BatchReportResult`.
|
|
2. Remove the unreachable copying of `ReportResult.Notification` into a batch
|
|
item. Rename `copyBatchReportPaths` to reflect that it copies the current
|
|
safe report result fields rather than only paths, or replace it with an
|
|
equally clear narrow helper.
|
|
3. Remove per-report notification formatting from `writeBatchStatus`. Keep the
|
|
top-level `batchNotification` status line and the batch summary
|
|
`notification` object unchanged.
|
|
4. Search tests and documentation for the removed per-report fields. Delete
|
|
stale assertions or descriptions rather than adding compatibility fields;
|
|
no backward compatibility is required for this pre-release result cleanup.
|
|
5. Retain single-report notification fields and behavior. This stage changes
|
|
only batch report items.
|
|
|
|
### Tests
|
|
|
|
Run:
|
|
|
|
```sh
|
|
go test ./internal/app ./internal/cli
|
|
go test ./...
|
|
git diff --check
|
|
```
|
|
|
|
### Exit Gate
|
|
|
|
Batch items expose only report-generation facts, and all batch delivery state
|
|
is represented by the single top-level notification result.
|
|
|
|
## Stage 18: Reconcile Documentation And Run The Remediation Exit Gate — Complete
|
|
|
|
### Goal
|
|
|
|
Remove the remaining documentation and repository-hygiene traces of the former
|
|
workspace architecture and verify the remediated implementation as a whole.
|
|
|
|
### Work
|
|
|
|
1. In `docs/roadmap/ephemeral-state.md`, rename `Current State` to
|
|
`Former State`, convert its description of persistence and Recent Changes to
|
|
past tense, and reconcile other implementation-future phrasing with the
|
|
roadmap's Implemented status. Preserve the roadmap's product intent and
|
|
desired end state; do not turn it back into a staged plan.
|
|
2. Remove the root-level `/workspace` ignore rule from `.gitignore` and update
|
|
its adjacent comment. Legacy workspace cleanup remains an explicit operator
|
|
procedure in `docs/operations.md`; removing the ignore rule must not delete
|
|
any operator data or add automated cleanup.
|
|
3. Review the canonical CLI, operations, architecture, app-orchestration, and
|
|
testing documentation for the Stage 14-17 behavior. Update only documents
|
|
whose owned contract changed, avoiding duplicate definitions.
|
|
4. Search production code, tests, examples, and current-state documentation
|
|
for:
|
|
- stale per-report batch notification fields;
|
|
- report counters that include notification failures;
|
|
- output validation performed inside the batch execution loop;
|
|
- claims that cancellation can publish an output;
|
|
- present-tense descriptions of the removed workspace; and
|
|
- active ignore rules or defaults that conceal a workspace tree.
|
|
5. Confirm ordinary generation and batch tests use isolated temporary
|
|
directories and leave only the selected Markdown outputs unless explicit
|
|
prompt debug capture is requested.
|
|
6. Run formatting and all repository validation gates. Review the complete
|
|
remediation diff for unrelated changes, content leakage, compatibility
|
|
shims, and unnecessary abstractions.
|
|
7. When every exit gate passes, mark Stages 14-18 and this plan Complete. Keep
|
|
the feature roadmap marked Implemented. Do not create, tag, or publish a
|
|
release in this 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
|
|
```
|
|
|
|
Verify all changed repository-relative documentation links resolve and inspect
|
|
`git status --short` for an accidentally created root-level `workspace` tree.
|
|
|
|
### Exit Gate
|
|
|
|
The remediated stateless workflow honors cancellation before publication,
|
|
preflights complete batch destinations, reports coherent batch counts, exposes
|
|
only reachable notification state, and has documentation and repository
|
|
hygiene consistent with the implemented architecture.
|
|
|
|
## Open Questions
|
|
|
|
None. The roadmap, accepted ADR, and remediation decisions above provide all
|
|
product and architectural choices required to implement Stages 14-18.
|