Integrate cleanup into pipeline execution
This commit is contained in:
11
docs/cli.md
11
docs/cli.md
@@ -153,7 +153,7 @@ Behavior:
|
||||
|
||||
- evaluates one inclusive contiguous range of the canonical stage order;
|
||||
- defaults an omitted `--from` to `prepare` and an omitted `--through` to
|
||||
`notify`, so omitting both retains full-pipeline behavior;
|
||||
`cleanup`, so omitting both retains full-pipeline behavior;
|
||||
- rejects unknown endpoints and a `--from` endpoint after `--through`;
|
||||
- runs `render` before `extract`; an omitted or disabled Notarius
|
||||
configuration records an explicit `notarius_disabled` self-skip;
|
||||
@@ -213,6 +213,7 @@ Valid stage names:
|
||||
- `analyze`
|
||||
- `publish`
|
||||
- `notify`
|
||||
- `cleanup`
|
||||
|
||||
Rules:
|
||||
|
||||
@@ -242,6 +243,10 @@ Equivalent to:
|
||||
narratio run-stage publish <session_id> --force [...common config flags]
|
||||
```
|
||||
|
||||
This command selects only `publish`; it does not invoke cleanup. Use a normal
|
||||
full run to include configured cleanup, or `run-stage cleanup` to retry cleanup
|
||||
from valid publication evidence.
|
||||
|
||||
### `clean`
|
||||
|
||||
```bash
|
||||
@@ -255,8 +260,8 @@ Behavior:
|
||||
- `--all` removes all local session work and spool state;
|
||||
- cache remains unless `--clear-cache` is provided.
|
||||
|
||||
See [Operations: Cleanup](./operations.md#cleanup) for deletion scope and
|
||||
post-publish cleanup behavior.
|
||||
See [Operations: Cleanup](./operations.md#cleanup) for manual and pipeline-stage
|
||||
deletion scope.
|
||||
|
||||
### `session plan`
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ The pipeline runner follows one explicit invocation lifecycle: inspect bounded
|
||||
prerequisites without mutation, prepare the workspace layout, acquire one
|
||||
session lock, load or create the authoritative session manifest, compose only
|
||||
the collaborators needed by the selected range, execute each selected stage in
|
||||
order, complete any required post-publish cleanup, and then return the summary.
|
||||
order, and then return the summary. Cleanup, when selected, is the ordinary
|
||||
final stage rather than runner finalization work.
|
||||
The lock remains held from manifest initialization through finalization, and a
|
||||
failed stage or required manifest save prevents later stages from starting.
|
||||
|
||||
@@ -35,7 +36,7 @@ failed stage or required manifest save prevents later stages from starting.
|
||||
| Area | Implemented owners | Responsibility |
|
||||
| --- | --- | --- |
|
||||
| Executable | `cmd/narratio` | Process entry, standard stream wiring, argument handoff, and exit status. |
|
||||
| Application orchestration | `internal/app` | Command dispatch, configuration selection, secret-file environment loading, production composition, session locking, planning, execution, restore, cleanup gates, and user-facing reporting. |
|
||||
| Application orchestration | `internal/app` | Command dispatch, configuration selection, secret-file environment loading, production composition, session locking, planning, execution, restore, and user-facing reporting. |
|
||||
| Configuration | [`internal/config`](configuration.md) | Presence-aware root/import/profile composition, canonical party and family expansion, strict YAML loading, defaults, normalization, session templating, and validation. |
|
||||
| Pipeline stages | `internal/stage` | Canonical stage registry, shared stage contract, execution dependencies, and implemented stage behavior. |
|
||||
| External boundaries | `internal/adapters`, `internal/audio` | WhisperX HTTP, downstream subprocesses, notification, object storage, and S3 audio materialization behind Narratio contracts. |
|
||||
@@ -78,6 +79,7 @@ The implemented canonical order is:
|
||||
9. [`analyze`](stage-analyze.md)
|
||||
10. [`publish`](stage-publish.md)
|
||||
11. `notify` (no-op)
|
||||
12. [`cleanup`](stage-cleanup.md)
|
||||
|
||||
`notify` currently has no persisted pipeline outputs and uses the explicit
|
||||
`noop` notification mode. Its versioned semantic evidence records that delivery
|
||||
@@ -91,7 +93,8 @@ registry owns the flat execution sequence. The application orchestration owner
|
||||
uses a fixed, validated dependency relation to find transitive dependents in
|
||||
canonical order. In particular, `render` and `extract` are sibling consumers of
|
||||
trimmed transcript state: neither invalidates the other, while either can stale
|
||||
`analyze`, `publish`, and `notify`.
|
||||
`analyze`, `publish`, `notify`, and `cleanup`. Cleanup is a dependent of notify,
|
||||
so any earlier replacement can stale a prior cleanup result.
|
||||
|
||||
## Focused Documentation
|
||||
|
||||
@@ -118,6 +121,7 @@ trimmed transcript state: neither invalidates the other, while either can stale
|
||||
- [`extract`](stage-extract.md)
|
||||
- [`analyze`](stage-analyze.md)
|
||||
- [`publish`](stage-publish.md)
|
||||
- [`cleanup`](stage-cleanup.md)
|
||||
|
||||
Use this map to find an owner, then read its focused documentation and tests
|
||||
before changing behavior.
|
||||
|
||||
54
docs/internal/stage-cleanup.md
Normal file
54
docs/internal/stage-cleanup.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Stage: cleanup
|
||||
|
||||
## Purpose
|
||||
|
||||
Remove explicitly configured local data for the run selected by a successful
|
||||
publish commit. Cleanup is the twelfth and final canonical stage, after
|
||||
`notify`.
|
||||
|
||||
## Authorization And Targets
|
||||
|
||||
Cleanup is disabled unless at least one of these policies is true:
|
||||
|
||||
- `pipeline.spool.delete_audio_after_publish`
|
||||
- `pipeline.workspace.cleanup_after_publish`
|
||||
|
||||
An enabled cleanup requires the manifest's publish stage to be succeeded with
|
||||
`uploaded=true`, a canonical `published_run_id`, and the exact remote commit and
|
||||
current commit-pointer keys for the manifest campaign/session prefix. The
|
||||
configured campaign and session must match the manifest. Cleanup derives its
|
||||
only possible targets through the canonical artifact path helpers:
|
||||
|
||||
- the published run's session spool-audio directory; and
|
||||
- the published run's workspace run directory.
|
||||
|
||||
It does not scan parent directories, infer the newest run, or read object
|
||||
storage. Every deletion uses the root-confined file operation, which rejects a
|
||||
root itself, traversal, symlink escape, and out-of-root targets.
|
||||
|
||||
## Execution And Resume
|
||||
|
||||
Disabled cleanup records an explicit skipped result. Enabled cleanup removes
|
||||
targets in deterministic policy order and treats an already-missing target as
|
||||
success. A successful record contains the published run ID and completed policy
|
||||
names.
|
||||
|
||||
A previous cleanup success is reusable only while its semantic configuration
|
||||
matches and every selected target remains absent. A recreated target makes the
|
||||
stage non-resumable. A failure is recorded against cleanup; publish remains
|
||||
succeeded and remote current state is unchanged. On a later normal full run,
|
||||
valid upstream stages are skipped and cleanup is retried without republishing.
|
||||
|
||||
`narratio publish` selects publish only and never invokes cleanup. A bounded run
|
||||
through `notify` or any earlier endpoint also excludes it. Operators may run
|
||||
`narratio run-stage cleanup <session_id>` directly; missing, failed, malformed,
|
||||
or identity-mismatched publication evidence fails before deletion.
|
||||
|
||||
## Implementation And Tests
|
||||
|
||||
- Planning and evidence validation: `internal/stage/cleanup_plan.go`
|
||||
- Execution and resume: `internal/stage/cleanup.go`
|
||||
- Root-confined deletion: `internal/fileops/cleanup.go`
|
||||
- Focused tests: `internal/stage/cleanup_plan_test.go`,
|
||||
`internal/stage/cleanup_test.go`, and
|
||||
`internal/app/cleanup_orchestration_test.go`
|
||||
@@ -109,8 +109,8 @@ Includes counts/lists for:
|
||||
- independent publish locks are not overridden by `--force`; every initially
|
||||
unlocked relevant source is reread immediately before current-state
|
||||
selection.
|
||||
- post-commit local cleanup is authorized by the committed publish metadata and
|
||||
is durably recorded by the application lifecycle before any local deletion.
|
||||
- successful uploaded publication records the exact run ID, remote commit key,
|
||||
and current-pointer key consumed by the later cleanup stage.
|
||||
|
||||
## Resume Semantics
|
||||
|
||||
@@ -123,9 +123,12 @@ and run identifiers are excluded. Independent remote locks remain mutable state
|
||||
and are read directly by publish at planning and commit boundaries; semantic
|
||||
evidence does not replace those safety checks.
|
||||
|
||||
The commit boundary and cleanup gate are normative architecture invariants; see
|
||||
The commit boundary and cleanup authorization are normative architecture invariants; see
|
||||
[Architecture](../policy/architecture.md#publish-commit-boundary).
|
||||
|
||||
Publish never deletes local state. The standalone `publish` command selects
|
||||
only this stage; a full run selects notify and cleanup afterward.
|
||||
|
||||
## Related Contracts And Tests
|
||||
|
||||
- [Configuration](../config.md#publish-configuration-summary) owns output
|
||||
@@ -141,4 +144,4 @@ The commit boundary and cleanup gate are normative architecture invariants; see
|
||||
`internal/stage/publish_test.go`,
|
||||
`internal/stage/semantic_contracts_delivery.go`,
|
||||
`internal/app/operator_helpers_test.go`, and
|
||||
`internal/app/post_publish_cleanup_test.go`
|
||||
`internal/app/cleanup_orchestration_test.go`
|
||||
|
||||
@@ -47,18 +47,18 @@ lock only while their context remains active, and report a release failure.
|
||||
|
||||
## Cleanup Semantics
|
||||
|
||||
Automatic post-publish cleanup:
|
||||
The canonical cleanup stage:
|
||||
|
||||
- is created only after a successful publish commit with complete publish
|
||||
metadata, then is persisted before any deletion;
|
||||
- requires `uploaded=true`, a remote commit key, and a current commit-pointer
|
||||
key in publish metadata;
|
||||
- runs after notify only when selected by the invocation range;
|
||||
- requires a succeeded publish record with `uploaded=true`, the published run
|
||||
ID, remote commit key, and current commit-pointer key;
|
||||
- consumes the resolved cleanup policy described in
|
||||
[Configuration](../config.md);
|
||||
- refuses unsafe deletes (root delete, traversal, and out-of-root targets);
|
||||
- retries any recorded incomplete target on later invocations even when no
|
||||
publish work is selected. Missing targets are a successful, idempotent
|
||||
cleanup result only after the completion evidence is saved.
|
||||
- treats missing targets as successful, idempotent deletion; and
|
||||
- uses its ordinary failed/succeeded manifest stage record for retry. A later
|
||||
full run can skip reusable upstream stages and retry cleanup without
|
||||
republishing.
|
||||
|
||||
Manual cleanup uses the same root-confined deletion mechanism. Invocation
|
||||
syntax and exact deletion scope belong in [CLI](../cli.md#clean) and
|
||||
@@ -82,9 +82,11 @@ syntax and exact deletion scope belong in [CLI](../cli.md#clean) and
|
||||
- Immutable bundle installation: `internal/stage/extract.go`
|
||||
- Workspace modes: `internal/fileops/modes.go`
|
||||
- Cleanup confinement: `internal/fileops/cleanup.go`,
|
||||
`internal/app/cleanup_targets.go`, `internal/app/post_publish_cleanup.go`
|
||||
`internal/stage/cleanup.go`, `internal/stage/cleanup_plan.go`, and
|
||||
`internal/app/cleanup_targets.go`
|
||||
- Tests: `internal/artifacts/paths_model_test.go`,
|
||||
`internal/artifacts/local_test.go`, `internal/stage/run_local_test.go`,
|
||||
`internal/fileops/modes_posix_test.go`,
|
||||
`internal/fileops/cleanup_test.go`, `internal/app/cleanup_targets_test.go`,
|
||||
`internal/app/post_publish_cleanup_test.go`
|
||||
`internal/stage/cleanup_test.go`, and
|
||||
`internal/app/cleanup_orchestration_test.go`
|
||||
|
||||
@@ -98,6 +98,7 @@ Canonical stage order:
|
||||
9. `analyze`
|
||||
10. `publish`
|
||||
11. `notify`
|
||||
12. `cleanup`
|
||||
|
||||
Execution rules:
|
||||
|
||||
@@ -154,7 +155,7 @@ narratio run 2026-04-04 --from extract --through analyze --force
|
||||
```
|
||||
|
||||
Omitting `--from` selects from `prepare`; omitting `--through` selects through
|
||||
`notify`. Force applies only within the selected range. Repeating `--from`,
|
||||
`cleanup`. Force applies only within the selected range. Repeating `--from`,
|
||||
`--through`, or `--force` is rejected instead of resolving by argument order.
|
||||
The plan command uses the same selection contract and prints only the selected
|
||||
range. Planning is read-only: it clones the loaded manifest, models selected
|
||||
@@ -194,8 +195,8 @@ This command is a transparent expansion to a forced bounded `run` from
|
||||
`extract` through `analyze`. Extraction always rebuilds its complete configured
|
||||
bundle. Analysis rebuilds the selected targets and their required analysis
|
||||
prerequisites, or uses the normal default selection when no artifact names are
|
||||
given. The command does not run publish or notify; delivery remains a separate
|
||||
operator action.
|
||||
given. The command does not run publish, notify, or cleanup; delivery and
|
||||
retention remain separate operator actions.
|
||||
|
||||
Inspect current artifact evidence, then publish explicitly when the regenerated
|
||||
set is ready:
|
||||
@@ -365,6 +366,9 @@ Equivalent:
|
||||
narratio run-stage publish 2026-04-04 --force
|
||||
```
|
||||
|
||||
This standalone command stops after publish and does not invoke cleanup. A
|
||||
default full `run` continues through notify and cleanup.
|
||||
|
||||
Publish commit model:
|
||||
|
||||
- uploads eligible run files under `{session_prefix}/runs/{run_id}/`, excluding
|
||||
@@ -591,16 +595,20 @@ Rules:
|
||||
- cache is preserved unless `--clear-cache` is set;
|
||||
- each deletion is confined beneath its configured workspace, spool, or cache
|
||||
root; root, traversal, and out-of-root targets are refused;
|
||||
- automatic post-publish cleanup is gated by successful publish commit plus:
|
||||
- the final cleanup stage is gated by successful publish evidence plus:
|
||||
- `pipeline.spool.delete_audio_after_publish=true`
|
||||
- `pipeline.workspace.cleanup_after_publish=true`
|
||||
- Narratio first records the exact run-scoped cleanup obligation. If cleanup
|
||||
reports incomplete, the remote committed snapshot remains current; rerun
|
||||
publish to retry only the outstanding confined local cleanup.
|
||||
- the manifest publish record has `uploaded=true`, the published run ID, the
|
||||
exact remote commit key, and the current commit-pointer key.
|
||||
|
||||
Post-publish cleanup is evaluated only when `publish` actually executes in the
|
||||
current invocation. A bounded range that excludes publish does not replay a
|
||||
cleanup obligation as an unrelated side effect.
|
||||
Cleanup derives only the configured run-scoped spool and workspace targets,
|
||||
uses root-confined deletion, and does not read or mutate object storage. A
|
||||
failure leaves publish succeeded and the remote committed snapshot current.
|
||||
Retry with a normal full run: valid upstream work, including publish and notify,
|
||||
is skipped while the failed cleanup stage runs again. `run-stage cleanup` is
|
||||
also available when the manifest has valid publish evidence. A range ending at
|
||||
`notify` or earlier and the standalone `publish` command never delete local
|
||||
state.
|
||||
|
||||
## Operational Caveats
|
||||
|
||||
|
||||
@@ -185,8 +185,8 @@ availability.
|
||||
Writes, moves, replacements, and deletions must use narrow, explicit,
|
||||
root-confined destinations. Symlinks, traversal, broad roots, and ambiguous
|
||||
relative destinations must not expand the scope of an operation. Cleanup is
|
||||
permitted only through explicit operator action or configured post-publish
|
||||
gates, and it must preserve durable cache unless cache removal is explicitly
|
||||
permitted only through explicit operator action or the configured final cleanup
|
||||
stage, and it must preserve durable cache unless cache removal is explicitly
|
||||
requested.
|
||||
|
||||
Physical layout, retention, and operational lifecycle belong in
|
||||
@@ -212,10 +212,16 @@ transaction boundary.
|
||||
|
||||
Automatic local cleanup is permitted only after a successful publish commit,
|
||||
only when explicitly configured, and only through the path-safety guardrails.
|
||||
It is a durable local obligation bound to that committed run and its exact
|
||||
targets, not an inferred side effect of the current stage list. A cleanup
|
||||
failure makes the invocation incomplete while leaving the committed remote
|
||||
snapshot authoritative; later invocations resume the recorded obligation.
|
||||
It is the final ordinary pipeline stage after `notify`. The stage derives its
|
||||
exact run-scoped targets from validated publish metadata and the configured
|
||||
campaign/session identity; it never infers a target from directory contents or
|
||||
rereads remote storage. A cleanup failure makes the invocation incomplete while
|
||||
leaving publish succeeded and the committed remote snapshot authoritative. A
|
||||
normal later full run reuses valid upstream stages and retries cleanup.
|
||||
|
||||
The standalone `publish` command selects only publish and therefore never
|
||||
invokes cleanup. Operators may select cleanup directly only when the manifest
|
||||
contains valid successful publication evidence.
|
||||
|
||||
## Security, Privacy, And Diagnostics
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ filesystem and manifest contracts.
|
||||
|
||||
## Stage 3 — Integrate Cleanup Into Canonical Orchestration
|
||||
|
||||
**Status:** Pending
|
||||
**Status:** Completed
|
||||
|
||||
### Goal
|
||||
|
||||
|
||||
Reference in New Issue
Block a user