# Feedback-Aware Validation Retry Implementation Plan ## Status Ready for implementation. This plan implements the target state defined by [Feedback-Aware Stage Validation Retries](validation-retries.md). Its stages are ordered dependencies, and each stage is intentionally scoped for one gpt-5.6-terra implementation prompt. The feature roadmap owns product intent and durable policy. This document owns implementation order, concrete boundaries, and stage-level verification. If a conflict is discovered, preserve the feature roadmap and the repository policies, stop the affected stage, and revise this plan rather than silently choosing a different architecture. ## Settled Decisions The implementation agent must treat these decisions as fixed: - PromptKit v0.9.0 is the minimum and exact supported PromptKit release for this work. Notarius uses `RunRequest.AppendedMessages`; it does not create paired correction manifests or bypass PromptKit preparation and execution. - A correction request reconstructs the ordinary initial request and appends exactly two messages: the latest exact producer response as `assistant`, followed by one deterministic aggregate correction request as `user`. Earlier correction turns never accumulate. - A correction-capable producer supplies the exact single LLM response that directly controlled the candidate. The initial protocol does not synthesize a model-facing projection of a compound artifact. - The only supported producer correction protocol is `single_response_v1`. An empty protocol means unsupported. Configuration rejects semantic-retry workflows for LLM-backed compound producers or any other producer unable to satisfy `single_response_v1`. - The existing producer binding `retries` value is the sole outer stage budget. PromptKit repair attempts and validator execution retries are independent budgets. - Terminal policy is configured as pipeline defaults with field-by-field producer-binding overrides. Validators never own candidate disposition. - Application defaults are `fail_run` for exhausted producer structural failure, `fail_run` for exhausted semantic rejection, and `warn_continue` for exhausted validator execution failure. - All applicable validators run sequentially in configured order. Rejections and validator failures are aggregated; failures are not represented to the producer as candidate defects. - Deterministic producers do not consume retries after rejection. An LLM-backed attempt that took a deterministic fast path and produced no model response is likewise not correctable for that candidate. - Known rejected or structurally invalid output never advances. A candidate accepted under `validator_failure: warn_continue` advances with explicit incomplete-validation provenance but is not checkpointed. - The D&D combat-scene validator and broader warning-system redesign remain out of scope. ## Cross-Stage Implementation Rules Apply these rules in every stage: 1. Read the feature roadmap, `docs/development.md`, all `docs/policy/` documents, and the focused current documentation named by the stage before editing. 2. Inspect current code and tests rather than assuming paths or private helper layouts. Preserve unrelated work and existing public ordering, cancellation, scheduler, checkpoint, and sensitive-data invariants. 3. Use transport-neutral types outside `internal/framework/llm`. PromptKit types must not escape the adapter boundary. 4. Keep correction material attempt-local. Do not put raw assistant responses or correction text in ordinary errors, warnings, manifests, receipts, checkpoints, caches, or default debug summaries. 5. Add the smallest durable tests that protect the stage's contracts. Do not duplicate PromptKit's own prepared-execution, copying, hashing, capacity, role-validation, or structural-repair test matrix. 6. Use `gofmt` on changed Go files. Run the focused checks listed for the stage and fix failures before stopping. Do not proceed into the next stage in the same prompt. 7. Do not delete this plan or the feature roadmap during implementation. They are retired only after a final review confirms the complete target state. ## Contract Names And Bounds Use one vocabulary consistently across packages. Exact private helper names may follow local conventions, but the following contracts and values are not open for redesign: - `CorrectionProtocol` has only the empty unsupported value and `single_response_v1`. - An application-owned `SemanticCorrection` carries owned `AssistantResponse []byte` and `UserGuidance string` values. It is exposed on chunk, typed extract, typed merge, typed normalize, and structured completion requests as an optional pointer. - An application-owned `ModelCandidate` carries the owned exact response bytes and `CorrectionProtocol`. It is exposed on the corresponding producer results as an optional pointer and is never serialized as part of a durable artifact. - `ValidationResult` gains optional `CorrectionGuidance`. Operator-facing `Message` is not copied into this field implicitly. - Each reason code is valid UTF-8, nonblank after trimming, and at most 128 bytes. Each validator-supplied correction guidance value is valid UTF-8, nonblank after trimming, and at most 4 KiB. - The exact defective assistant response may be at most 1 MiB. The aggregate user correction message may be at most 64 KiB. The combined appended content may therefore be at most 1,114,112 bytes. Reject invalid UTF-8, empty/whitespace-only content, or over-limit content; never truncate it. - Invalid producer-owned correction material is a framework contract error. It is not a validator failure and cannot be converted to `reject_output` or `warn_continue`. - Aggregate correction entries are ordered by validator order, contain the stable reason code plus guidance, and collapse only byte-identical duplicate `(reason_code, correction_guidance)` pairs while retaining first occurrence. A rejection without guidance receives bounded generic guidance based only on its reason code. - Terminal actions are closed enums: structural failure and semantic rejection accept `fail_run` or `reject_output`; validator failure accepts `warn_continue` or `fail_run`. ## Stage 1 — Adopt PromptKit v0.9.0 ### Goal Upgrade the dependency without changing Notarius stage behavior, prove the existing integration remains compatible, and make the new upstream request primitive available to later stages. ### Work - Update `go.mod` and `go.sum` to PromptKit v0.9.0 with `go get` and `go mod tidy`. Accept the catalog modules selected transitively by PromptKit; do not import or register them directly. - Review every Notarius `promptkit.RunRequest` literal and retain keyed form. Verify production prompt roles are limited to `system` and `user`. - Update the conservative built-in-profile checkpoint marker in `internal/framework/llm/promptkit_profile_fingerprint.go` from v0.8.0 to v0.9.0. Do not duplicate the separately versioned catalog module versions. - Update `docs/integrations/pkg-promptkit.md` only to describe the newly implemented dependency version and unchanged current integration boundary. Include the strict role vocabulary and external catalog ownership, but do not document Notarius correction behavior yet. ### Verification - Run `go test ./internal/framework/llm ./internal/cli`. - Run `go test ./...`, `go test -race ./internal/framework/llm`, `go vet ./...`, and `go build ./cmd/notarius`. ### Exit Criteria Notarius builds and passes its suite on PromptKit v0.9.0, its compatibility document and checkpoint marker name v0.9.0, and no Notarius package directly depends on either upstream catalog module. This stage is one Terra prompt. ## Stage 2 — Record The Architecture And Add Transport-Neutral Contracts ### Goal Record the durable decision and introduce owned correction/candidate types without changing runtime retry behavior. ### Work - Add ADR-0014 under `docs/adr/` using the repository ADR format. Record the three distinct retry budgets, complete validator aggregation, the fresh two-message correction protocol, exact-response producer capability, non-recursive validator failure handling, terminal-policy ownership and defaults, checkpoint conservatism, and sensitive-data constraints. - Add `CorrectionProtocol`, `SemanticCorrection`, and `ModelCandidate` to the domain-neutral framework contracts, with constructors/clone helpers that validate the settled bounds and defensively copy bytes. - Add optional correction input to `ChunkRequest`, `TypedExtractionRequest`, `TypedMergeRequest`, and `TypedNormalizeRequest`. - Add optional model-candidate output to `ChunkPlanResult`, `TypedExtractionResult`, `TypedMergeResult`, and `TypedNormalizeResult`. - Add `CorrectionGuidance` to `ValidationResult` and centralize validation of reason codes and corrective guidance at the framework boundary. - Update type-erasure adapters, stored fakes, and clone paths so the new values retain ownership and cannot alias caller buffers. Do not declare production module capabilities or use the fields in the runner yet. ### Verification - Add contract-level tests for accepted values, UTF-8 and size rejection, defensive copying, nil behavior, and typed-erasure preservation. - Run `go test ./internal/framework/contracts ./internal/framework/pipeline`. - Run `go test ./...`. ### Exit Criteria The generic contracts can safely carry correction input and exact candidate material across every producer stage, no PromptKit type crosses the boundary, and existing runtime behavior is unchanged. This stage is one Terra prompt. ## Stage 3 — Add Validation Policy Configuration And Resolution ### Goal Implement strict configuration, inheritance, identity, and provenance for terminal validation policy before the runner consumes it. ### Work - Add optional `validation_policy` to a pipeline profile and to chunk, extract, merge, and normalize producer bindings. Use pointer-backed override fields so omission is distinguishable from an explicit value. - Reject an explicitly null policy object, null policy fields, duplicate or unknown fields, and values outside the settled enums. Keep the current file configuration version. - Reject `validation_policy` on input, output, and validator bindings. Reject a binding-level explicit `producer_structural_failure` value on a deterministic producer; a pipeline-level structural default remains valid because a pipeline may contain LLM-backed producers. - Resolve each policy field independently in binding, pipeline, application default order. Store one detached concrete effective policy for chunk and for each lane's extract, merge, and normalize stage; do not leave runtime inheritance to the runner. - Include both configured overrides and effective policies at their existing appropriate configuration/provenance boundaries. Include the effective values in resolved-pipeline digest and checkpoint identity. Preserve deterministic serialization and redaction. - Update `examples/dnd-minimal/config.yml` and `examples/dnd-complete/config.yml` only if their current shape must change to remain valid; do not add redundant explicit defaults merely to demonstrate the feature. ### Verification - Add focused parsing tests for omission versus null, unknown/duplicate fields, invalid placements, and invalid enums. - Add resolution tests for field-by-field inheritance and mixed overrides. - Add digest, clone, JSON/YAML round-trip, and redacted-effective-config tests. - Run `go test ./internal/core/config ./internal/framework/pipeline ./internal/cli`. ### Exit Criteria Every producer stage receives one immutable effective policy, invalid configuration fails before execution, and policy changes invalidate resolved identity. The runner still follows its old behavior until later stages. This stage is one Terra prompt. ## Stage 4 — Declare And Validate Producer Correction Capability ### Goal Make correction support an explicit module contract and prepare the framework to reject impossible workflows. ### Work - Extend `pipeline.ModuleSpec` with `CorrectionProtocol`; normalize, clone, validate, and include it in relevant registry/spec fingerprints. - Permit `single_response_v1` only for LLM-backed chunk, extract, merge, or normalize modules. Reject it for deterministic, input, output, or validator specs. Empty remains the default unsupported value. - Carry the selected protocol into resolved and prepared producer metadata and checkpoint fingerprints. - Reject positive `retries` on deterministic validator bindings during resolution. LLM-backed validator retries remain valid and independent of producer capability. ### Verification - Add spec normalization/clone tests, invalid stage/class combinations, validator retry-class tests, and preparation tests for supported and unsupported producer workflows. - Run `go test ./internal/framework/pipeline ./internal/core/config`. ### Exit Criteria Capability is explicit, fingerprinted, and testable, while existing production pipelines remain executable pending their migrations. No dormant feature gate or unused preparation check is introduced. This stage is one Terra prompt. ## Stage 5 — Adapt Corrections Through PromptKit ### Goal Map the transport-neutral correction contract onto PromptKit v0.9.0 without changing ordinary requests. ### Work - Add optional `SemanticCorrection` to `StructuredCompletionRequest` and its debug-safe request representation. - In `PromptKitClient.CompleteStructured`, validate and defensively copy the correction, then map it to exactly two `promptkit.RenderedMessage` values in `RunRequest.AppendedMessages`, using `promptkit.RoleAssistant` followed by `promptkit.RoleUser`. - Leave `AppendedMessages` nil for an ordinary request. Do not allow callers to choose other roles through the Notarius contract. - Ensure request formatting and default debug summaries expose only safe counts/digests. The existing explicitly requested detailed PromptKit trace may contain complete effective messages and must retain its existing sensitive-data treatment. - Preserve the same prompt identity, inputs, variables, session, profile, execution overrides, repair attempts, scheduler, and prepared-execution path for corrected calls. ### Verification - Add focused adapter tests proving an ordinary request is unchanged and a corrected request has the ordinary rendered prefix plus exactly the two supplied messages in order with exact content. - Test invalid/oversized correction rejection before preparation and absence of raw content from ordinary formatting/errors. - Add one representative test showing PromptKit structural repair remains available on a request with appended messages; do not reproduce upstream's complete repair suite. - Run `go test ./internal/framework/llm ./internal/framework/pipeline` and `go test -race ./internal/framework/llm`. ### Exit Criteria Notarius has one safe, tested adapter path for fresh corrected requests, and no stage invokes it yet. This stage is one Terra prompt. ## Stage 6 — Migrate The Scene Chunker And Foundational Extractors ### Goal Make the scene chunker and the foundational direct D&D extractors satisfy `single_response_v1`. ### Work - Update `dnd/scenes`, `dnd/npc-registry`, `dnd/item-registry`, `dnd/location-registry`, `dnd/scene-descriptions`, and `dnd/spells` producer implementations to pass request correction to their structured completion and return an owned copy of the successful response's exact validated raw bytes as `ModelCandidate`. - Declare `single_response_v1` in each corresponding module spec. - Do not serialize normalized artifacts to fabricate candidate material. Keep artifact parsing, deterministic identity attachment, evidence validation, warnings, and durable schemas unchanged. - Update shared D&D extraction helpers only where the behavior is genuinely common; keep domain prompt ownership in each module. ### Verification - Use representative package-level tests to prove exact-response propagation, correction forwarding, and input/result ownership. Update spec tests for the declared protocol without multiplying the same behavior test across all six modules. - Run the affected module tests and `go test ./internal/modules/dnd/...`. ### Exit Criteria All named producers truthfully advertise and implement the exact-response protocol, with unchanged ordinary extraction behavior. This stage is one Terra prompt. ## Stage 7 — Migrate Downstream D&D Extractors ### Goal Complete `single_response_v1` support for the remaining direct D&D extraction producers. ### Work - Migrate `dnd/npc-occurrences`, `dnd/item-occurrences`, `dnd/location-occurrences`, `dnd/combat-turns`, and `dnd/enemy-events` using the same contract as Stage 6. - Preserve their contextual-name and deterministic-ID rules. Correction messages must never introduce opaque registry IDs or ask the model to copy them. - Preserve combat-scene gating, reference projections, and prompt-cache prefix ordering. The correction pair is appended after the complete existing request and never changes stable prompt assets. ### Verification - Add or adapt focused tests for correction forwarding and exact raw-response retention at the shared boundary, plus one registry-grounded extractor case proving no opaque IDs enter correction material. - Run the affected module tests, `go test ./internal/modules/dnd/...`, and the assembled D&D CLI contract tests. ### Exit Criteria Every direct production D&D LLM extractor implements the same correction protocol without changing artifact semantics. This stage is one Terra prompt. ## Stage 8 — Migrate Semantic Reconciliation Normalizers ### Goal Support correction for the current single-proposal reconciliation path and activate capability enforcement for all eligible production producers. ### Work - Extend `semanticreconcile.Request` to accept `SemanticCorrection` and its result to expose the exact validated proposal response as owned `ModelCandidate` when an LLM call actually occurred. - Forward correction through the shared engine's ordinary structured completion request. Preserve request-local integer candidate handles, proposal validation, typed application policies, and fallback behavior. - Update the NPC-, item-, and location-registry normalizers to carry the exact proposal material through their typed result and declare `single_response_v1`. - Mark deterministic skip/limit/fallback outcomes as having no model candidate. If such a candidate is later rejected, it is not correctable and must not consume a retry merely because its module execution class is LLM-backed. - Audit all production LLM-backed producer specs. Add the preparation rule that an LLM-backed producer with a non-empty validator chain and `retries > 0` must declare `single_response_v1`. Any genuine multi-response producer remains unsupported and a configured validator-backed semantic retry for it must fail preparation. ### Verification - Add engine tests for initial and corrected requests, exact proposal bytes, deterministic no-call outcomes, invalid proposal outcomes, and ownership. - Add representative normalizer and preparation tests for supported, unsupported, and no-validator/no-retry configurations. - Run `go test ./internal/framework/semanticreconcile ./internal/framework/pipeline ./internal/modules/dnd/... ./internal/cli`. ### Exit Criteria All eligible production LLM producers implement the declared protocol, unsupported workflows fail before source parsing, and ordinary operational retries remain allowed when semantic correction cannot occur. This stage is one Terra prompt. ## Stage 9 — Build Complete Validator-Chain Execution ### Goal Replace first-result validation with one reusable, deterministic executor that aggregates the complete chain and isolates validator retries. ### Work - Introduce an internal immutable `validationReport` model with one ordered invocation record per validator: approved, rejected, failed, or skipped; validator attempt count; safe reason/message metadata; warnings; and bounded correction guidance. - Implement one shared sequential executor around stage-specific invocation closures. It must continue after rejection and isolated execution failure, retry an LLM-backed failed validator against the same immutable candidate up to its binding budget, and stop retrying after a contract-valid approval or rejection. - Reconstruct the same ordinary validator request for each validator retry. Do not append feedback to validator prompts and do not regenerate the producer candidate. - Preserve only one final warning for an exhausted validator failure; retain individual attempt details for debug. Keep warnings from completed validators in configured order. - Build aggregate correction guidance from all rejections using the settled ordering, deduplication, generic fallback, and bounds. Validator failures, skips, warnings, and operator messages must not enter it. - Retain `skipped` as a framework-owned outcome for an otherwise selected validator whose runtime prerequisites are unavailable. Module construction, type incompatibility, candidate cloning failure, cancellation, and debug persistence failure remain framework errors rather than skips. ### Verification - Add table-driven behavior tests for all approved, multiple rejections, rejection plus failure, failure only, skipped, retry success, retry exhaustion, immutable candidate reuse, deterministic ordering, duplicate guidance, and bounds. - Prove deterministic validators cannot receive positive retry budgets and LLM validator retry counts do not consume producer attempts. - Run `go test ./internal/framework/pipeline` and `go test -race ./internal/framework/pipeline`. ### Exit Criteria The shared executor returns a complete ordered report without deciding whether the producer candidate advances. Existing stage callers may still adapt the report through their old disposition path until the next stages. This stage is one Terra prompt. ## Stage 10 — Implement The Generic Producer Attempt State Machine ### Goal Replace the boolean retry helper with one explicit domain-neutral state machine used by later stage integrations. ### Work - Refactor `runWithRetry` into an attempt engine that accepts producer and complete-validation closures and returns a terminal result plus ordered attempt provenance. Keep stage-specific artifact handling outside it. - Classify attempts as initial, operational-error retry, structural retry, module-requested retry, or semantic correction. Preserve one total producer budget of `retries + 1` attempts. - On semantic rejection, correct only when another attempt exists and the current candidate contains valid `single_response_v1` material. Construct a fresh `SemanticCorrection` from that latest response and aggregate feedback. - Apply outcome precedence and effective terminal policy exactly as the feature roadmap specifies. Ordinary producer errors remain framework errors after retries. Only `ErrInvalidStructuredOutput` uses the structural-failure policy; `reject_output` records no usable artifact. - A deterministic or no-model candidate applies semantic terminal policy immediately without spending an ineffective retry. - With rejection plus validator failure, use rejection guidance for a correction while recording incomplete validation. With failure only, apply validator-failure policy without regenerating the producer. - Keep cancellation and debug-persistence failures immediately terminal. Abandoned-attempt warnings must not be promoted. ### Verification - Test the state machine through stable behavior with fake closures: budget accounting, fresh correction history, latest-response replacement, all terminal actions, failure precedence, deterministic candidates, cancellation, and warning promotion. - Do not assert private helper call choreography or exact correction prose. - Run `go test ./internal/framework/pipeline` and its race-enabled suite. ### Exit Criteria One tested state machine owns attempt budgets and disposition, but no stage is partially migrated. This stage is one Terra prompt. ## Stage 11 — Integrate Chunk Validation And Correction ### Goal Move chunk generation, validation, cache reuse, and retry disposition onto the new state machine. ### Work - Adapt chunk candidate materialization and both chunk/serialized validator targets to the complete-chain executor. - Pass correction only to a generated chunker attempt and retain the exact raw chunker response associated with the materialized plan. - Preserve chunk-plan cache identity and mode semantics. A rejected automatic cache hit is unusable for the invocation and falls through to generated attempt one without pretending the cache hit has model material. Publish a newly generated plan only after complete accepted validation. - Apply chunk effective terminal policy. A terminal chunk rejection prevents lane execution; a framework error still prevents output encoding. - Preserve annotation materialization, deterministic plan canonicalization, attempt debug paths, scheduler use, and checkpoint behavior. ### Verification - Add focused tests for corrected plan acceptance, multi-validator feedback, rejected cache hit regeneration, cache non-overwrite, incomplete-validation non-publication, policy outcomes, cancellation, and debug failure. - Run `go test ./internal/framework/pipeline ./internal/modules/dnd/chunk/... ./internal/cli` and the pipeline race tests. ### Exit Criteria Chunk is the first complete production stage using feedback-aware retries, with cache and terminal behavior matching the roadmap. This stage is one Terra prompt. ## Stage 12 — Integrate Per-Chunk Extraction ### Goal Apply the state machine independently to every concurrent extraction job. ### Work - Adapt typed and serialized extract validation to the complete-chain executor and use the extract binding's effective policy. - Keep correction state local to one lane/chunk job. Rebuild the same initial extraction request with correction attached only on a semantic retry. - Preserve the run-wide worker pool, scheduled LLM client, chunk-first/lane- second public ordering, stable error selection, cancellation, and lane continuation rules. - Ensure `reject_output` records the terminal chunk-scoped rejection without advancing it to merge. `warn_continue` is available only for validator failure with no semantic rejection and marks the accepted extract as validation-incomplete. ### Verification - Add representative extraction tests for correction success, exhausted rejection, validator failure policy, independent concurrent jobs, stable ordering, cancellation, and warning promotion. - Add one assembled D&D pipeline test using fakes—not a live provider—to prove a rejected direct extraction is corrected using the exact prior response. - Run `go test ./internal/framework/pipeline ./internal/modules/dnd/... ./internal/cli` and relevant race tests. ### Exit Criteria Every extraction job has an isolated bounded correction conversation and continues to obey existing concurrency and ordering contracts. This stage is one Terra prompt. ## Stage 13 — Integrate Merge And Normalize ### Goal Complete stage coverage and reconcile semantic correction with the existing normalizer fallback retry directive. ### Work - Adapt typed and serialized merge and normalize validation to the shared executor and their respective effective policies. - Keep merge and normalize serial within a lane and reuse the exact same accepted upstream artifacts, references, source input, profile, and session on every attempt. - Fold `NormalizeRetry` into the one producer attempt state machine. It consumes the same remaining stage budget, retains its validated safe fallback when exhausted, and never overrides a semantic rejection of that fallback or a later candidate. - Do not send correction to deterministic mergers/normalizers. A rejected deterministic candidate applies terminal policy immediately. - Preserve typed erasure checks, codec boundaries, generated handoffs, and lane continuation/cancellation behavior. ### Verification - Add one representative merge path and normalize paths for correction success, deterministic rejection, `NormalizeRetry` success/exhaustion, fallback rejection, validator failure, and terminal policies. - Run `go test ./internal/framework/pipeline ./internal/framework/semanticreconcile ./internal/modules/dnd/... ./internal/cli` and relevant race tests. ### Exit Criteria Chunk, extract, merge, and normalize all use the same attempt and validation semantics, with no nested normalizer retry loop. This stage is one Terra prompt. ## Stage 14 — Finalize Provenance, Checkpoints, Debug, And Durable Results ### Goal Make the new state machine auditable and safe without leaking correction content or allowing degraded output to become reusable state. ### Work - Extend internal attempt/debug records with attempt kind, PromptKit repair count and usage, ordered validator outcomes and attempt counts, aggregate reason codes, validation completeness, effective policy, and terminal decision. - Keep raw assistant responses and complete correction messages only in the existing explicitly requested detailed trace. Default summaries contain counts, digests, identities, and bounded safe fields. - Add one reusable durable validation summary with the JSON fields `status`, `rejecting_validators`, `reason_codes`, `incomplete_validators`, `producer_attempt_count`, and `terminal_action`. `status` is one of `complete`, `rejected`, or `incomplete`; lists preserve configured order and omit duplicates after their first occurrence. Embed or project this summary at the manifest, rejection, and run-result boundaries that already expose the affected stage outcome. Preserve the existing singular rejection fields as the first configured rejection for downstream continuity; do not put raw guidance or responses in the summary. - Emit one genuine, bounded, deterministically ordered warning per validator whose execution budget is exhausted under `warn_continue`; do not emit a warning merely because a later correction succeeded. - Checkpoint only accepted and completely validated results. Never write or reuse rejected, structurally invalid, or validation-incomplete producer output. Ensure correction protocol and effective policy participate in fingerprints. - Confirm cache, resume, generated-reference handoff, output encoding, and CLI result publication cannot treat a rejected or incomplete checkpoint as accepted. ### Verification - Add focused manifest, receipt, warning, debug, redaction, checkpoint reuse, generated-handoff, and sensitive-content tests at their canonical owners. - Test that corrected success is auditable but quiet, warn-continue output is never checkpointed, and raw content is absent from ordinary durable files. - Run `go test ./internal/framework/pipeline ./internal/framework/checkpoint ./internal/framework/artifacts ./internal/cli` and relevant race tests. ### Exit Criteria Every terminal path has accurate bounded provenance, no sensitive correction content leaks by default, and only completely validated output is reusable. This stage is one Terra prompt. ## Stage 15 — Update Canonical Documentation And Perform Final Verification ### Goal Document the implemented contracts in their canonical homes and prove the repository is ready for review. ### Work - Update `docs/policy/architecture.md` with durable validator aggregation, retry-budget separation, producer correction capability, terminal-policy, checkpoint, and sensitive-data invariants. Link to ADR-0014 for rationale. - Update `docs/config.md` with the exact `validation_policy` schema, enum values, defaults, inheritance, placement restrictions, retry-budget meanings, and invalid combinations. - Update `docs/operations.md` with costs, terminal outcomes, warnings, debug sensitivity, retry exhaustion, resume/cache consequences, and recovery. - Update `docs/internal/pipeline.md`, `docs/internal/llm.md`, and `docs/internal/modules.md` with implemented mechanics and focused test routing. Keep public configuration definitions in `docs/config.md`. - Complete `docs/integrations/pkg-promptkit.md` for v0.9.0 appended messages, supported roles, application-owned bounds, and the external catalog boundary. Update the run-result and affected output/subprocess integration contracts for any durable fields added in Stage 14. - Update maintained examples only to demonstrate implemented behavior. Use a minimal policy override in the complete D&D example if it materially aids operators; keep the minimal example minimal. Ensure all links point to canonical owners and remove stale v0.8.0 claims outside historical release notes. - Do not create a release note until an actual release is prepared. ### Verification - Run `gofmt` on all changed Go files. - Run `go test ./...`, `go test -race ./...`, `go vet ./...`, and `go build ./cmd/notarius`. - Run the repository's example/config validation tests and documentation link checks. If no standalone link checker exists, verify changed relative links and record that manual check in the implementation report. - Use targeted searches to confirm no current documentation still claims PromptKit v0.8.0, no production correction-capable spec is missing its protocol, no PromptKit type escaped `internal/framework/llm`, and no raw correction content is serialized outside explicit detailed debug data. - Review `git diff --check` and `git status --short`; do not include generated binaries, temporary files, or unrelated work. ### Exit Criteria All roadmap acceptance criteria are satisfied, canonical documentation matches the code, maintained examples validate, the complete ordinary and race-enabled test suites pass, and the worktree contains only intentional implementation changes. This stage is one Terra prompt. ## Open Questions None. PromptKit transport, producer representation, terminal-policy ownership, bounds, retry budgets, outcome precedence, and checkpoint treatment are all settled by the feature roadmap and this plan.