# Implementation Plan: PromptKit v0.12.0 Adoption **Last updated:** 2026-10-04 **Status:** Complete; Stages 1–9 completed. **Audience:** Luna coding agent. ## Scope and Execution Implement the accepted target in the [PromptKit roadmap](promptkit.md). That document owns feature intent and policy choices; this plan owns the ordered implementation work. The planning baseline is Audita commit `b31955fc97adec707b4e5f9a1b0c43c4cbc66750`: ConfigKit v0.5.0 is adopted, PromptKit is v0.11.2, and the finalized roadmap includes the selected-profile, operator-override, example-layout, and major-release clarifications. This replaces the completed ConfigKit plan at this path. Its [completed implementation record](https://gitea.maximumdirect.net/eric/audita/src/commit/b31955fc97adec707b4e5f9a1b0c43c4cbc66750/docs/roadmap/implementation.md) remains available for readers following the ConfigKit completion roadmap. Execute Stage 1 through Stage 9 in order. Each is sized as one bounded Luna implementation prompt. Commit completed units with short, plain English messages under the [agent policy](../policy/agents.md); no approval round is needed between stages. Record actual checks and any remaining expected migration failures. Stages 1 and 2 change formats before Stage 3 changes their consumer. Intermediate commits need not be runnable or release-ready. Do not add temporary readers, compatibility shims, fallback engines for execution, or scaffolding to make them so. Later stages complete the same migration rather than separate product modes. Start with [development guidance](../development.md) and the applicable agent, [architecture](../policy/architecture.md), [testing](../policy/testing.md), [documentation](../policy/documentation.md), and [OSS](../policy/oss.md) policies. Use graph-first discovery. Read the current [configuration](../config.md), [LLM runtime](../internal/llm-runtime.md), [prompt registry](../internal/prompts.md), and [LLM integration](../integrations/openai-compatible-llm.md) contracts for the established behavior this migration preserves. Target the released PromptKit v0.12.0 at commit `4b8169da286917fde7875425bb32b799b12c6af3`, ConfigKit v0.5.0, and both maintained `/v3` catalogs at `v3.20260930.0`. Read the pinned [format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.12.0/docs/formats.md) and [migration guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.12.0/docs/consumers/pkg-promptkit.md#migrate-from-the-previous-configuration-api). The sibling checkout is reference material, not a dependency replacement. ### Selected Implementation Decisions - Keep Go 1.25.5, application `version: 2`, current flags, role selection, application overlays, and main-file-relative path rules. Retain the `profiles_dir` name and default; broaden its accepted documents as agreed. - Use PromptKit's catalog and owned defaults, then caller underlays for embedded Audita prompts and operator directory inputs, then `Sources.Main` for application backend settings. Directory inputs compose strictly within their group; discovery order supplies no field precedence. Keep imports disabled. - Use one ConfigKit mapping for the final application source. For each application backend, supply its endpoint, `concurrency_limit`, `queue_capacity`, and explicit `api_key_env: null`. The null suppresses lower-tier credential lookup. Leave other supported provider fields available to native layering. Do not put resolved credential values in this mapping. - Keep selected-role registration, endpoint-match, competing-credential, and required-key checks. Add explicit nonblank effective model and endpoint checks for both selected roles. Valid unselected partial profiles remain permitted. - Preserve the adapter's complete per-call schemas, configured repairs/retries, operation context, shared variables, observation, and prepare/check/run flow. Operator messages can omit shared-variable references; do not append the shared text unconditionally or require particular message counts or roles beyond PromptKit's own format rules. - Use captured source inspection for consumed host configuration and message paths. Keep source-relative resource resolution with PromptKit and ConfigKit; Audita projects paths for its existing output collision checks. - Replace the old profile-reload test expectation with snapshot behavior. Successful construction uses only final effective definitions. A failed construction may make an embedded-only diagnostic construction to distinguish asset defects from operator errors; it never executes or substitutes for the requested configuration. - Maintained example roots are `examples/profiles/local/` and `examples/profiles/service/`. Service testing profiles stay in the service root. Keep the literal `temperature: 0` in examples as an explicit outbound setting, and use native presence semantics without a compatibility translator. This unit is an intentional major-release migration. Exact version selection, release notes, tag/push, and publication timing remain release preparation under the [release policy](../policy/release.md). Guided recovery, new report formats, hot reload, extra configuration commands, and scheduling changes remain outside this plan. Tests should protect changed integration behavior and established contracts, not reproduce the libraries' entire validation matrices. ## Stage 1 — Convert Embedded Prompt Definitions **Primary files:** The seven YAML files under `internal/prompts/assets/prompts/`. 1. Wrap each existing definition beneath `prompts`, its exact current ID, and the string version `v1`. Remove the old inner `id` and `version` fields. Keep filenames and Audita registry identifiers unchanged; filenames are asset locations rather than PromptKit identities. 2. Preserve messages, block-scalar text, variable references, task examples, output settings, and schema paths. Preserve the applicable references to `HardeningPolicy`, `ProposalContract`, and `ValidationContract`. Do not edit shared fragments, response schemas, or domain policies to accommodate the new container format. 3. Review each before/after definition structurally, including YAML indentation inside block scalars. Do not introduce default profile selections or new repair counts. The adapter continues to own the runtime output contract. **Verification and completion:** Check all seven migrated identities and version keys against `RegisteredMetadata`, and run `git diff --check`. Registry preparation tests become runnable with the new constructor in Stage 3. Commit the asset conversion; do not introduce an old-format reader to test it here. **Completion marker:** Stage 1 complete. All seven registered prompt assets use keyed prompt/version mappings; parsed definitions were structurally checked against their prior content, and `git diff --check` passed. ## Stage 2 — Migrate Operator Profiles, Example Roots, and YAML Fixtures **Primary files:** `examples/profiles/`, the three maintained configuration examples, and profile-producing test fixtures in `internal/framework/llm/{runtime_inspection,adapter,adapter_capacity}_test.go`, `internal/framework/proposal_generation/adapter_integration_test.go`, `internal/framework/validators/llm_integration_test.go`, `internal/framework/runner/cancellation_test.go`, and `cmd/audita/main_integration_test.go`. 1. Move local proposal/validation examples beneath `profiles/local/`; move the four service proposal/validation and testing files beneath `profiles/service/`. Convert each to `profiles: {: }` in readable YAML. Keep IDs, models, positive timeouts, and controls, including explicit zero temperature. No example needs a real credential or live model. 2. Set `profiles_dir: profiles/local` in `examples/minimal-config.yml` and `examples/configkit-inheritance.yml`; set `profiles_dir: profiles/service` in `examples/production-config.yml`. Preserve the testing overlay's role IDs and the existing ConfigKit inheritance example. Select the leaf root, since recursive discovery at their common parent would still load both groups. 3. Convert profile YAML emitted by the listed fixtures to keyed definitions. Search for remaining old profile construction strings and removed `base_profile` syntax, and migrate any genuine profile fixture found. Do not rewrite transcript/proposal `id` fields or domain schema fixtures. Keep test source names independent of profile IDs where already exercised. 4. Keep negative tests negative for their selected behavioral reason. Give cases clean temporary layouts or replace their contribution completely rather than leaving an unrelated invalid definition behind for later cases. Eager validation now reads unselected final definitions too. Do not remove such definitions merely to simulate the old lazy loader where the test is intended to exercise eager validation. **Verification and completion:** Review the six profiles, explicit root selections, and changed fixture text; run `git diff --check` and format touched Go test files. These formats become consumable in Stage 3. Commit this unit. Current documentation links and recipes are updated together in Stage 8. **Completion marker:** Stage 2 complete. Six maintained profile documents are keyed and split into separately selected local/service roots; the listed Go fixtures use keyed definitions. Touched Go files were formatted and `git diff --check` passed. Runtime tests are deferred until Stage 3 replaces the current consumer, as the plan allows intermediate commits not to run. ## Stage 3 — Adopt the Released Source API and Selected-Role Checks **Primary files:** `go.mod`, `go.sum`, `internal/framework/llm/runtime.go`, and `internal/prompts/registry_test.go`. 1. Upgrade with `go get gitea.maximumdirect.net/eric/promptkit@v0.12.0` and reconcile the module files. Verify ConfigKit stays v0.5.0, the catalog dependencies become `/v3` at `v3.20260930.0`, and obsolete `/v2` requirements are removed when unused. Retain the Go minimum and unrelated selections; introduce no local replacements. 2. Resolve `profiles_dir` exactly as the current runtime does. Obtain embedded inputs with `pk.FilesystemInputs` and operator inputs with `pk.DirectoryInputs`. An unavailable selected root is an operator error; an empty directory can contribute no definitions. Do not require one profile per file, IDs matching filenames, or profile-only top-level content. 3. Construct the agreed `pk.ConfigurationSources`: two ordered caller underlays for embedded and operator groups, and one highest-priority application `ck.Input` whose source is the mapping specified above. Retain `pk.WithSchemaFS`, the supplied HTTP client, and configured transient retries. Remove old prompt/profile/backend registration options. 4. Inspect registered prompt ID/version selections, then both selected roles. Reject a selected role whose effective model or endpoint is empty or whitespace-only. Retain backend registration, normalized endpoint equality, nonblank effective `APIKeyEnv` rejection, and required-credential checks. Preserve literal IDs; do not trim/re-key identities or require all profiles to be complete. Populate the same role inspection map for both clients. 5. Migrate the registry test engine to `FilesystemInputs` and a programmatic `ProfileSource` fixture in its own tier, retaining its schema filesystem. A complete endpoint/model fixture without an application backend is valid for this direct library test; Audita's selected-role guard belongs in its runtime tests. Keep the embedded prompt preparation assertions scoped to embedded prompts. 6. Remove the old `profileSourceFS` wrapper once unused. Source accounting is completed in Stage 5. Preserve the adapter boundary; change other production callers only to resolve actual API incompatibilities. Search for remaining uses of removed source options and old `pk.Profile`/`pk.Backend` values. Run `go mod tidy` after migrating construction callers and review its diff. **Verification and completion:** Run `go test ./internal/prompts` and the existing offline profile assembly, unsafe-selection, and absolute-directory tests in `internal/framework/llm`. Run `git diff --check` and review the module diff. The obsolete file-reload assertion is intentionally replaced in Stage 6; do not restore reload behavior to make that assertion pass. Commit the runtime API migration. **Completion marker:** Stage 3 complete. Runtime construction now uses the released PromptKit source API with the selected application mapping; module selections match PromptKit v0.12.0 and both `/v3` catalogs at `v3.20260930.0`. `go mod tidy`, prompt registry tests, offline profile assembly, unsafe-selection, absolute-directory tests, and `git diff --check` passed. Captured source accounting remains in Stage 5. ## Stage 4 — Preserve Startup Failure Classification and Validate Assembly **Primary files:** `internal/framework/llm/runtime.go`, `internal/framework/llm/runtime_inspection_test.go`, and configuration-command tests in `internal/cli`. Update `internal/cli/run.go` only where the changed startup path needs existing exit behavior preserved. 1. Treat embedded discovery failures as `AssetError`; treat operator-directory discovery failures as configuration input errors. Preserve wrapped causes for `errors.Is`/`errors.As` and retain configured-secret redaction at CLI boundaries. Caller cancellation remains a runtime exit, not an operator mistake, and should not trigger further diagnostic loading. 2. PromptKit wraps both definition-loading and template/content failures in `ErrInvalidConfig`; some materialization errors have no public source/path type. Do not classify by parsing error strings or by that sentinel alone. On final engine-construction failure, perform an embedded-only diagnostic construction with the same embedded prompt/schema sources and library defaults, excluding operator inputs and application backend mappings. If that also fails, surface an `AssetError` with the asset cause; otherwise return the original final-construction error as an operator/configuration error. The diagnostic engine does no provider work and is never retained for execution. Keep a small unexported assembly seam accepting an embedded filesystem so tests can exercise asset failures without modifying shipped files or creating a global test hook. 3. Do not run this diagnostic construction as a successful-path preflight. A valid final snapshot remains accepted even if an operator contribution repairs an otherwise invalid lower-tier prompt. Verify that property with the same small assembly test seam. This avoids strengthening upstream final-value validation into mandatory validation of displaced definitions. 4. Cover incomplete selected profiles using omitted, empty, and null model contributions and a cleared selected endpoint. Exercise proposal and validation selection, including omission-derived validation selection, with a rejecting HTTP transport. Confirm valid unselected partial profiles are accepted; malformed unselected definitions, undefined backend references, and conflicting directory contributions still fail under native rules. 5. Add focused boundary coverage that invalid operator YAML/template/resource input produces configuration exit `2`, and test the asset classification directly at the runtime seam. Reuse existing CLI handling of `AssetError` for exit `1`; no damaged-binary subprocess fixture is needed. Cover the shared `NewRuntime` validation route and preserve cancellation exit `1` in configuration commands if the new error path would otherwise classify it as `2`. Avoid exact complete diagnostic wording assertions. **Verification and completion:** Run targeted startup/inspection tests and `go test ./internal/cli`; check whitespace and commit. Preserve the original failure cause where available rather than flattening it to a generic error. **Completion marker:** Stage 4 complete. Embedded discovery and construction failures are distinguished from operator inputs through an embedded-only diagnostic construction; cancellation skips that diagnostic. Selected-profile completeness and native directory validation are covered, and both config commands preserve exit 1 for cancellation/assets and exit 2 for invalid operator YAML, templates, and resources. Targeted runtime tests, `go test ./internal/cli`, and `git diff --check` passed. ## Stage 5 — Protect Consumed Configuration and Message Files **Primary files:** `internal/framework/llm/runtime.go` or a focused source-path helper in that package, `internal/cli/process.go`, runtime source-accounting tests, and `cmd/audita/main_integration_test.go`. 1. Rename the internal `Runtime.ProfilePaths` field to `SourcePaths` and update its process caller. It now covers consumed host YAML and message resources, rather than profiles alone. Populate it from the successfully captured final engine; do not expose source metadata as a new public output. 2. Call `InspectConfiguration`. Index `Sources()` by source ID, and collect paths with `Kind == ck.SourceKindFile`; embedded filesystem and synthetic sources are not host paths. All loaded host YAML counts, including unused definitions and files whose contributions were later overlaid. Deduplicate paths and sort for a stable internal projection. 3. For message resources, enumerate `Metadata().HistoricalPaths()` and retain effective, nonnull paths shaped as `/prompts///messages//content_file`. Use `Lookup` and the effective field's origin, not an inherited destination's guessed source. PromptKit successfully captures these fields only with a unique usable source context. Obtain the effective scalar from `Explain(path).Effective` and decode that scalar YAML into a string with the existing YAML dependency. This decodes captured inspection data; it is not a second configuration loader. When the contributing source is a host file, join the untrimmed resource name against that source file's directory and add it to the ledger. Ignore displaced references and non-host resources. Do not reread operator YAML, infer IDs from filenames, or reimplement resource-root validation. 4. Pass `SourcePaths` through existing `diagnostics.PrepareOutput` protection. Leave canonicalization, symlink/hardlink checks, permitted in-place transcript handling, and output initialization with their current owner. Do not protect every unrelated file in the selected directory or add filesystem mutation guarantees beyond the existing collision contract. 5. Extend `TestSubprocessProfileSources` and a focused runtime case to cover an arbitrarily named YAML contribution, a consumed source-relative message file, and conflicting transcript/report destinations. Use a non-YAML message filename, such as `instruction.md`, so directory discovery does not mistake plain prompt text for a configuration document. Include an inherited message reference from a different directory and a prompt ID/version with a JSON Pointer escape character so source provenance and literal keys determine the path. Check rejection before provider dispatch and unchanged input bytes. Preserve acceptance of an unused alternate output filename; do not turn the whole directory into a forbidden output location. **Verification and completion:** Run focused source-ledger tests and subprocess collision cases, plus `git diff --check`, then commit. Check that resource accounting uses the frozen snapshot and never changes the engine's source or resource-resolution behavior to facilitate tracking. **Completion marker:** Stage 5 complete. `Runtime.SourcePaths` now projects host YAML and effective source-relative message files from PromptKit's captured configuration inspection, using field provenance for inherited references. Process output protection consumes that ledger. Focused source-accounting and subprocess collision tests passed, including unchanged input bytes, no provider dispatch, JSON Pointer-escaped keys, and acceptance of an unused alternate output; `git diff --check` passed. ## Stage 6 — Verify Operator Prompt Overrides and Captured Execution **Primary files:** `internal/framework/llm/adapter_test.go` and focused runtime tests. Change `adapter.go` only for an actual integration defect. 1. Add a native keyed operator contribution overriding messages for an active prompt/version. Use the real runtime and controlled HTTP responses to prove the operator text reaches both the prepared snapshot and dispatched request. One case deliberately omits shared-variable references and still succeeds; do not require Audita to inject their text. A reference-bearing case renders the adapter-supplied value and retains existing protection against caller variables replacing the reserved shared variables. 2. Override the prompt's definition-level output contract with another valid upstream contract. Prove that Audita's per-call JSON schema and configured repair budget still govern execution: a structurally invalid response is repaired or exhausted as the controlled budget dictates. Domain validators remain downstream. Reuse existing validator/proposal integration coverage for their rules rather than weakening them to fit an operator prompt. 3. Replace the reload portion of `TestPreparedAdapterRejectsTargetDriftAndPreparationErrors`. After successful construction, change a profile or message file and verify the existing runtime still uses its captured settings/text. Construct a new runtime to observe a valid edit or reject a newly mismatched endpoint. Keep the missing prompt preparation failure case. 4. Retain a focused test of the prepared-target check independently of reload: deliberately change the test runtime's application backend endpoint after construction and verify the inconsistency is blocked before dispatch. This tests the existing guard, not a supported live mutation/reload feature. Continue executing the same prepared handle whose details were inspected; do not add another preparation or an application-side retry loop. **Verification and completion:** Run the prompt override, snapshot, and prepared-adapter tests. Compare semantic messages and selected targets, not old hash values or exact YAML formatting. Check whitespace and commit. **Completion marker:** Stage 6 complete. Native operator messages reach both the prepared snapshot and provider request, with and without shared-variable references. The adapter's per-call schema and repair budget remain effective under a valid operator output-contract override. Existing runtimes retain captured prompt/profile values after source edits, and a new runtime observes valid edits; the target guard and preparation failure remain covered. The `internal/framework/llm` tests and `git diff --check` passed. ## Stage 7 — Verify Native Profiles, Backend Authority, and Resilience **Primary files:** Runtime inspection and adapter tests, `internal/framework/llm/adapter_capacity_test.go`, and existing framework/CLI integration tests where their established behavior is affected. 1. Add a compact native profile inheritance fixture with literal keyed IDs unrelated to filenames, multiple definitions in one file, a partial parent, and a complete selected child. Verify inherited controls survive a child model change and child overrides win. Reuse the metadata-facing literal-key coverage from Stage 5 rather than repeating it in profile tests. 2. Use controlled HTTP request bodies to distinguish explicit zero temperature from omission and inherited-control suppression by null. Check a representative recursively overlaid provider parameter and null clearing; do not promise that all providers accept every valid configured zero. Reuse existing deadline/cancellation coverage for unchanged outer deadlines; explicit zero profile timeout must not disable the operation context. 3. Verify an operator backend contribution can add supported provider fields, while a conflicting endpoint/concurrency/queue/environment contribution cannot displace the final application fields. Preserve an explicit profile environment lookup as a selected-role error rather than hiding it with an adapter override. Include an application backend using a catalog ID to show it is allowed and its catalog credential lookup is suppressed. Use synthetic environment values and local HTTP fixtures, not provider catalog endpoints. 4. Reuse `TestRolesShareBackendCapacityAndReleaseAfterCancellation` and `TestDistinctBackendsHaveIndependentCapacity`; verify the final mapped limits, including zero queue capacity, still coordinate both roles and remain backend-local. Strengthen a fixture with conflicting lower-tier capacity only where needed to prove the new mapping wins. Keep existing synchronization; do not infer admission with sleeps or add another limiter. 5. Preserve offline selected-profile inspection and value-free application explanations. Check configured secrets, endpoint strings, arbitrary provider fields, and prompt text remain outside the current safe profile summary. Do not replace it with a full upstream dump. Its numeric projection is not proof that an omitted provider setting is sent; wire presence belongs to the HTTP coverage above. 6. Run the existing transient retry, structural repair, attempt-count, observation, partial-validation, and all-model-failure subprocess cases after fixture migration. Preserve their error/recovery/debug classifications, cancellation, and continued output. Fix proven integration regressions; do not rewrite domain outcomes or reduce budgets to obtain a passing suite. **Verification and completion:** Run `go test ./internal/framework/llm ./internal/framework/proposal_generation ./internal/framework/validators ./internal/framework/runner ./internal/cli ./cmd/audita` and `git diff --check`. Review whether each new test addresses a distinct changed boundary. Commit the native-profile and runtime verification unit. **Completion marker:** Stage 7 complete. Native profile inheritance, control presence, provider-map overlays, application backend authority, selected credential rejection, catalog-ID handling, shared backend capacity, and safe inspection behavior are covered. The six targeted packages passed, along with focused wire, timeout, capacity, credential, and safe-view tests; `git diff --check` passed. ## Stage 8 — Document the Migration and Update Attribution **Primary files:** `docs/config.md`, `docs/internal/llm-runtime.md`, `docs/internal/prompts.md`, `docs/integrations/openai-compatible-llm.md`, `docs/operations.md`, `docs/internal/cli-config.md`, `README.md`, and `docs/oss/attribution.md`. 1. Update the configuration contract for unified `profiles_dir` content, exact keyed identities, directory composition, agreed tier precedence, profile inheritance/presence, selected-role completeness, eager validation of all final definitions, selected-root failures, and construction-time capture. Replace the obsolete statement that PromptKit profiles do not gain ConfigKit inheritance. Retain application overlays, defaults, and credential ownership. 2. Include concise migration instructions in the profile section: wrap old profile fields beneath `profiles/`, remove inner `id`, change `base_profile` to `extends`, review explicit values/nulls, and select roots whose final definitions have valid backend references. Show a small keyed inheritance/override snippet and link complete maintained examples. Explain explicit zero temperature versus omitted or null controls and link upstream for the full field table. State that this ships as an Audita major migration; do not invent an exact release version or automatic file conversion. 3. Document intentional prompt overrides and optional shared-variable references. Supplying shared variables does not inject omitted text, while per-call schemas and domain validators remain enforced. Internal prompt documentation distinguishes shipped asset instructions from operator-effective messages; no prompt-quality rewrite or new global prompt-policy requirement is added. 4. Describe layered runtime assembly, source accounting, snapshot use, and startup classification in their internal owner. Update the pinned PromptKit consumer link in the LLM integration contract. Expand operations' loaded source description to include consumed operator message files; keep physical output/collision rules with operations and diagnostics. 5. Repair example navigation for separate local/service roots, especially the README's local-profile link. Update validation recipes to use the maintained config files' explicit roots and keep the service testing overlay workflow. Review other affected links without rewriting historical release notes. 6. Update the PromptKit and both catalog attribution entries to selected versions and exact commit-pinned source/notice URLs. Resolve catalog tag commits from the selected module origins or authoritative upstream refs, not annotated tag object IDs. Check the releases' COPYRIGHT/LICENSE files and retain the applicable unchanged local LGPL/GPL and MIT texts. Keep the existing House Format; no new license selection, policy rewrite, or attribution inventory is needed. Review `go.mod`/`go.sum` against those entries. **Verification and completion:** Check affected local links/anchors, format examples against the implemented loader, verify source revisions/notices, and run `git diff --check`. Commit the documentation and attribution unit. **Completion marker:** Stage 8 complete. Configuration, runtime, prompt, integration, operations, contributor, and README guidance now reflects native PromptKit layering, migration, presence, snapshot, and separate example-root behavior. Attribution matches PromptKit v0.12.0 and both v3 catalog module origins and notices. Local links/anchors and `git diff --check` passed. ## Stage 9 — Validate the Integrated End State and Close the Plan **Primary files:** This plan and the feature roadmap; correct an implementation file only if the final checks reveal an actual gap. 1. Verify the full roadmap acceptance criteria against the landed code and the distinct tests from these stages. Review for unintended requirements: profile-only filtering, mandatory shared text in operator messages, filename-derived IDs, complete unselected profiles, catalog ID bans, successful-path asset preflights, compatibility readers, and new output guarantees are not part of the accepted target. 2. Run `go build -o ./bin/audita ./cmd/audita` and `go test ./...`. Keep the generated binary out of commits. Reuse successful checks on unchanged content; rerun checks affected by any corrective code changes. 3. Validate the maintained examples offline using the built binary: ```sh ./bin/audita config validate --config examples/minimal-config.yml ./bin/audita config validate --config examples/configkit-inheritance.yml AUDITA_SERVICE_KEY=synthetic-example ./bin/audita config validate --config examples/production-config.yml AUDITA_SERVICE_KEY=synthetic-example ./bin/audita config validate --config examples/production-config.yml --overlay testing ./bin/audita config print-effective --config examples/minimal-config.yml --view profiles ./bin/audita config print-effective --config examples/configkit-inheritance.yml --view explain ``` Confirm local/service roots and testing selections work without provider dispatch. Check safe views exclude resolved secrets and preserve the established explanation fields. Do not call a model to validate examples. 4. Check the selected dependency graph, attribution, affected links, and final diff. Run `git diff --check`. Confirm only the released modules are used and no obsolete `/v2` catalog or removed construction API remains in active code. Historical release documents and historical roadmap links may retain old versions as accurate records. 5. Mark this plan and the feature roadmap complete only after the full target passes. Record the tested implementation revision and checks accurately; distinguish a subsequent documentation-only completion commit. Commit the completion documentation and report remaining work, if any. Do not select a release number, publish, tag, push, poll CI, or add permanent release gates. **Completion marker:** Stage 9 complete. The tested implementation revision is `5525fe8`; the preceding documentation migration commit is `9bcf183`, and this roadmap closure is documentation-only. At `9bcf183`, the application built, `go test ./...` passed, all six maintained example commands passed offline, `go mod verify` passed, the selected module graph contained PromptKit v0.12.0 and both `/v3` catalogs at `v3.20260930.0` with no `/v2` catalogs, and `git diff --check` passed. The active Go/module scan found no removed PromptKit construction options. **End state:** Native PromptKit configuration and catalogs are adopted, operator overrides and captured resources work through the real runtime, application backend/domain ownership and resilience remain effective, and maintained examples and migration documentation match the implementation. No implementation-blocking decisions remain; exact major-release numbering and publication timing remain outside this implementation unit.