diff --git a/docs/roadmap/audita.md b/docs/roadmap/audita.md new file mode 100644 index 0000000..76f85c9 --- /dev/null +++ b/docs/roadmap/audita.md @@ -0,0 +1,250 @@ +# Adopt Audita v2 + +Status: agreed scope; implementation has not started. + +## Goal + +Migrate Narratio's `polish` integration from Audita's former command/configuration +contract to Audita v2.0.0. Keep Narratio responsible for orchestration and Audita +responsible for correction behavior and LLM execution configuration. + +Adopt a consistent provider-named credential list for both Audita and Notarius, +so operators define each secret once and explicitly share it with the downstream +applications that need it. This is a clean cutover without backward-compatibility +shims. + +Production runs use Audita's default reporting configuration: Narratio passes +neither `--debug` nor `--reporting=false`. Normal reports remain available without +enabling debug diagnostics. Adding debug reporting through Narratio's testing +profile is deferred. + +This document defines the intended end state, migration scope, and policy. +The [implementation plan](implementation.md) owns implementation sequencing and +verification steps. + +## Baseline and upstream contract + +The baseline is Narratio v2.2.1 and the Audita checkout tagged v2.0.0. Upstream +references are Audita's `docs/migrations/v2.md`, `docs/cli.md`, +`docs/integrations/subprocess.md`, and `docs/integrations/output-files.md`, +available in the sibling `../audita/` checkout. Narratio's current contract is +documented in [Integration: Audita](../integrations/audita.md). + +The current integration is not compatible with Audita v2: + +- It requests `--report-json` by default; that flag has been removed. +- It can pass retired endpoint, model, concurrency, and work-directory-retention + flags. +- It expects one JSON report instead of the normal v2 report bundle. +- Its single forwarded `AUDITA_LLM_API_KEY` has no implicit meaning in v2; + an Audita backend must explicitly reference that environment variable. +- Its semantic fingerprint sorts modules, although Audita treats module order + and repetitions as meaningful. + +Audita v2 requires a version-2 configuration file. An explicit `--config` selects +one; otherwise Audita performs its own documented discovery. Backend definitions +own endpoints, credentials, and capacity. PromptKit profiles own models and +per-attempt controls. Audita owns retry/repair policy and operation deadlines. +Narratio's generated invocation YAML is a diagnostic record, not a substitute +for that Audita configuration file. + +## Target architecture + +Retain the existing subprocess boundary and `polish` stage. Do not introduce a +second correction engine, an in-process Audita dependency, or a generic external +tool configuration framework. + +Narratio owns: + +- Selection of the executable and the overall invocation timeout/cancellation. +- Transcript and glossary inputs, run-local output placement, validation of the + corrected transcript, and promotion to the existing polished transcript + identity. +- Explicit configuration/profile selections and supported domain overrides. +- Deliberate credential forwarding, secret-safe invocation diagnostics, and + manifest references to results and reports. +- Existing stage completion, resume, force, publish, restore, and cleanup + behavior. + +Audita owns its configuration schema and discovery, backend/model configuration, +provider execution, correction sequence, recovery behavior, and report contents. +Narratio does not translate old settings into a generated v2 configuration or +duplicate Audita's complete validation logic. + +## Configuration and invocation migration + +Keep binary, timeout, explicit config-path selection, and surviving explicit +domain overrides such as transcript description, output schema, and modules. +Allow Audita's native configuration discovery when no config path is selected; +do not impose an additional requirement to supply an explicit path. + +Provide optional Audita overlay, proposal-profile, and validation-profile +selectors, passed through to their corresponding CLI flags. Omission leaves +Audita's own defaults and validation-profile inheritance in control. These are +Audita selectors, not automatic translations of Narratio profile names. + +Retire the Narratio settings that mirror removed Audita endpoint/model/capacity +flags and work-directory retention. Move their operational meaning into the +operator-maintained Audita configuration and profiles. Remove stale adapter +fields, validation, invocation metadata, examples, and tests along with them. +Remove the old report toggle and both adapters' singular `llm_api_key` fields +from accepted Narratio configuration. Do not retain deprecated aliases, +automatic conversion, ignored fields, or a v1 execution path. Existing strict +configuration decoding rejects removed fields. Provide migration guidance and a +release compatibility notice rather than runtime compatibility machinery. + +Preserve the distinction between omitted modules and an explicitly empty module +list: omission requests Audita's configured/default sequence; an empty list +requests no correction modules. Preserve order and repetitions rather than +sorting or deduplicating. Do not broaden this into a change to unrelated +adapters' module semantics. + +Normal invocations no longer pass `--report-json`, `--work-dir-retention`, or +debug-work-directory flags as a way to obtain reports. They need no reporting +override: Audita writes its ordinary report bundle by default. The old +Narratio `report` toggle must not silently become `--reporting=false`. + +The production Audita configuration must also retain reporting enabled and debug +disabled. Omitting CLI flags does not override an operator's explicit external +configuration. Document this distinction rather than silently adding forced +boolean overrides or rejecting otherwise valid Audita configuration. + +## Credentials + +Define secrets once under provider-oriented environment-variable names, such as +`OPENROUTER_API_KEY` and `RAKESTRAWHOME_API_KEY`, through the process environment +or Narratio's existing secrets-directory bootstrap. These names are examples, +not a fixed provider registry; application-specific names are not required. + +Add `pipeline.audita.credentials` and `pipeline.notarius.credentials` as lists +of Narratio typed secret references. Each entry names the environment variable +whose captured value is forwarded under that exact name. Omission or an empty +list forwards no credentials. The same reference may appear in both adapters' +lists without duplicating its stored secret value. An illustrative configuration +fragment is: + +```yaml +pipeline: + audita: + credentials: + - OPENROUTER_API_KEY + - RAKESTRAWHOME_API_KEY + notarius: + credentials: + - OPENROUTER_API_KEY +``` + +Resolve references through the existing configuration/secret-loading mechanism +before adapter execution, preserving its nonempty-value requirement. Forward +the captured values rather than rereading the parent environment during a run. +Retain the minimal child execution environment plus each adapter's explicit +credential list; do not forward every secret found during bootstrap. + +Audita backends select these names through `credential`; the current Notarius +PromptKit profiles select them through `api_key_env`. Narratio neither inspects +downstream configuration to infer required credentials nor translates names, +registers providers, or duplicates backend configuration. Audita resolves +credentials for every surviving configured backend, even one not selected by +a profile, so its list must cover all those references. + +Generalize Notarius's current single-name forwarding and replace Audita's fixed +`AUDITA_LLM_API_KEY` destination with this shared convention. Use existing shared +secret and subprocess facilities, extending narrow helpers where needed rather +than introducing a new secret-management framework. Register every forwarded +credential with captured-output redaction, including custom names and multiple +keys. Values must not enter arguments, generated configuration, manifests, +logs, or examples. As today, downstream tools remain responsible for files they +write directly; this does not add arbitrary downstream-file scanning. + +## Ordinary reports and result handling + +Replace the old `audita.report.json` handling with Audita's normal `errors.yml`, +`recoveries.yml`, and `report.md` bundle. With a file output, Audita writes these +beside the corrected transcript; an arbitrary report destination is not supplied +through the removed report flag. + +Discover the reports at their defined run-local locations and retain them as +diagnostics using Narratio's existing manifest and diagnostic lifecycle. Keep +them distinguishable from the canonical polished transcript. Adapt report +references, publication/restore coverage, and operator inspection guidance so +the bundle is not lost or confused with an older run's JSON report. Do not +fabricate a legacy JSON report or delete historical diagnostics as part of the +migration. + +Retain existing bounded, confined file handling. Replace JSON-specific report +handling with only the validation needed for consuming the v2 bundle; do not +introduce a second comprehensive report-schema validator or make incidental +Markdown wording a contract. Report locations must be discoverable without +parsing human-readable stderr. Detailed report-counter ingestion is not required +for this migration. + +Audita's exit status remains authoritative. Exit zero with a valid corrected +transcript may include recoverable LLM failures, including a normalized result +with no model corrections. Preserve the reports so operators can assess that +outcome; do not add an unrequested fail-on-recovery or minimum-correction policy. + +Conversely, a nonzero exit must fail polish even if a transcript file exists: +Audita can fail while writing required reports after writing the transcript. +Preserve available failure diagnostics without requiring early failures to have +produced a complete report bundle. Failed output must not become the canonical +successful result. + +## Resume and semantic evidence + +Update polish's semantic evidence for the new result-affecting selections and +remove retired endpoint/model fields. Include explicit config/overlay/profile +selection and preserve ordered module semantics, including omitted versus empty +selection. Version the changed evidence so incompatible older evidence is not +mistaken for a valid match when polish is considered for reuse. + +Keep the existing boundary for opaque downstream configuration: Narratio does +not recursively hash Audita configuration, overlays, and profile contents. +Operators force polish when changing contents behind unchanged selectors. +Timeouts, credential values, reporting details, and other execution-only settings +must not become blanket semantic invalidation keys. Do not rerun unrelated or +unselected stages merely because the integration was upgraded. + +## Migration guidance and verification + +Update the canonical [configuration reference](../config.md), +[Audita integration contract](../integrations/audita.md), +[Notarius integration contract](../integrations/notarius.md), +[polish internals](../internal/stage-polish.md), maintained examples, and relevant +operations/troubleshooting guidance when implementation lands. Cover: + +- Preparing and validating an Audita v2 configuration and its profiles before + switching the executable; copying an old v1 configuration is insufficient. +- Moving endpoint, model, capacity, and credential selections to their v2 owners. +- Replacing both singular `llm_api_key` settings with explicit `credentials` + lists, storing each provider key once, and matching downstream credential + references to those names. State clearly that old fields are removed. +- Using normal reports to inspect recoveries and failures without debug mode. +- Force/resume expectations and the treatment of existing completed sessions. +- The explicitly deferred nature of Narratio testing-profile debug support. + +Verification should exercise the real adapter boundary with offline subprocess +fixtures and focused stage/configuration tests: accepted v2 arguments, omitted +defaults, ordered/empty modules, secret-safe forwarding, successful report +capture, recoverable-error success, nonzero exit with an existing transcript, +failure diagnostics, and semantic reuse/invalidation. Update existing behavioral +tests rather than retaining assertions for removed flags or exact stderr prose. +Where practical, verify invocation against the tagged Audita CLI without live +provider calls. Follow the repository's testing and documentation policies. + +Credential tests must cover both adapters, multiple custom names, reuse of one +secret by both tools, no forwarding of unselected secrets, captured-value +semantics, and redaction of every forwarded value. Verify removal of obsolete +configuration fields without preserving their compatibility behavior. + +## Scope boundaries + +No changes to pipeline order, transcript identity, downstream artifact +definitions, or provider algorithms are intended. No automatic v1 configuration +converter, Audita-internal resume mechanism, runtime binary-version negotiation, +or live-service release gate is required. Debug-profile integration and ingestion +of Audita's debug-only execution artifacts are future work. + +The Notarius change is limited to credential configuration, forwarding, and +associated diagnostics/documentation/tests; extraction and cache behavior are +unchanged. This migration breaks existing pipeline configurations using removed +fields; account for that explicitly in Narratio release versioning. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 13a4d25..1d10040 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,316 +1,349 @@ -# Implementation Plan: Shared Stage Checkpoint Mechanics +# Implementation Plan: Audita v2 and Shared Provider Credentials -Status: Complete. +Status: Not started. -## Scope and Authority +## Scope and working instructions -Implement the agreed follow-up to v2.2.0: consolidate the thin checkpoint -mechanism shared by transcribe and analyze without combining their progress -models or changing operator behavior. There is no separate consolidation -roadmap in this checkout. This plan uses the accompanying discussion as its -scope: persistence is already centralized; candidate isolation and -save-before-promotion are the duplication to remove. The completed -[transcription roadmap](transcribe-checkpoints-and-replay.md) provides background, -not authorization to reimplement transcription or HTTP replay. The preceding -completed implementation plan remains in Git history. +Implement [the Audita roadmap](audita.md). The baseline is Narratio commit +`70f1dbf` (v2.2.1), with Audita v2.0.0 as the upstream contract. This replaces +the completed checkpoint-refactoring plan, which remains in Git history. -Complete the numbered stages in order, one bounded implementation prompt per -stage for gpt-5.6-terra. Record completion and actual verification results here. -This planning pass changes documentation only; the steps below are for the -subsequent implementation sprint. +Complete Stage 1 through Stage 7 in order, one bounded implementation prompt per +stage for gpt-5.6-terra. Record completion and actual verification results under +each stage. These instructions apply to the implementation sprint; the planning +pass changes documentation only. Intermediate stages are not release candidates. +Do not add compatibility code to make intermediate states look like a supported +release. -Before each stage, read `AGENTS.md`, `docs/development.md`, and all three -documents in `docs/policy/`: architecture, documentation, and testing. Use -maintained Go 1.26. Prefer graph tools for code discovery; inspect current -files if their index is stale. Read the stage-specific preparation below, -rather than unrelated historical roadmaps. +Before each stage, read `AGENTS.md`, `docs/development.md`, and all three policies +under `docs/policy/`: architecture, documentation, and testing. Read this plan's +selected design and that stage's preparation. Use Go 1.26 and graph-first code +discovery; inspect current files when graph results are incomplete. Preserve +unrelated changes. Test at behavioral owners rather than replicating every case +across configuration, adapter, stage, and command tests. -## Target and Scope Boundaries +The user approved a clean cutover: no Audita v1 runner, deprecated aliases, +compatibility shims, generated configuration conversion, or silently ignored +old settings. Do not broaden that decision into a purge of unrelated legacy +code or historical session data. -The existing `internal/manifest.Store` and `LocalStore` remain the session -manifest persistence interface and implementation. Encoding, schemas, -validation, normalization, and atomic file replacement remain unchanged. -There is no new store, journal, file format, dependency, command, configuration, -or migration. +## Selected design -One private helper in `internal/stage` owns candidate preparation, calling the -existing store, and promoting the selected stage record only after successful -save. The existing typed analyze/transcribe checkpoint methods become thin -callers. This is execution plumbing: keep it beside the callers rather than -moving orchestration into the storage package or exporting a reusable API. +### Configuration and credentials -Keep these responsibilities stage-owned: +- Both `pipeline.audita.credentials` and `pipeline.notarius.credentials` are + lists of ConfigKit secret references. Use `[]configkit.Secret`; each element + is an actual reference rather than a nullable pointer. Existing ConfigKit + validation owns name/value resolution. Omitted, null, or empty lists mean no + additional credential forwarding. +- Define each key once through existing environment/secrets-directory bootstrap. + Forward it under its original name to each adapter whose list includes it. + No alias mappings, provider registry, downstream config inspection, extra + bootstrap, or inheritance of the entire environment. +- Repeated names need no new rejection rule: forwarding the same captured + reference once suffices. Arbitrary valid variable names remain supported; + provider names in the roadmap are examples, not an allowlist. +- Add a narrow shared helper in `internal/adapters/subprocess` converting resolved + references to `EnvOverrides` and `SensitiveEnvNames`. It checks the existing + resolved/nonempty requirement for direct adapter callers but never resolves + secrets or rereads environment values. Errors expose no values. Both adapters + use it; no dependency upgrade or credential service is needed. +- Configuration projections and diagnostic metadata contain reference names + only. Register all forwarded names for existing captured-stream redaction. + Downstream tools remain responsible for files they write themselves. +- Remove both singular `llm_api_key` fields. For Audita also remove `base_url`, + `model`, `validation_model`, `total_llm_concurrency`, + `proposal_llm_concurrency`, `validation_llm_concurrency`, + `work_dir_retention`, and `report`, including defaults and projections. +- Retain Audita `binary`, `timeout`, `config_path`, `transcript_description`, + `output_schema`, and `modules`. Add optional string selectors `overlay`, + `proposal_profile`, and `validation_profile`: empty/unset means no CLI + override. Audita owns downstream file/profile validation and native config + discovery. Narratio profile names are not implicitly Audita overlay names. +- Preserve nil versus non-nil empty `modules` through loading, projection, + cloning, composition, adapter defaults, and request overrides. Nil omits the + flag; empty passes `--modules` with an empty argument; nonempty joins in order + with repetitions intact. A nil request override uses the configured selection. + Avoid clones that collapse empty slices to nil. YAML null follows unset + behavior. Other adapters' module semantics do not change. -- Transcribe's completed-only speaker map, evidence checks, bounded concurrency, - mutex, checkpoint-failure latch, cancellation, pre-dispatch force reset, - output installation, and aggregate repair. -- Analyze's dispositions, selection, dependencies, catalog updates, working and - committed collections, failure reconciliation, invalidation, and outputs. -- Each stage's decision whether/when to checkpoint, typed validation, contextual - errors, and post-save working-state updates. -- Runner aggregate transitions, session locking, terminal failure saves, and - fixed dependent-stage invalidation. +### Invocation, reports, and failure -Do not introduce a common subtask model, scheduler, transaction manager, global -mutex, automatic retry, additional checkpoint, or batching policy. Do not -migrate publish/restore, planning clones, cleanup, or ordinary runner saves: -their operations are not the demonstrated duplication. Leave HTTP replay and -all adapters unchanged. +Use `process INPUT --glossary PATH --output PATH` plus selected surviving +overrides. Production passes no reporting or debug switches, including +`--debug`, `--reporting=false`, `--report-dir`, or `--work-dir`. +Remove required `WorkDir` and legacy `ReportPath` request/result plumbing. +Document production external-config defaults without forcibly overriding or +rejecting deliberate external reporting/debug choices. -## Selected Design +Replace Audita's long positional config-values constructor with typed runner +configuration. Keep timeout parsing in composition and subprocess cancellation +through the existing runner. No version probe or automatic config-validation +subprocess is required. -### Shared Save-and-Promote Operation +The corrected transcript remains the only canonical polish output, with existing +identity, path, validation, and bounded file handling. Discover exactly +`errors.yml`, `recoveries.yml`, and `report.md` beside the requested output. +Represent available paths in a small typed report bundle in `PolishResult`. +Fixed names belong to the adapter; do not parse stderr or recursively scan. -Add `internal/stage/checkpoint.go` with a private helper shaped as: +Reports are diagnostics, not a new correctness gate: -```go -func checkpointStageCollection( - ctx context.Context, - store manifest.Store, - path string, - live *manifest.Manifest, - stageName string, - update func(*manifest.StageRecord) error, -) error -``` +- Bound reads of present reports using the existing named 16 MiB report limit; + retain confined regular-file handling and errors identifying Audita, the file, + and limit. No new smaller limits or report schema/status/count validation is + necessary when Narratio only preserves bytes; Markdown needs no parser. +- Missing files are not independently fatal: external configuration can disable + reports and early failures may produce none. Default-reporting success tests + must nevertheless demonstrate capture of all three files. +- On process failure, preserve available diagnostics and the original error; + report-inspection errors must not hide it. Never promote an output merely + because it exists following a nonzero exit. +- Exit zero with a valid transcript may include recoverable errors or no model + corrections. Accept it without a fail-on-recovery or minimum-correction rule. -Names are implementation choices, not public contracts. Use a function and -small copying helpers, not a factory/options/interface framework. The two -existing typed checkpoint methods are the only production callers. They pass -the already-resolved manifest path; the helper does not discover paths or -inspect configuration. +Keep reports next to the run-local transcript, not in a second canonical +destination. Register present report paths in the existing `StageResult.Logs` +diagnostic collection alongside stdout/stderr, with safe bundle-path metadata. +Reuse current manifest-driven diagnostic publication rather than adding a +manifest schema or new publish source IDs. Physical placement does not define +canonical artifact identity. Existing diagnostic retention/cleanup rules apply. -The helper performs this sequence: +On failure, retain run-local files and expose the output/report directory in +contextual errors. Do not add runner-wide failed-result persistence merely to +register those files. Do not fabricate legacy JSON reports or delete historical +reports. Normal successful stage-record replacement removes obsolete current +output references. -1. Check required live/store inputs without mutation. Copy a checkpoint - candidate and select a copied target record. If absent, provide an empty - candidate record to the caller, without inferring its name, status, or time. -2. Apply the supplied update to that candidate record only. On update error, - return without saving or promoting. The typed caller validates and fills - its version, collection, and stage-owned initialization/timestamps. -3. Invoke `Store.Save` once with the supplied context. Preserve error identity - through `%w` and useful path context. On error, do not promote, retry, - reload, or synthesize aggregate failure. -4. After success, install the saved target record and candidate manifest - `UpdatedAt` into live state. Preserve an existing target record's pointer - identity by assigning through it. Allocate missing live maps/records only - after success. Do not replace the entire live manifest or overwrite other - stage records. Copy mutable checkpoint collections on promotion so saved - candidates and caller working collections cannot mutate live progress. +Generated invocation YAML becomes `audita.generated.v2`, recording actual +arguments, selections, paths, and credential names, never values. This remains +a diagnostic invocation record, not an Audita configuration file. -Callers serialize the whole operation. Transcribe's current mutex does so; -analyze executes artifacts sequentially. Do not add a lock to the helper or -promise support for concurrent independent manifest writers. Atomic replacement -visibility does not become power-loss durability or a transaction covering -transcript files. +### Resume boundary -### Bounded Candidate Isolation +Bump only polish semantic-config version from 1 to 2. Record config path, +overlay/proposal/validation selectors, ordered modules with presence preserved, +transcript description, output schema, and existing output identity. Remove old +endpoint/model fields. Existing runner comparison reconsiders obsolete evidence +when polish is selected; do not synthesize equivalent fingerprints or expand +normal dependency/selection invalidation. -Factor `cloneManifestForTranscribeCheckpoint` into a shared checkpoint-scoped -copy helper in the new file. Use ordinary typed copies and existing -`manifest.CloneAnalyzeArtifactCollection` and -`manifest.CloneTranscribeSpeakerCollection`. Do not introduce reflection -cloning, JSON round trips, or a public general-purpose clone API. +Credentials, binary path, timeout, and diagnostics are not semantic keys. Do not +hash downstream config/profile contents; operators force polish after edits +behind unchanged selections. Notarius credential migration does not change +extraction fingerprints, references, force, resume, or chunk-cache behavior. -Copy the manifest value, stages map, stage records, and mutable collections -touched by these updates or `LocalStore.Save`. In particular, Save normalizes -analyze collections throughout the candidate, including on a transcribe -checkpoint. Clone those collections for every stage so normalization cannot -leak into live state on failure. Preserve the existing bounded copies of -input/artifact and output/log/config slices. Retain nil entries for existing -validation to reject, rather than silently repairing invalid manifests. +## Stage 1: Add shared resolved-credential forwarding -This is not arbitrary deep isolation of metadata. Neither the two update -callbacks nor the current Store mutates `map[string]any` metadata, so it may -remain shared read-only. Document that boundary and inspect every current -normalization write. Use existing typed clones for nested checkpoint evidence; -do not restrict legal metadata values or alter their Go/JSON representations -to simplify copying. +Status: Not started. -### Differences to Preserve +Preparation: `internal/adapters/subprocess/run.go`, its environment/redaction +helpers and tests; `internal/adapters/notarius/subprocess.go`; +`internal/config/credential_projection.go`; the pinned ConfigKit secret API. -- Analyze still requires an existing stage record. Its callback changes only - analyze version/collection, not transcribe-style initialization or timestamp - policy. It refreshes working and committed collections only after success. -- Transcribe retains missing-record initialization for direct stage calls: - its typed caller supplies name, running status, and initial timestamps when - needed. Its callback retains the existing stage `UpdatedAt` update. Copying - an existing record must not clear aggregate fields or invoke lifecycle - transitions. -- Existing transcribe live-record initialization is incomplete on the unusual - missing-record path; promoting the actual successfully saved candidate makes - its identity agree with disk. This does not add a new missing-record - rejection or change ordinary runner status transitions. -- Analyze rollback/failure handling and transcribe failure latching remain in - their execution owners. The shared operation never invents failed items. -- Preserve starting-checkpoint elision, force/reset semantics, empty versioned - collections, evidence and producer identity, legacy transcription handling, - supported zero-sized audio, and aggregate repair without HTTP calls. -- Do not freeze exact error wording, wall-clock values, copy choreography, or - iteration order into new contracts. No new schema, limits, filename rules, - statuses, or compatibility guarantees are authorized. +1. Add the narrow helper described above. Return an independent environment map + and selected sensitive names. No logging/serialization of values and no + changes to minimal child environment inheritance. +2. Test multiple custom names, empty lists, repeated names, unresolved references, + and captured values after the parent environment changes. Reuse existing + split/overlapping-stream redaction coverage rather than repeating its matrix. +3. Leave production callers unchanged until their migrations. -## Stage 1: Add the Shared Checkpoint Operation +Verify: `go test ./internal/adapters/subprocess` and +`go test -race ./internal/adapters/subprocess`. -Status: Complete. +Done when both adapters can reuse one small conversion mechanism without adding +a resolver, provider policy, or ambient-secret inheritance. -Completion marker (2026-09-22): Added the private stage-level checkpoint -save-and-promote helper and bounded candidate copying without migrating either -production caller. Focused real-store coverage proves live isolation through -updates, validation, save-time normalization and timestamps, save failures, -missing-target creation, pointer-preserving promotion, unrelated aggregate -preservation, caller-copy isolation, context/error identity, and exact one-save -behavior. Verified with `go test ./internal/manifest ./internal/stage`, -`go test -race ./internal/stage`, and `git diff --check`. +## Stage 2: Migrate Notarius to credential lists -Preparation: `internal/manifest/store.go`, `manifest.go`, `analyze_state.go`, -`transcribe_state.go`; `internal/stage/analyze_execution_state.go`, -`transcribe_execution_state.go`; `docs/internal/manifest.md`. +Status: Not started. -1. Add the private helper and bounded candidate copying described above. - Leave existing production checkpoint paths unchanged until their migration - stages. Do not duplicate manifest record-validation rules. -2. Add focused `internal/stage/checkpoint_test.go` coverage with real - `manifest.LocalStore` and temporary directories for successful save/reload. - Use a small Store wrapper only to observe/fail the persistence boundary. -3. Prove live progress remains old during Save, matches saved progress after - success, and does not change on update, validation, or save failure. Include - both typed collections and a transcribe checkpoint alongside analyze - records subject to save-time normalization. A failure test must exercise - candidate timestamp/normalization mutation before returning an error, not - merely fail before any work. -4. Prove unrelated stage/aggregate data survives, existing target references - observe updates, missing-target creation is invisible on failure, and later - caller collection edits do not mutate committed records. Preserve context - and error identity. Test the supported copy/write boundary, not arbitrary - malicious Store mutation. +Preparation: `internal/config/config.go`, `credential_projection.go`, loading/ +inspection tests; `internal/adapters/notarius/runner.go`, `subprocess.go`; +`internal/stage/extract.go` and its request construction; +`docs/integrations/notarius.md` and secret handling in `docs/config.md`. -Verify: `go test ./internal/manifest ./internal/stage` and -`go test -race ./internal/stage`. +1. Replace the singular field with the typed list across configuration, + projection, request types, stage wiring, and adapter execution. Use Stage 1's + helper and register all selected names for redaction. +2. Update name-only metadata and config-show/diff/effective projections. Test + real ConfigKit loading, profile list replacement, and empty-list clearing. + Preserve bootstrap precedence and existing load-time reference resolution, + including references outside the selected stage range. +3. Migrate maintained examples, fixtures, and current Notarius configuration/ + integration documentation for this field. Ordinary strict decoding rejects + the old field; do not add a compatibility parser. +4. Cover multi-key forwarding, unselected-key exclusion, empty selection, + captured-value behavior, and custom-name redaction on success/failure. + Keep extraction cache/reference/output tests as regression protection, + not occasions to redesign extraction. -Done when the shared integrity boundary is tested without changing existing -stage behavior. Temporary copying overlap is removed in Stage 3. +Verify: `go test ./internal/config ./internal/adapters/notarius ./internal/stage ./internal/app` +and `go test -race ./internal/adapters/notarius`. -## Stage 2: Migrate Analyze +Done when Notarius uses credential lists end to end and no active singular +credential path remains. -Status: Complete. +## Stage 3: Cut Audita configuration and adapter over to v2 -Completion marker (2026-09-22): Replaced analyze's local candidate-copy, -save, and promotion choreography with the shared checkpoint operation while -retaining its existing-record requirement, typed validation, path resolution, -and post-save working and committed collection refresh. Existing recovery, -selection, invalidation, and rollback coverage required no duplication. -Verified with `go test ./internal/stage ./internal/app ./internal/manifest`, -`go test -race ./internal/stage ./internal/app`, and `git diff --check`. +Status: Not started. -Preparation: `internal/stage/analyze_execution_state.go`, -`analyze_checkpoint_test.go`, `analyze_failure_test.go`, -`internal/app/analyze_checkpoint_recovery_test.go`, and -`docs/internal/stage-analyze.md`. +Preparation: Audita v2.0.0 `docs/migrations/v2.md`, `docs/cli.md`, +`docs/integrations/subprocess.md`, and `docs/integrations/output-files.md` in +`../audita/`; Narratio `internal/adapters/audita/`, +`internal/app/runner.go` (`buildDefaultAuditaRunner`), and config types, +defaults, validation, and credential projection. -1. Replace manual candidate copying, saving, and live promotion in analyze - with the shared helper. Retain typed validation, required-record checking, - the typed update callback, and committed/working collection refresh. -2. Preserve starting-checkpoint elision, selected-artifact behavior, catalog - sequencing, dependent invalidation on changed output, and rollback after - checkpoint failure. Do not change the runner's terminal failure save or - joined errors. -3. Run existing tests before adding coverage. Retain tests proving earlier - artifacts survive failure/cancellation, unsaved output bytes gain no - authority, selected/forced work preserves appropriate unrelated artifacts, - and interrupted runs recover across store reloads. Add only missing - integration coverage; do not duplicate Stage 1's isolation matrix. +1. Replace the Audita configuration surface as selected above, updating defaults, + validation, safe projection, examples, and config fixtures. Prove nil/empty + modules survive real configuration loading and profile overrides. +2. Migrate runner construction, selectors, and credential forwarding. Remove + retired flags, fixed credential alias, required work-directory plumbing, and + old JSON-report validation. Add the typed report bundle. +3. Implement adjacent report discovery, bounded reads, failure results, and + generated invocation v2. Share metadata construction between success/failure + instead of maintaining duplicate field maps. +4. Rewrite the Audita subprocess fixture to model v2 argument acceptance and + output placement. Cover omitted/selected selectors, ordered/repeated/empty + modules, no report/debug switches, malformed/missing transcript, ordinary + reports, externally disabled reporting, recoverable-error success, and + nonzero exit after transcript creation. Cover multiple custom credential names + and redaction; preserve timeout/cancellation coverage at its existing owner. +5. Make mechanical polish and app-fixture adjustments needed to compile: remove + obsolete request/metadata fields and old report materialization. Stage 4 owns + complete diagnostic integration. Remove retired fingerprint members as needed + to compile; Stage 5 completes the replacement semantic contract. These are + bounded call-site changes, not permission to introduce transitional shims. -Verify: `go test ./internal/stage ./internal/app ./internal/manifest` and +Verify: `go test ./internal/config ./internal/adapters/audita ./internal/stage ./internal/app` +and `go test -race ./internal/adapters/audita`. + +Done when configuration composes a v2-only adapter and subprocess tests prove its +credential/transcript/report boundary. Stages 4 and 5 are required before release. + +## Stage 4: Integrate polish reports with diagnostic lifecycle + +Status: Not started. + +Preparation: `internal/stage/polish.go`, `polish_test.go`, `run_local.go`, +`stage.go`, `publish_sources.go`; result application in `internal/app/runner.go`; +publish/restore diagnostic tests; `docs/internal/stage-polish.md`. + +1. Finish stage integration: materialize only the canonical polished transcript; + register available adjacent reports as diagnostics plus safe metadata and + existing logs/generated invocation references. Remove old `audita_report` + production and stale stage metadata. +2. Use existing authoritative-path checks for the requested transcript and fixed + adjacent report paths. Do not accept arbitrary fake-returned paths, scan + directories, or copy reports to a second destination. Preserve workspace + handling/modes. +3. On execution failure, preserve canonical transcript authority and run-local + diagnostics, with actionable directory/log context and original error identity. + Test failure after output creation. +4. Adapt the fake and app helper. With real manifest/store collaborators, prove + successful promotion, report references, absence of report canonical outputs, + and current-run diagnostic publication. Preserve restore's existing scope of + declared committed transcript/artifact objects: run-archive diagnostics do not + become automatically restored canonical objects. Test that report references + do not create new required canonical restore targets. Document remote diagnostic + inspection separately; no new diagnostic-restore feature is authorized. +5. Leave historical files untouched. Update tests expecting a second canonical + polish output without introducing a manifest-format migration. + +Verify: `go test ./internal/stage ./internal/app ./internal/manifest ./internal/artifacts` +and `go test -race ./internal/stage ./internal/app`. + +Done when reports use existing diagnostic lifecycle and failed execution cannot +promote an incidental transcript. + +## Stage 5: Complete semantic evidence and resume behavior + +Status: Not started. + +Preparation: `internal/stage/semantic_contracts_refinement.go`, semantic +fingerprint tests, app runner semantic comparison tests, and extraction semantic +configuration tests (locate their current owners through graph discovery). + +1. Implement polish evidence version 2 and the selected payload. Remove sorting; + preserve nil/empty distinction in payload encoding and copies. +2. Test changes from module order/repetition/presence and external selectors. + Credentials and execution-only settings do not change evidence. Avoid + assertions on incidental digest literals. +3. Exercise old-version evidence through runner resume behavior: selected polish + is reconsidered and normal dependent invalidation applies. Downstream-only + bounded execution does not unexpectedly invoke polish. Unchanged new evidence + reuses valid completed output. +4. Confirm credential-list changes leave extraction semantic/cache behavior + unchanged. No downstream file-content scanning or eager fingerprint migration. + +Verify: `go test ./internal/stage ./internal/app` and `go test -race ./internal/stage ./internal/app`. -Done when analyze delegates persistence choreography while progress, artifact -selection, and failure behavior remain unchanged. +Done when selections affect reuse accurately without blanket credential/config +invalidation or changes to unselected-stage execution. -## Stage 3: Migrate Transcribe and Remove Duplicate Machinery +## Stage 6: Complete operator migration documentation and examples -Status: Complete. +Status: Not started. -Completion marker (2026-09-22): Delegated transcription's locked checkpoint -operation to the shared helper while retaining typed validation, direct-call -record initialization, stage timestamp updates, post-save working collection -refresh, and the existing caller-owned mutex and failure latch. Removed the -duplicate production manifest clone; the read-only resume assertion now uses -the shared bounded snapshot. Existing real-store, concurrency, force/retry, -interruption, aggregate-repair, and zero-sized-audio coverage passed unchanged. -Verified with `go test ./internal/stage ./internal/app ./internal/manifest`, -`go test -race ./internal/stage ./internal/app`, and `git diff --check`. +Preparation: documentation policy; `docs/config.md`, `docs/operations.md`, +`docs/troubleshooting.md`, both integration guides, +`docs/internal/adapters.md`, `docs/internal/stage-polish.md`, and pipeline examples. -Preparation: `internal/stage/transcribe_execution_state.go`, `transcribe.go`, -`transcribe_resume.go`, `transcribe_checkpoint_test.go`, -`transcribe_reconciliation_test.go`, -`internal/app/transcribe_checkpoint_recovery_test.go`, and -`docs/internal/stage-transcribe.md`. +1. Complete current-behavior documentation as implementation lands. Configuration + owns fields/defaults; integrations own external contracts; operations owns + placement and migration; internal docs explain ownership and link onward. +2. Provide an old-to-new migration table: endpoints/capacity move to Audita + backends, models to profiles, role selection to selectors, and credentials to + provider-named lists. Remove report/retention settings. Explain Audita's + all-configured-backend credential resolution and Notarius's profile lookup. +3. Describe preparing and validating Audita v2 config offline with its documented + command before switching executables. Link upstream examples rather than + building a downstream configuration generator. Explain ordinary reports, + recoverable-error success, and force after edits behind unchanged selectors. +4. Production examples omit modules when upstream defaults are intended; + `modules: []` deliberately disables correction modules. Production external + Audita config keeps reports enabled/debug disabled, without Narratio flag + overrides. Testing-profile debug integration remains deferred. +5. Document the configuration-breaking clean cutover for release-version + consideration. Do not edit historical release records, tag a release, or + remove unrelated roadmaps. -1. Delegate `checkpointCollectionLocked` to the shared helper, retaining - typed initialization/update and successful working-collection refresh. - Keep the existing mutex across candidate creation, save, and promotion. - Do not move HTTP/hashing work into that critical section or add a lock. -2. Preserve failure-latch checks and worker joining, the parent versus worker - context distinction, force's durable empty starting collection, and - ordinary retry's reuse of committed forced replacements. -3. Remove `cloneManifestForTranscribeCheckpoint`. Its current use by a - read-only resume test is not a reason to retain duplicate production code. - Use an independent test snapshot or the shared bounded copy where sufficient, - without exporting a helper for tests. -4. Retain existing real-store and concurrency coverage: no lost completions; - pre-dispatch save failure prevents requests/canonical writes; later failure - retains prior authority; interrupted and aggregate-save recovery; failed - force followed by retry; run-directory independence; zero-sized audio; - removed/mismatched aggregate repair without additional WhisperX requests - or removed-speaker merge input. Do not weaken these regression assertions. - -Verify: `go test ./internal/stage ./internal/app ./internal/manifest` and -`go test -race ./internal/stage ./internal/app`. - -Done when both stages use one save/promote implementation and one bounded -copy implementation, with their different models and synchronization intact. - -## Stage 4: Document, Review Scope, and Validate - -Status: Complete. - -Completion marker (2026-09-22): Documented the private shared checkpoint -persistence boundary and linked the stage guides back to it while retaining -their separate analyze and transcribe progress policies. The refactor removed -the two local candidate/save/promotion sequences and the transcription-only -bounded clone; the retained thin wrappers own typed validation, updates, -working-state refresh, and their existing serialization and failure behavior. -The collective test review retained focused helper integrity coverage plus -stage/application recovery tests, without duplicating the helper's isolation -matrix. A cumulative scope audit found no schema, validation-policy, -scheduling, force, concurrency, output-selection, stage-order, adapter-call, -configuration, or public-interface change. - -Verified with `go test ./...`, `go test -race ./...`, `go vet ./...`, -`go build ./...`, `go test ./internal/doccheck`, +Verify: `go test ./internal/doccheck`, `go test ./internal/config -run '^TestExamplesLoadAndValidate$'`, and -`git diff --check`; all passed. +`git diff --check`. -Preparation: `docs/internal/manifest.md`, `docs/internal/stage-transcribe.md`, -`docs/internal/stage-analyze.md`, documentation/testing policies, and the -implementation diff against this plan's starting commit. +Done when operators can migrate using valid examples without obsolete fields, +implicit credential aliases, or retired CLI/report expectations. -1. Update manifest internals to identify the shared checkpoint owner and copy/ - save/promote boundary. Stage guides retain stage-specific policy and link - to that explanation instead of duplicating shared implementation details. - Do not rewrite immutable release notes or announce new operator behavior. -2. Assess tests collectively. Consolidate genuinely duplicated persistence - mechanics coverage, but retain stage/application recovery tests proving - correct integration. Avoid test-count/LOC quotas. Record a brief summary - here of duplicated mechanisms removed and thin wrappers retained. -3. Confirm no schema, validation policy, scheduling, force, concurrency, output - selection, stage order, adapter call, or configuration change slipped into - the refactor. Additional restrictions require a separate decision, not - tests that retrospectively declare new policy. -4. Run all gates below and record actual results. Mark this plan complete only - when both migrations and verification pass. Do not release, tag, push, delete - other roadmaps, or expand into a repository-wide cloning refactor. +## Stage 7: Verify assembled behavior and audit scope + +Status: Not started. + +Preparation: cumulative diff, this plan, feature roadmap, app configuration/ +subprocess integration tests, and all policies. + +1. Adapt or add one representative offline app-level scenario showing one + provider-named secret source supplying both adapters and another key selected + only for Audita. Use real config/bootstrap/composition with subprocess fixtures. + Prove safe inspection/logging and successful polish reports. Leave exhaustive + flag/redaction cases at lower layers. +2. Where the tagged Audita checkout is available, smoke-test CLI acceptance and + ordinary transcript/reports offline with an explicit minimal v2 config, + unauthenticated backend/profile fixtures, and an empty module sequence. + No provider requests or production credentials. This is optional local evidence, + not a default test dependent on sibling checkouts or installed tools. +3. Audit active references to removed fields/flags/aliases; historical release + notes and completed roadmaps are not compatibility code. Review tests + collectively for duplication while retaining consequential failure coverage. +4. Confirm no provider-name restrictions, duplicate-name rejection, downstream + content hashing, fail-on-recovery rule, mandatory explicit config path, debug + requirement, live-service gate, pipeline-order change, or Notarius cache change + slipped in. Do not require missing reports when disabled externally. Surface + additional policy choices rather than encoding them silently in tests. +5. Run every gate below and record actual results. Mark complete only after all + stages and gates pass. No release, tag, push, or unrelated cleanup in this plan. ```sh go test ./... @@ -322,12 +355,12 @@ go test ./internal/config -run '^TestExamplesLoadAndValidate$' git diff --check ``` -Done when duplication is removed, recovery remains covered, documentation -matches the implementation, and all gates pass. +Done when the assembled v2 integration and shared credentials meet the roadmap, +verification passes, and no compatibility machinery remains within scope. ## Open Questions -None requiring a product decision. A private stage-level helper is selected -because persistence already has an owner and the duplication is execution -plumbing. Model unification, library extraction, generalized transactions, and -broader cloning cleanup remain out of scope. +None requiring a product decision before implementation. The user settled the +clean cutover and shared provider-named lists. Reports use existing diagnostics +without new content-based success criteria; debug-profile work remains deferred. +Release version selection belongs to the later release procedure.