Files
narratio/docs/operations.md

417 lines
15 KiB
Markdown

# Operations Guide
Operator workflow for running, recovering, and publishing Narratio sessions.
For command syntax, see [docs/cli.md](./cli.md). For field-level config, see [docs/config.md](./config.md).
## Campaign and Session Selection
Campaign selection priority:
- `--campaign-file`
- `--campaign`
- `pipeline.campaigns.default_campaign_id`
Session source priority:
- `--session`
- local default search paths
- remote session object (S3) when local session file is not found and storage is configured
## Session Initialization
Use `session init` to generate a concrete session file for local or remote use.
Local file:
```bash
narratio session init 2026-04-04 --output ./session.yml --date 2026-04-04 --title "Session 12"
```
Remote session object:
```bash
narratio session init 2026-04-04 --remote --force
```
If `campaign.yml` sets `session_template_file`, `session init` renders it. Template variables must resolve to concrete values.
Campaigns must provide stable input files for speakers, autocorrect, glossary, players, and party. Session files may override those paths for one session. The `prepare` stage materializes them under `inputs/`; configured Scriptorium artifacts can reference prepared `players`, `party`, and `glossary` files with `narratio.input.players`, `narratio.input.party`, and `narratio.input.glossary`.
## Standard Session Workflow
1. Select pipeline/campaign/session config.
2. Validate session readiness:
```bash
narratio session validate 2026-04-04
```
3. (Optional) inspect stage decisions:
```bash
narratio session plan 2026-04-04
```
4. Run the pipeline:
```bash
narratio run 2026-04-04
```
5. Check state:
```bash
narratio session status 2026-04-04
```
## Stage Execution and Continuation Behavior
Canonical stage order:
1. `prepare`
2. `transcribe`
3. `merge`
4. `polish`
5. `normalize`
6. `trim`
7. `extract`
8. `render`
9. `analyze`
10. `publish`
11. `notify`
Execution rules:
- succeeded stages are skipped unless `--force` is set;
- `run` continues interrupted or partially completed sessions by running non-succeeded stages;
- forcing an upstream stage marks succeeded downstream stages as `stale` before
the replacement runs; and
- an executed failure, changed self-skip, or success that replaces a different
effective upstream outcome also marks succeeded downstream stages stale. A
repeated self-skip with the same reason and no outputs is stable and does not
perpetually rerun downstream work.
An explicit self-skip is a durable `skipped` stage outcome that later runs
reconsider. It differs from successful no-output execution: disabled `render`
and `publish`, and absent or no-executable `analyze`, record `succeeded` with
metadata and no outputs. Ordinary later runs reuse those successful results;
force the affected stage after enabling or configuring it. Optional artifact
inputs are omitted only from the consuming artifact invocation and do not make
the stage self-skip.
Single-stage execution:
```bash
narratio run-stage normalize 2026-04-04 --force
```
## Artifact Selection
`--artifacts` can be used on `run`, `run-stage`, `analyze`, and `publish`.
Selection behavior:
- validates names against `pipeline.scriptorium.artifacts`;
- filters analyze execution to selected configured artifacts;
- filters publish rules for `narratio.artifact.<name>` sources only;
- does not suppress built-in transcript, bounds, or explicitly configured
`narratio.extraction.<name>` publish sources; and
- never partially selects Notarius lanes.
## Extraction Workflow
When Notarius is omitted or disabled, `extract` records an explicit skipped
outcome with reason `notarius_disabled` and no outputs. A later invocation
reconsiders the skipped stage, so enabling Notarius does not require force.
When Notarius extraction is enabled, the stage consumes the final trimmed JSON
and preserves the complete validated Notarius bundle at:
- `artifacts/notarius/{narratio_run_id}/`
The directory is immutable once promoted. Configured lanes become
`narratio.extraction.<name>` sources for Scriptorium and explicit publish rules;
the bundle and `index.json` are retained for audit and resume validation but
are not selectable or published implicitly.
Starting a replacement clears the previous extraction payload from the current
session-stage record. If that replacement fails or self-skips, the current
record does not fall back to the earlier outputs. The earlier run manifest and
immutable bundle remain available for inspection, but downstream resolution
requires a new current successful extraction record.
Atomic Notarius bundle promotion is supported on Linux and macOS. On Windows
and other operating systems, extraction fails before copying the bundle into a
temporary promotion tree because Narratio has no verified atomic no-replace
directory primitive there. This is an extraction limitation, not a broader
platform-support guarantee for every Narratio workflow.
## External Command Lifecycle
When an external command is cancelled or times out, Narratio terminates its
owned descendants as well as the command itself. Cancellation first requests
termination where the platform supports it, then force terminates after a
bounded wait. A command is not considered finished until its leader has been
reaped, and descendants that keep standard output or error open cannot keep
the invocation blocked. Other operating systems fail closed rather than launch
a command without tree ownership.
Subprocess stdout and stderr diagnostics are separately redacted and capped at
8 MiB per invocation. Narratio does not retain configured credential values in
these logs or their error tails; reaching a capture limit terminates the command
tree and reports which stream exceeded the limit.
Run-local diagnostics are:
- `runs/{run_id}/extract/notarius.receipt.json`
- `runs/{run_id}/extract/notarius.stderr.log`
- `runs/{run_id}/extract/notarius-output/` before durable promotion
The run-record upload is an allowlist derived from the validated run manifest,
not a workspace scan. Each declared source is opened without following
symlinked ancestors or the leaf, verified as a regular file, and streamed from
that verified descriptor. Unlisted files and unsafe entries are never uploaded.
The durable bundle is never scanned for implicit publication; only lanes named
by explicit `pipeline.publish.outputs` rules are uploaded.
To intentionally replace the current extraction result, run:
```bash
narratio run-stage extract 2026-04-04 --force
```
Narratio automatically reruns extraction when its recorded invocation contract
or durable output validation changes. It cannot fingerprint configuration
files, profiles, prompts, modules, or references loaded transitively by
Notarius. Force extraction after changing any of those inputs, even when the
top-level Narratio and Notarius config paths remain the same. A forced extract
marks successful downstream stages stale. Ordinary extraction failures or
outcome changes also stale affected downstream stages, while an identical
repeated `notarius_disabled` self-skip does not repeatedly invalidate them.
## Publish Workflow
Run publish only:
```bash
narratio publish 2026-04-04
```
Equivalent:
```bash
narratio run-stage publish 2026-04-04 --force
```
Publish commit model:
- uploads eligible run files under `{session_prefix}/runs/{run_id}/`, excluding
audio and the run-local Notarius staging bundle;
- uploads configured published outputs and `previous/**` cache files into the
same immutable run scope, including only explicitly configured extraction
lanes;
- writes `{session_prefix}/runs/{run_id}/commit.json` after all declared
immutable objects are uploaded and verified; and
- writes `{session_prefix}/current/commit-pointer.json` once, last.
`current/commit-pointer.json` is the remote current-state commit marker. It
selects exactly one immutable commit, which declares the complete object set.
## Remote Commit Migration
The immutable remote commit contract uses
`runs/{run_id}/commit.json` to declare a run's complete object set and a small
`current/commit-pointer.json` to select it. The pointer binds the selected
commit by version, checksum, size, and storage generation; committed artifacts
are also checksum- and generation-bound. Readers accept this contract now and
strictly reject mismatched or unknown data.
Legacy reads are limited to a coherent `current/manifest.json` and
`current/run_id.txt` pair; a torn pair is rejected. New publication does not
write that pair and remote commit state does not carry local
`current_pointer_written` metadata.
## Publish Locks
Lock sources:
- static locks in `pipeline.publish.locks`
- mutable remote locks in `{session_prefix}/locks.yml`
Effective lock rules:
- static and remote locks are merged;
- static locks win on source collisions;
- locked outputs are intentional skips;
- lock add/remove commands mutate only remote lock state through generation-bound
conditional writes. A command retries a bounded number of concurrent
conflicts while its invocation context remains active, so it never replaces a
different lock-document generation; and
- a publish re-reads remote locks immediately before it writes the current
commit pointer. A lock committed before that recheck prevents selecting the
new snapshot, even though its already-uploaded immutable objects may remain
available for a later retry.
Examples:
```bash
narratio session locks 2026-04-04
narratio session locks add 2026-04-04 narratio.artifact.session_recap --reason "manual edits" --force
narratio session locks remove 2026-04-04 narratio.artifact.session_recap
```
## Restore Workflow
Use restore when local durable session state is missing or stale and remote committed current state is authoritative.
Dry run:
```bash
narratio session restore 2026-04-04 --dry-run
```
Apply:
```bash
narratio session restore 2026-04-04
```
`--dry-run` does not write durable session files. It still reads the selected
remote current state and may read object identity/content needed to classify the
plan, so it is not a network-free operation.
Default restore scope:
- the committed session manifest and the committed transcript/artifact objects
declared by the selected remote commit
- `previous/**` when needed by configured previous-session artifact inputs
Optional:
- `--include-audio` to include `audio/**`
- `--force` to overwrite eligible conflicting regular files; it never replaces
directories or other non-regular local targets
Restore writes an execution report at `reports/restore-latest.json`.
If restore fails after beginning installation, it leaves a durable
`.restore-incomplete.json` marker in the session root. Pipeline runs will stop
until you rerun the same restore command and it completes. Restore intentionally
does not try to roll back files already installed; retrying the selected remote
snapshot is the recovery procedure.
## Local State Layout
Session root:
- `{workspace.root}/work/{campaign}/{session_id}`
Durable session paths:
- `manifest.json`
- `inputs/**`
- `audio/**`
- `transcripts/**`
- `artifacts/**`
- `previous/**`
- `reports/**`
- `logs/**`
- `config/**`
- `runs/**`
Validated Notarius bundles live below `artifacts/notarius/{run_id}/`; receipt,
stderr, and pre-promotion output remain in the producing run's `extract`
directory as described in [Extraction Workflow](#extraction-workflow).
Run-local layout:
- `runs/{run_id}/{stage}/outputs`
- `runs/{run_id}/{stage}/logs`
- `runs/{run_id}/{stage}/reports`
- `runs/{run_id}/{stage}/config`
- `runs/{run_id}/{stage}/scratch`
Spool layout (runtime/transient):
- `{spool.root}/{campaign}/{session_id}/{run_id}/...`
- restore audio spool under `{spool.root}/{campaign}/{session_id}/restore/audio`
Cache layout (durable S3 audio cache):
- `{cache.root}/s3/{bucket}/...`
Each cached audio file has an adjacent managed identity record. It binds the
file to its remote object version and verified digest; deleting or altering the
record simply causes Narratio to download and verify the object again.
### Workspace Permissions
Ordinary Narratio workspace content is intentionally shareable with the
workspace group. On POSIX systems, Narratio-created workspace, spool, and cache
directories converge on setgid `02775`; ordinary files, including manifests,
transcripts, generated configuration, logs, reports, and Notarius artifacts,
converge on `0664`. Narratio explicitly applies these modes so a restrictive
caller umask does not remove group write or setgid. It does not change file or
directory ownership: the configured workspace's existing group is inherited.
Windows does not implement POSIX mode bits or setgid semantics. Configure the
workspace, spool, and cache locations with an ACL that grants the collaborating
group read/write access, and configure credential locations with an ACL limited
to the intended credential owner. Do not use POSIX mode displays as evidence of
Windows access control.
API keys are credentials, not ordinary workspace data. Store them outside the
shared workspace or in a separately restricted credential location; ordinary
workspace group access must never be treated as authorization to read keys.
On POSIX, provision a credential directory as `0700` and credential files as
`0600`; Narratio rejects group- or other-readable configured credential paths.
On Windows, restrict the directory and files with ACLs to the credential owner.
External adapter results are individually bounded before Narratio validates or
materializes them. These per-file limits do not reserve disk space: prevent hard
disk exhaustion with filesystem, service, container, or volume quotas sized for
the session workload.
## Cleanup
Session-scoped cleanup:
```bash
narratio clean 2026-04-04
```
Global cleanup:
```bash
narratio clean --all
```
Dry-run and cache variants:
```bash
narratio clean 2026-04-04 --dry-run --clear-cache
narratio clean --all --dry-run --clear-cache
```
Rules:
- `clean` deletes work/spool session state;
- cache is preserved unless `--clear-cache` is set;
- each deletion is confined beneath its configured workspace, spool, or cache
root and refuses symlinked paths;
- automatic post-publish cleanup is gated by successful publish commit 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
Narratio to retry only the outstanding confined local cleanup.
## Operational Caveats
- Local and S3 audio modes are mutually exclusive.
- Publish requires prerequisite stages through `render` and `analyze` to be succeeded.
- Markdown publish defaults require render outputs (`transcripts/final.md` and `transcripts/final.trimmed.md`).
- Restore requires configured object storage and committed remote current state.
- Storage-backed commands load filesystem secrets before object-store initialization.