From e5c1029165856a7fc435aeb82c935b686862cce3 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Fri, 25 Sep 2026 16:00:27 +0000 Subject: [PATCH] Document Audita v2 operator migration and examples --- docs/config.md | 38 ++++++++-- docs/integrations/audita.md | 109 ++++++++++++--------------- docs/internal/adapters.md | 14 ++-- docs/operations.md | 68 +++++++++++++++-- docs/roadmap/implementation.md | 6 +- docs/troubleshooting.md | 40 +++++++++- examples/README.md | 6 +- examples/pipeline.full.annotated.yml | 5 +- examples/pipeline.production.yml | 2 +- 9 files changed, 201 insertions(+), 87 deletions(-) diff --git a/docs/config.md b/docs/config.md index 3c133a0..5eaf93a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -381,6 +381,32 @@ Rules: | `pipeline.scriptorium.artifact_families` | map | No | empty; expands one ordinary artifact per canonical party character | | `pipeline.notification.mode` | string | No | `noop`; the only supported notification mode until a provider is implemented | +### Audita Selection and Credentials + +`pipeline.audita.config_path` optionally passes an Audita v2 configuration file; +when empty, Audita uses its own native config discovery. `overlay`, +`proposal_profile`, and `validation_profile` are independent, optional Audita +selectors. Empty or omitted strings add no command-line override. Narratio's +selected pipeline overlay is never inferred as an Audita overlay, and Narratio +does not create or validate Audita's backend or PromptKit profile files. Prepare +them with [Audita's v2 migration guide](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.0/docs/migrations/v2.md). + +Omit `modules` or set it to `null` to use Audita's configured default sequence. +Set `modules: []` to run no correction modules. A nonempty list is passed in +order, including repetitions. Narratio does not add a reporting or debug flag; +Audita's external configuration controls those settings. + +`pipeline.audita.credentials` lists secret-reference names, not values. Narratio +resolves every listed name during pipeline loading and forwards the captured +nonempty value under that exact name to Audita. It does not inspect Audita's +configuration to discover names or map them to aliases. Audita v2 resolves +credentials for **all configured backends**, even ones not selected by the +current profiles: list every named backend credential in the selected Audita +configuration. An unauthenticated backend needs no reference. Omission, `null`, +or `[]` forwards nothing. A Narratio overlay replaces the entire list, and +`[]` clears it. See the [Audita integration contract](./integrations/audita.md) +for the subprocess and redaction boundary. + ### Notarius Configuration Profile `pipeline.notarius.config_profile` optionally selects a Notarius ConfigKit @@ -417,12 +443,12 @@ notarius: ``` The list contains variable names, not credential values. Those names must -match the credential references in the selected Notarius/PromptKit configuration; -Narratio does not infer or remap provider names. Omission, `null`, or `[]` -forwards nothing. Each selected reference must resolve at pipeline -load time through the process environment or existing secrets-directory -bootstrap, even when Notarius is disabled, extract is outside the requested -range, or a completed extraction can be reused. +match the references used by the Notarius/PromptKit profiles that Notarius +loads. Notarius owns profile lookup; Narratio neither infers those names nor +remaps them. Omission, `null`, or `[]` forwards nothing. Each selected reference +must resolve at pipeline load time through the process environment or existing +secrets-directory bootstrap, even when Notarius is disabled, extract is outside +the requested range, or a completed extraction can be reused. The Notarius child receives only Narratio's minimal execution environment plus these exact selected names and loaded values. Other credentials are not forwarded. diff --git a/docs/integrations/audita.md b/docs/integrations/audita.md index 3daa320..da23b72 100644 --- a/docs/integrations/audita.md +++ b/docs/integrations/audita.md @@ -1,69 +1,54 @@ # Integration: Audita -## Purpose -Define the Audita adapter contract used by the `polish` stage. +Narratio invokes Audita v2's `process INPUT --glossary PATH --output PATH` +subprocess for `polish`. The configured timeout and parent cancellation bound +execution. Narratio passes explicit `--config`, `--overlay`, +`--proposal-profile`, `--validation-profile`, `--transcript-description`, +`--output-schema`, and `--modules` only when selected. An omitted module list +leaves Audita's default sequence in place; `modules: []` passes an explicit +empty argument and runs no correction modules. Order and repetitions are kept. +Narratio passes no debug, work-directory, or reporting flags, leaving those +choices to Audita's own configuration. -## External Boundary +Audita owns its ConfigKit file, backend and profile definitions, native config +discovery, and their validation. Narratio does not create an Audita +configuration or infer downstream overlay/profile names from its own selected +pipeline overlay. An empty Narratio Audita selector adds no CLI override. +The [configuration reference](../config.md#audita-selection-and-credentials) +owns Narratio's fields and defaults. Audita's +[v2 migration guide](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.0/docs/migrations/v2.md) +owns its downstream file format. -Narratio invokes `audita process` as a subprocess for each polish operation. -The configured timeout and parent cancellation bound the invocation. Internal -runner composition is documented in -[the adapter implementation guide](../internal/adapters.md). +Each name in `pipeline.audita.credentials` is a ConfigKit secret reference +resolved when Narratio loads the pipeline. Narratio forwards only the selected +names and their captured, nonempty values under those exact names, in the +minimal child environment; it never maps them to a fixed alias or rereads the +parent environment. Every name is registered for captured stdout/stderr and +failure-diagnostic redaction. Audita resolves credentials for all configured +backends, including unselected ones, so operators must list every backend +credential that its selected configuration needs. The downstream files and +provider output remain Audita's responsibility, outside Narratio's +captured-stream redaction boundary. -## Request Contract -`PolishRequest` carries: -- required transcript/glossary/output/work-dir paths; -- optional report path (required when report mode is enabled); -- generated config and stdout/stderr log paths; -- optional per-invocation module override. +The corrected transcript is the only canonical polish output. A successful +invocation must produce a valid JSON transcript with a top-level `segments` +array within Narratio's 64 MiB bound. Exit zero is accepted even if Audita's +ordinary reports describe recoverable model errors or no corrections. Narratio +does not parse report status, counts, or Markdown. It discovers only +`errors.yml`, `recoveries.yml`, and `report.md` next to the requested output, +each subject to a 16 MiB read bound. Missing reports are allowed, for example +when Audita reporting is disabled externally. Available reports are diagnostic +references, not canonical artifact outputs. See Audita's +[ordinary output contract](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.0/docs/integrations/output-files.md) +for their schemas, and [operations](../operations.md) for placement and +publication. -The constructed runner owns static Audita settings: binary, timeout, -credentials, default modules, model and endpoint settings, validation and output -settings, report mode, and concurrency. The `polish` stage supplies only -invocation-specific paths and may override modules for that invocation. +On nonzero exit, Narratio preserves the original subprocess error and +available run-local evidence; it never promotes a transcript merely because +the file exists. The adapter returns safe paths, exit details, and selection +metadata on failure. Narratio's `audita.generated.v2` YAML records the +invocation, including arguments, paths, and credential names but never values; +it is a diagnostic record, not a generated Audita config file. -## Result Contract -`PolishResult` returns: -- processed transcript path; -- optional report path; -- work dir and generated-config/log paths; -- exit code, duration, binary provenance; -- adapter metadata map. - -## Validation and Failure Semantics -Construction fails for invalid static config values, including: -- empty binary; -- non-positive timeout; -- invalid base URL; -- invalid output schema; -- invalid work-dir retention value; -- invalid concurrency values. - -Run fails for: -- missing required request paths; -- subprocess execution failure; -- invalid processed transcript JSON (`segments` array required); -- invalid report JSON when reporting is enabled. - -Processed transcript JSON is limited to 64 MiB and optional report JSON to 16 -MiB. Both must be regular files without symlinked path components. - -Failure results still include output/log/config/exit metadata for diagnostics. - -## Deterministic Behavior -- CLI args are built from runner config + request in a fixed order. -- A configured typed `llm_api_key` reference is resolved during pipeline load; - the captured value is supplied only as the child's `AUDITA_LLM_API_KEY` - override and is never re-read from the parent environment. -- Generated invocation YAML (`audita.generated.v1`) is emitted when requested. -- Manifest writes are stage-owned; adapter itself is stateless. - -## Configuration - -Operator-selected values are defined under `pipeline.audita.*` in the -[configuration reference](../config.md#pipeline). - -Maintained example with Audita config: - -- [Full annotated pipeline](../../examples/pipeline.full.annotated.yml) -- [Production-shaped pipeline](../../examples/pipeline.production.yml) +Maintained Narratio examples: [full annotated pipeline](../../examples/pipeline.full.annotated.yml) +and [production-shaped pipeline](../../examples/pipeline.production.yml). diff --git a/docs/internal/adapters.md b/docs/internal/adapters.md index e4428f0..1869abd 100644 --- a/docs/internal/adapters.md +++ b/docs/internal/adapters.md @@ -68,11 +68,15 @@ owner of serializing them as repeated `--reference` arguments before `--json`. It also serializes an effective resume request as `--resume` and a nonempty validated chunk mode as `--chunk_cache `. The extract stage, not the adapter, resolves force precedence before constructing the request. -Its request may also carry one already-resolved opaque ConfigKit secret -reference. Only the Notarius adapter reads that value, rejects an unresolved or -empty programmatic reference, and maps the exact configured name/value into the -shared subprocess override and sensitive-name fields. It never rereads the -parent environment. A nil reference preserves the previous invocation. +Its request may also carry already-resolved ConfigKit secret references. +Audita's request carries the same kind of list. Both adapters use the shared +subprocess helper to convert their selected references into exact-name child +environment overrides and sensitive-name registration. That helper rejects +unresolved or empty programmatic references, but neither adapter rereads the +parent environment or inspects downstream configuration to discover names. +Empty lists add no credential overrides. See the public [Audita](../integrations/audita.md) +and [Notarius](../integrations/notarius.md) contracts for selection and +downstream-file boundaries. Application-owned object-store construction loads configured filesystem secrets before invoking the invocation's storage factory. Production commands diff --git a/docs/operations.md b/docs/operations.md index c374c29..635cd88 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -124,10 +124,11 @@ membership, S3 object identity, or missing/tampered copies rerun prepare and its fixed descendants without requiring `--force`. Changing prepare selection semantics likewise reruns all fixed descendants; changing WhisperX language/service identity reuses prepare; changing a Seriatim merge -transformation reuses prepare and transcribe; and changing an Audita model -reuses prepare, transcribe, and merge while rebuilding transcript refinement. -A trim change invalidates both render and extract through the fixed dependency -relation, while a render-only change preserves the extract sibling. +transformation reuses prepare and transcribe; and changing a selected Audita +overlay, profile, or module sequence reuses prepare, transcribe, and merge while +rebuilding transcript refinement. A trim change invalidates both render and +extract through the fixed dependency relation, while a render-only change +preserves the extract sibling. Operational timeouts, retry/concurrency tuning, executable paths, workspace/cache/spool placement, reports, diagnostics, and secret values are @@ -409,6 +410,58 @@ execute. Deleting Narratio's local reference snapshots does not invalidate a complete durable extraction; missing snapshots are reconstructed only when a later extraction actually runs. +## Migrating Audita and Provider Credentials + +This is a breaking clean cutover to Audita v2. Narratio does not translate an +Audita v1 configuration, retain old field aliases, or generate a downstream +configuration. Update both the deployed Audita executable/configuration and +the Narratio pipeline before running polish. Retired Narratio fields are +rejected by strict configuration loading; account for this break when choosing +a release version. + +| Previous Narratio setting | New ownership and selection | +| --- | --- | +| `audita.base_url` | Audita v2 `backends..endpoint` | +| `audita.total_llm_concurrency`, `proposal_llm_concurrency`, `validation_llm_concurrency` | Audita v2 `backends..concurrency` and optional `queue_capacity`; backend capacity is shared across roles | +| `audita.model`, `validation_model` | Audita PromptKit profile files; optionally select them from Narratio with `audita.proposal_profile` and `validation_profile` | +| `audita.llm_api_key` | `audita.credentials: [PROVIDER_KEY_NAME]`, matching each Audita backend's `credential` name | +| `notarius.llm_api_key` | `notarius.credentials: [PROVIDER_KEY_NAME]`, matching references in Notarius-owned profiles | +| `audita.work_dir_retention`, `report` | Remove; Audita's external configuration owns diagnostics and reporting | + +An Audita configuration can also be selected through `audita.config_path`, +and `audita.overlay` selects an Audita overlay independently of Narratio's +`--overlay`. Narratio forwards no implicit provider key: a single provider-named +secret source may be listed for both adapters, and an Audita-only backend key +may be listed only for Audita. Audita resolves credentials for all configured +backends, including those not currently selected. Notarius looks up its own +profiles; Narratio does not discover their credential names. Credential lists +may be cleared with `[]` in a Narratio overlay. + +Prepare the external file from Audita's maintained +[local example](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.0/examples/minimal-config.yml), +[service example](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.0/examples/production-config.yml), +and [v2 migration guide](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.0/docs/migrations/v2.md). +Before switching the executable, validate the file offline: + +```bash +audita config validate --config /usr/local/etc/audita/config.yml +``` + +Use `audita config print-effective --config /usr/local/etc/audita/config.yml --view profiles` +to inspect downstream profile selection without contacting a provider. For a +production Audita configuration, leave ordinary reports enabled +and debug disabled unless an operator deliberately chooses otherwise; Narratio +does not override those settings. Audita writes `errors.yml`, `recoveries.yml`, +and `report.md` beside the polished output when reporting is enabled. An +exit-zero run with a valid transcript succeeds even if those reports describe +recoverable errors or no applied corrections. See the [Audita integration +contract](./integrations/audita.md) for report placement and limits. + +Narratio's polish resume evidence tracks selected config path, Audita overlay, +profiles, ordered modules, description, schema, and output identity. Editing +Audita-owned files behind unchanged selectors is invisible to Narratio; force +polish with `narratio run-stage polish --force` after such edits. + ## External Command Lifecycle When an external command is cancelled or times out, Narratio terminates its @@ -699,9 +752,10 @@ files. Existing environment variables—including empty values—always win. S3 `access_key_id` and `secret_access_key` are an optional pair of typed environment references. When both are absent, the AWS SDK retains its default credential provider chain. When both are configured, Narratio supplies their -load-time resolved values through an explicit static provider. Audita's optional -`llm_api_key` is likewise captured at pipeline load and supplied only through -the child process's `AUDITA_LLM_API_KEY` override. +load-time resolved values through an explicit static provider. Audita and +Notarius credential lists likewise resolve at pipeline load. Each adapter +receives only its listed names and captured values, with no alias mapping or +ambient environment inheritance. See [configuration](./config.md#audita-selection-and-credentials). External adapter results are individually bounded before Narratio validates or materializes them. These per-file limits do not reserve disk space: prevent hard diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index b7b0a9f..284f436 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -383,7 +383,11 @@ invalidation or changes to unselected-stage execution. ## Stage 7: Complete operator migration documentation and examples -Status: Not started. +Status: Complete (2026-09-25). + +Verification: `go test ./internal/doccheck`, +`go test ./internal/config -run '^TestExamplesLoadAndValidate$'`, and +`git diff --check` passed. Preparation: documentation policy; `docs/config.md`, `docs/operations.md`, `docs/troubleshooting.md`, both integration guides, diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 7662213..0a1c7f1 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -328,7 +328,7 @@ Safe fix: - set the exact nonempty environment variable or provide an equivalently named file through the conventional or explicit secrets directory; -- remove or set the field to `null` when that deployment needs no credential; +- remove, set to `null`, or set to `[]` when that deployment needs no credential; and - use `config show`, `config sources`, and `config diff` to inspect the public reference name and ownership without exposing its value. @@ -339,7 +339,43 @@ invalidate a completed extraction, but the current reference must still resolve for the command to proceed. Relevant references: [Secrets](./config.md#secrets-handling) and -[Notarius credential](./config.md#notarius-credential). +[Notarius credentials](./config.md#notarius-credentials). + +## Audita v2 configuration or credential failure + +Symptom: + +- Narratio rejects a retired `pipeline.audita` field during loading, reports + `secret.unset` or `secret.empty` for a listed credential, or Audita rejects + its external configuration or selected profile when polish runs. + +Likely causes: + +- the Narratio pipeline still uses v1 endpoint, model, capacity, singular key, + report, or retention settings; +- the named key is missing or empty, including a present but empty process + environment variable that takes precedence over a secrets-directory file; +- Audita's external v2 file references a backend credential name not forwarded + by `pipeline.audita.credentials`, including a backend not selected by the + current profile; or +- an Audita overlay or profile selector names a missing downstream definition. + +Safe fix: + +- follow the [migration table](./operations.md#migrating-audita-and-provider-credentials) + and use a supported Audita v2 executable and configuration; +- provide each needed provider-named variable through the environment or + secrets directory, and list that same name in `pipeline.audita.credentials`; +- validate the external file offline with + `audita config validate --config ` before switching executables; and +- inspect Audita's effective profile selection separately from Narratio's + `config show`. Narratio does not infer downstream selectors. + +An exit-zero polish with a valid transcript succeeds even when Audita reports +recoverable errors or no corrections. Missing reports are allowed when Audita +reporting is disabled externally. Edits to Audita-owned files behind unchanged +selectors require `narratio run-stage polish --force` to replace a +previously successful result. See the [Audita integration contract](./integrations/audita.md). ## Notarius executable missing diff --git a/examples/README.md b/examples/README.md index f2d7c99..f9c3083 100644 --- a/examples/README.md +++ b/examples/README.md @@ -70,7 +70,11 @@ The examples contain environment-variable names but no credential values. Set `OBJECT_STORAGE_KEY_ID`, `OBJECT_STORAGE_KEY`, `AUDITA_LLM_API_KEY`, and `NOTARIUS_LLM_API_KEY` to nonempty synthetic or real values before loading the examples that reference them. They use fictional campaign content and reserved -example domains. +example domains. The Audita and Notarius names are example references, not +implicit aliases: external backend/profile configurations must use those exact +names, or the Narratio credential lists must be changed to match. See the +[Audita v2 migration guide](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.0/docs/migrations/v2.md) +for maintained downstream configuration examples. For a deployed bundle, keep credential files out of source control in a `secrets/` directory beside the root `pipeline.yml`, one file per referenced diff --git a/examples/pipeline.full.annotated.yml b/examples/pipeline.full.annotated.yml index c2a4ba1..235af8d 100644 --- a/examples/pipeline.full.annotated.yml +++ b/examples/pipeline.full.annotated.yml @@ -90,11 +90,12 @@ seriatim: filler_max_duration: 1.25 audita: - # Optional overrides; defaults shown explicitly where applicable. + # Optional overrides. Audita owns its own configuration and profiles. binary: audita timeout: 3h + # Names must match credentials on every backend in the Audita v2 config. credentials: [AUDITA_LLM_API_KEY] - modules: [glossary, homophones, spoken_word, grammar] + # Omit modules for Audita's default sequence; modules: [] disables corrections. overlay: "" proposal_profile: "" validation_profile: "" diff --git a/examples/pipeline.production.yml b/examples/pipeline.production.yml index 2094687..bdb26e4 100644 --- a/examples/pipeline.production.yml +++ b/examples/pipeline.production.yml @@ -58,7 +58,7 @@ audita: binary: audita timeout: 3h credentials: [AUDITA_LLM_API_KEY] - modules: [glossary, homophones, spoken_word, grammar] + # Omit modules to use Audita defaults; modules: [] disables corrections. output_schema: audita-v1 normalize: