Files
promptkit/docs/roadmap/implementation.md

37 KiB

ConfigKit Adoption Implementation Plan

Status: ready for staged implementation under the agreed configuration boundary. This is a planning document; writing it does not implement the feature or authorize publishing dependencies.

Authority And Working Method

The ConfigKit feature roadmap owns the intended end state and approved policy. Its intentional-breaking-change direction is authoritative: preserve substantive prompting capabilities, not the old loader, signatures, source wrappers, incidental error ordering, or configuration syntax. The configuration-boundary ADR records the ownership decision: PromptKit interprets and validates the final effective configuration supplied by ConfigKit. Presence/null information and effective resource context are part of that handoff. Source history serves explicit operator inspection, not validation or catalog enforcement. This applies to tests as well as production code.

Implement the stages below in order, one stage per coding-agent prompt. Each stage includes its tests and affected current-state documentation. Read development and the applicable policies before starting; in particular, follow agents, architecture, testing, documentation, and OSS. Catalog work also follows each catalog repository's own instructions and release procedure. Do not turn this plan's internal organization into new public promises.

Begin each stage by inspecting the worktree and earlier stages. Commit completed units under the agent policy. Keep stages buildable; temporary private wiring needed to connect successive stages must be removed by Stage 11. Do not ship a legacy mode, dual loader, or old-format conversion layer. Do not add prototype applications or a generic configuration framework of our own.

Planning baselines:

  • PromptKit runtime v0.11.2, commit 12d6d80024e80c552d122a076c22429bf6f2f6c2; approved roadmap at 521291d.
  • ConfigKit v0.5.0, commit dc09959cca4e105f49ec316c6d4ba585bd2340bd, module gitea.maximumdirect.net/eric/ConfigKit.
  • Both catalog dependencies currently select /v2 at v2.20260926.0.

Use ConfigKit v0.5.0 for this work. Do not silently upgrade to a different contract. The catalog asset migration needs coordinated releases, not a committed workspace or local replacement. Changing the backend asset contract is broader than the catalog profile-data compatibility exception: migrate the catalogs to /v3 with v3.YYYYMMDD.N tags, preserving their date/revision convention and updating their own release documentation accordingly. Select exact dates and unused revisions at publication; record versions and full commits consumed. Publishing any repository requires separate authority.

Implementation Decisions

Construction Surface

Keep NewEngine(Config, ...Option) and the execution/injection surface where it still serves its substantive purpose. Replace profile/prompt source options with these fields and helpers; this is an intentional API break:

type ConfigurationSources struct {
    Underlays []configkit.Underlay
    Main      *configkit.Input
}

// Add Sources; remove PromptDir and ProfileDir.
// Retain SchemaDir, Timeout, HTTPClient, and TransientRetries.
type Config struct { /* existing non-definition settings; Sources ConfigurationSources */ }

func DirectoryInputs(directory string) ([]configkit.Input, error)
func FilesystemInputs(label string, filesystem fs.FS, root string) ([]configkit.Input, error)

The pointer distinguishes omitted main input without inspecting ConfigKit's opaque Source. Nil main becomes configkit.NoSource(); a supplied invalid Input is not silently ignored. Prepend two private underlays: external catalogs, then PromptKit-owned definitions. Append caller underlays in their supplied order; main is last and keeps its ConfigKit meaning. Imports follow each Input's flag. Do not expose named overlays, CLI overrides, or VersionRule through another PromptKit abstraction in this feature.

Show the usual application categories as caller underlays ordered fallback, operator, programmatic, with main omitted. For a single highest-priority document, main is also useful. These are explicit selections, not directory-name heuristics or a second automatic precedence algorithm. Each directory helper returns inputs for one strict-composition group, recursively finding .yaml and .yml files; sorted discovery makes diagnostics reproducible, not one file higher priority. An explicitly selected missing/unreadable root fails; an empty directory supplies no contributions. Helpers set imports false; callers may enable them explicitly. Use one ConfigKit filesystem namespace per helper invocation and root resource contexts at the supplied directory. Single files use ConfigKit directly.

Remove WithPromptFS, WithPromptFile, WithProfileFS, WithProfileFile, WithFallbackProfileFS, WithProfiles, and WithBackend at public cutover. Retain schema source options and runtime collaborator injection. Backend configuration moves into ConfigKit inputs as specified below. Do not require any prompts to exist merely to construct an engine for profile inspection.

Programmatic configuration uses labeled configkit.Mapping inputs. Replace the old zero-sentinel Profile/OpenAICompatibleProfileConfig pair with one small ProfileConfig convenience and a source builder:

type ProfileConfig struct {
    Extends, Backend, Endpoint, Model *string
    Temperature, TopP *float64
    MaxTokens, TimeoutSeconds *int
    ServiceTier, ReasoningEffort, APIKeyEnv *string
    APIKeyRequired *bool
    ExtraParams map[string]any
}
func ProfileSource(label string, profiles map[string]ProfileConfig) configkit.Source

Nil convenience fields mean omitted; nonnil pointers preserve zero/false/empty. Nil ExtraParams omits the map; a nonnil empty map supplies an empty mapping, not a clear operation. Use raw Mapping for explicit null, prompt definitions, or richer configuration. Do not introduce a public generic optional-value type just for this helper. Convert fields explicitly to ConfigKit-supported built-in values, then call Mapping for snapshot ownership and load-time errors. Do not marshal through YAML or infer absence from a value. Helpers encode values; domain validation occurs on the final configuration at handoff.

Replace the registration-only Backend value with a presence-aware convenience:

type BackendConfig struct {
    Endpoint, APIKeyEnv *string
    ConcurrencyLimit, QueueCapacity *int
    ExtraParams map[string]any
}
func BackendSource(label string, backends map[string]BackendConfig) configkit.Source
func LocalBackend(endpoint string, concurrencyLimit int) BackendConfig

Use the same omission/pointer/map conventions as ProfileSource. LocalBackend supplies endpoint and concurrency pointers and leaves the remaining fields omitted; callers choose the ID as the map key. Neither helper validates settings before ConfigKit processes them. For example, place BackendSource with map[string]BackendConfig{"local": LocalBackend(endpoint, 4)} in an application underlay. Raw Mapping supports explicit null and combined backend/profile/prompt documents. Remove the old Backend registration value and its reservation rules; retain useful built-in ID constants. All backend contributions follow the same strict-composition and overlay rules as other configuration.

Typed Configuration And Execution Values

Add internal/configuration as the cohesive ConfigKit adapter. Its private document DTO has backends: map[string]backendConfig, profiles: map[string]profileConfig, and prompts: map[string]map[string]promptConfig. Collection entries are mappings, not nullable definition pointers. No duplicate identity fields; ConfigKit consumes extends, so no DTO field or second resolver handles it. Use configkit.Keys, Key, and Index for semantic paths, never split IDs on dots.

Profile DTO fields match ProfileConfig's YAML spellings (backend, reasoning_effort, etc.). Nullable pointers plus ConfigKit presence metadata distinguish absent, value, and explicit null. Store that distinction in small private execution-owned fields or presence bits, not retained metadata queries. Runtime/domain packages must not import ConfigKit. Do not duplicate its tree, merge engine, inheritance graph, diagnostics, or presence framework.

Backend DTO fields match BackendConfig using endpoint, api_key_env, concurrency_limit, queue_capacity, and extra_params. Validate the final endpoint as required, absolute HTTP(S) with the existing URL rules. An absent or null API-key environment name means no lookup; a supplied name follows existing normalization and naming rules. Absent/null concurrency means zero (unlimited); supplied values must be nonnegative. Absent/null queue capacity selects the existing default of 1024 for positive concurrency and no queue for unlimited concurrency. Explicit queue capacity, including zero, requires positive concurrency and must satisfy existing nonnegative/overflow checks. Null provider maps mean no configured extra parameters; entries may contain JSON null. Required endpoint failures, unknown fields, and domain errors apply to final definitions, including unused ones. Registry construction consumes these final normalized values; it does not replay registration or source-reservation checks.

Use ConfigKit's Resolve/Validate callbacks only on its effective post-layering, post-inheritance typed values. These public lifecycle hooks implement the domain handoff and record normalization; they are not hooks for inspecting earlier contributions. Final presence lookup and resource-context lookup are sufficient for interpretation. History/Explain/HistoricalPaths are operator inspection facilities, not inputs to construction-time policy checks.

Use the existing prompt fields under each keyed version, without id/version. Use pointers for content, content_file, and optional clearable strings; preserve existing input, cache-control, output-contract, and role rules. messages must be nonempty; each message has exactly one nonnull content source. An explicitly supplied empty inline string is a valid template. Null content removes that selection; null content_file removes its reference. Output remains a required mapping with valid format and validation mode. Optional description, session template, default profile, cache control, inputs, and schema path can be cleared where their domain permits absence. Null required role/format/mode or a null whole definition is invalid. Scalar required and repair_attempts retain their false/zero defaults and are not nullable. Null inputs means no declarations. Unknown fields are ConfigKit errors, including old id, version, and base_profile. Prompt versions must be string mapping keys.

Literal definition keys remain exact; require nonblank identity but do not normalize/rekey maps after ConfigKit has resolved relationships. Update selection to use exact nonblank IDs/versions rather than silently trimming them into a different identity. Existing value normalization (for example role lowercase or endpoint trimming) is recorded through ConfigKit's resolution callbacks. Field references to definition IDs remain exact as well.

Profile field rules after configuration overlay/inheritance:

Fields Absent Explicit value Explicit null
backend No selected backend Exact registered ID; blank means none No backend
endpoint Selected backend endpoint, if any Normalize/validate nonblank URL; empty clears Clear, do not recover backend endpoint
model Unspecified Nonblank supplied model; empty clears Unspecified
temperature, top_p, max_tokens Unspecified Validate existing bounds; zero is explicit and sent Suppress outbound control
reasoning_effort, service_tier Unspecified Existing normalization; blank suppresses Suppress outbound control
timeout_seconds Framework 600-second baseline Nonnegative; zero disables generation deadline Reset to framework baseline, not lower profile timeout
api_key_env Selected backend's optional lookup name Trimmed value; blank disables lookup Disable lookup, do not recover backend name
api_key_required False Explicit boolean, including false overriding true False
extra_params Backend defaults ConfigKit-composed profile map, recursively overlaid on backend map Suppress entire configured provider map

Backend registry defaults are applied once during snapshot construction, after effective profile inheritance. Keep them out of the inheritance input: a parent's derived endpoint/key/defaults must not follow a child that changes backend. Provider map null entries are literal JSON null; empty mappings retain children. For backend-to-profile provider-map overlay, use a narrow JSON-value merge helper with the same recursive-map/value-replacement semantics; it is not a configuration loader. Both backend and profile configuration maps have already passed through ConfigKit's reserved-key semantics; only request-level maps bypass that lifecycle.

Record any defaults/normalizations written into the typed configuration via ConfigKit Resolve, with dependencies on relevant configuration paths. Do not project runtime collaborators or credentials into the configuration tree just to report them. Inspection includes effective backend configuration. It describes resolved configuration, while InspectProfile and preparation describe backend-completed execution settings. Make this boundary explicit rather than inventing synthetic provenance for registry defaults.

Retain APIKeyRequired's direct-key workflow: true suppresses a backend-derived environment source. An explicitly configured profile environment source, or a request environment override, remains usable; false restores ordinary optional credential semantics. No credential values belong in the DTO, inspection, or construction-time environment resolution. Raw profile api_key remains invalid.

Validate all effective supplied values and referenced backend IDs at construction. Do not require a complete model/endpoint there or reject unused partial profiles. Do not require a prompt default_profile to be runnable before a request can override it. Final target completeness is checked after runtime overrides. InspectProfile can report a partial target without credential or provider access. Keep request override contracts otherwise unchanged, including complete nonempty runtime ExtraParams replacement and reasoning clearing. A runtime literal extra_params["extends"] remains ordinary provider data. Do not expand this work into a redesign of every request override.

Snapshot And Inspection Design

The loader returns indexed, execution-owned definitions plus a private retained ConfigKit result. An adapter may implement the runner's narrow lookup interfaces over maps during migration; no repository chain, fallback-on-error, or per-call configuration load survives. Preserve defensive ownership across injected clients and public results. Cache prompt definition hashes at construction; hash effective captured content, not a stale resource path. Hash bytes need not match the old configuration format. Preserve rendered-prompt hashing semantics.

Resolve each effective content_file using its exact field origin and ConfigKit SourceContext. Join its relative name to BaseDir inside the returned rooted FS; reject absolute/outside-root paths and close every opened handle. Preserve path text, including meaningful whitespace, after separately checking nonblankness. Do not choose the child's source for an inherited reference. If there is no unique contributing source with context, fail with an actionable path/source error; the caller can supply an explicit Input filesystem context or override the field. Retain no resource capability for the purpose of public diagnostics.

Capture message text and parse message/session template syntax at construction with the same function names/options used for runtime rendering. Do not invoke input helpers or require Vars/artifacts while parsing. Reuse compiled templates where practical, binding request-specific input functions on safe per-call clones; never mutate a shared template function closure with request state. Runtime missing-variable/input failures remain runtime errors.

Expose a concrete read-only facade value:

func (e *Engine) InspectConfiguration() (ConfigurationInspection, error)
func (v ConfigurationInspection) Metadata() configkit.Metadata
func (v ConfigurationInspection) Sources() []configkit.SourceInfo
func (v ConfigurationInspection) Diagnostics() []configkit.Diagnostic
func (v ConfigurationInspection) Explain(path configkit.Path) (configkit.Explanation, bool)
func (v ConfigurationInspection) WriteEffective(w io.Writer) error
func (v ConfigurationInspection) WriteExplanation(w io.Writer, path configkit.Path) error

Store an unexported narrow implementation reference; do not expose Result.Config, ConfigKit SourceContext, mutable runtime values, or internal types. Delegate queries and redaction to the retained result. Nil Engine returns ErrInvalidConfig; the zero inspection view has empty query results and writer operations return ErrInvalidConfig. Writer errors remain inspectable. Mark credential-shaped dynamic keys sensitive using Definition.Secret; the existing secret-key vocabulary can serve as a redaction predicate, not a source-rejection rule. Do not redact api_key_env names as credential values. This is not a promise that arbitrary prompt/provider content is safe to disclose.

Keep the runner independent of this view. Inspection calls perform no discovery, resource reads, environment credential lookup, or provider operations. Schemas, artifacts, preparation ownership, generation admission, retry/repair, observations, and cancellation remain at their established runtime boundaries.

Stage 1 — Add The Dependency And Typed Loading Core

Completed: 2026-09-30.

Scope: module metadata, internal/configuration DTOs, real ConfigKit loading, and its focused tests. Leave engine assembly on the old path for this stage.

  1. Add ConfigKit v0.5.0; update go.sum and factual OSS notices for it and its selected transitive dependencies. Preserve project licenses and the Go floor.
  2. Add keyed backend/profile/prompt DTOs and a private load entry point accepting ConfigKit Inputs and underlays. Call LoadLayered once, with no VersionRule or secret resolution bindings for API credentials. Use callback-scoped Resolve/Validate correctly.
  3. Implement effective presence extraction and the field rules above. Validate final domain values through existing helpers, resolving backend references against the final backend map; profiles have no final target requirement yet. Record normalization/default mutations, not arbitrary DTO bookkeeping fields.
  4. Preserve *configkit.LoadError through wrapping. Domain callback messages identify paths/problems without interpolating raw values or credentials.
  5. Add representative real-loader tests: keyed literal IDs, strict group conflict, recursive cross-tier overlay, a shared base with explicit zero/null/false, an unused invalid effective definition, and preservation of a ConfigKit load error. Cover an invalid lower-layer domain value replaced by a valid final value: construction succeeds. Do not reproduce ConfigKit's parser/inheritance matrix or add preflight/source-policy tests.

Exit: focused tests and go test ./... pass; old engine behavior is not presented as migrated. Internal inventory documents only the loader now actually present.

Stage 2 — Add Source Discovery And Prompt Resource Capture

Completed: 2026-09-30.

Scope: source selection helpers and construction-time prompt materialization.

  1. Implement private directory/FS discovery behind the chosen helper signatures; wrap discovered paths as ConfigKit sources, retaining explicit root context. Reuse useful filecatalog path handling without carrying profile metadata scans.
  2. Materialize effective prompt message text using field origins and passive contexts. Move reusable prompt/input/cache/output validation into the loader or shared domain owner; do not copy entire legacy parsers.
  3. Build immutable prompt indexes by exact ID/version and an ambiguity indicator for omitted versions. Capture declared-input inspection data and prompt hashes.
  4. Validate static template syntax using the renderer's grammar/function setup. Refactor that setup into one private owner if needed; do not render at load.
  5. Test native and embedded sources, imported/inherited relative content from a different directory, explicit mapping context, contextless failure, handle closure, malformed static syntax, and resource mutation after capture. Use minimal fixtures, sharing scenarios where the same adapter is exercised.

Exit: loader creates usable frozen prompt definitions without request data. go test ./internal/configuration ./internal/prompt ./internal/promptdef passes; existing execution tests still work through the old assembly until cutover.

Stage 3 — Make Execution Settings Presence-Aware

Completed: 2026-09-30.

Scope: domain settings, target resolution, wire-presence propagation, profile inspection. No new source discovery in execution packages.

  1. Build the immutable backend registry from the final loaded backend map. Add execution-owned presence/suppression state and construct indexed profiles from loader output plus that registry. Apply registry-derived values after inheritance, using the field table above.
  2. Replace scalar-zero/blank merge assumptions in target resolution. Configuration explicit zero reaches injected clients and the built-in request body; null does not resurrect a provider setting. Extend existing TargetPresence plumbing through preparation/results as necessary rather than creating a parallel path.
  3. Preserve request-level override precedence, API-key availability behavior, endpoint-only profiles, backend identity/capacity, and partial-profile runtime completion. Move final completeness checks after overrides. InspectProfile returns partial settings without treating missing model/endpoint as load errors.
  4. Test explicit numeric zero versus omission, map overlay and null, backend change without derived defaults leaking from parent, timeout null/zero, credential-source suppression, and completion through request overrides. Include one built-in-client wire test, not just an injected-client assertion.

Exit: focused domain/usecase/client tests pass. Any temporary adaptation for the old assembly is private, clearly limited to reaching Stage 7, and does not become a compatibility promise. Update affected target/presence GoDoc with this change.

Stage 4 — Migrate The OpenRouter Catalog Assets

Completed: 2026-09-30. Published OpenRouter catalog v3.20260930.0 from f17d208cb7ad1fb043cda2266cd3011d11b40aa0.

Scope: ../promptkit-backend-openrouter only. Catalog maintainers own source and publishing checks here; PromptKit consumes its configuration through ConfigKit.

  1. Read that repository's instructions; preserve unrelated work. Convert each profile asset to profiles: {literal-id: {settings...}}, preserving inventory and values, changing base_profile to extends, and removing embedded ID. Keep per-profile files and the exported FS/Root package; no dependency on PromptKit and no second legacy asset tree.
  2. Audit zero/empty values that previously meant unspecified. Remove those when omission was intended; retain intentional explicit values. Review any dynamic provider extends keys rather than silently changing outbound payloads.
  3. Replace catalog/backend.json with catalog/backend.yml containing a backends: {openrouter: {settings...}} mapping. Preserve endpoint, API-key environment name, concurrency, queue, and extra-parameter values; remove the duplicate id and old manifest schema_version. The file is an ordinary ConfigKit input, not a separately decoded manifest. Update embedded assets, module path and imports to /v3, tests, and catalog format/release documentation, with an incompatible-format migration note. Keep FS/Root as the minimal export surface. Catalog-local publishing checks stay in that repository. No provider probes.
  4. Validate under its procedure and commit. If publication is authorized, publish the next unused v3.YYYYMMDD.N; otherwise report the exact commit awaiting publication. The date/revision is selected then, not guessed in this plan.

Exit: one reviewed migrated catalog commit; existing immutable tags still serve old consumers. The new major module path identifies the changed asset contract; old consumers retain the published /v2 assets.

Stage 5 — Migrate The Rakestrawhome Catalog Assets

Completed: 2026-09-30. Published Rakestrawhome catalog v3.20260930.0 from 993443d88c451901f4c917fa00c204fd3b54d28d.

Scope: ../promptkit-backend-rakestrawhome only. Apply the same keyed-format, presence, notice, validation, and publication treatment as Stage 4 to its smaller inventory, including the /v3 transition and keyed backends.rakestrawhome definition in catalog/backend.yml. Preserve backend endpoint, credentials metadata, and capacity policy. Do not couple its date/revision to OpenRouter's release.

Exit: both compatible catalog versions are published and ordinarily resolvable before Stage 6 pins them. If permission or publication is unavailable, stop at this external dependency checkpoint; do not commit a local replace, guessed version, or legacy-to-new runtime converter to bypass it.

Stage 6 — Integrate Catalog Sources And Maintained Profiles

Completed: 2026-09-30.

Scope: internal/catalog, maintained definitions, catalog integration tests, dependency pins/notices. Keep this separate from public API migration.

  1. Pin the published compatible catalog versions and exact attribution commits. Update imports to /v3. Replace manifest decoding with ConfigKit file Inputs.
  2. Supply backend and profile assets as ConfigKit Inputs in the first underlay. Supply PromptKit-owned keyed Mapping definitions as the next group: standard extends the selected catalog's current maintained base; auto retains its current direct model/backend definition. Preserve both literal names.
  3. Retire source-layout allowlists, catalog preflight, source ownership/reserved prefix checks, connection-field prohibitions, and secret-key source rejection. The adapter selects known asset entry points and discovers configuration files; ConfigKit acquires their contents. Domain validation sees only the final assembled configuration. Consumers may overlay catalog backends, profiles, and their bases through the same configuration model.
  4. Test real imported assets offline with the new loader, maintained-name resolution, consumer override of a maintained base/backend, and rejection of an invalid final backend. Test a replaced lower-layer domain error succeeds. Do not independently validate catalog-only intermediate configurations, parse raw assets in PromptKit tests, or audit origins to establish ownership.

Exit: catalog and owned definitions participate in the new keyed configuration model without a legacy profile parser on that path. Catalog integration tests pass against released modules with GOWORK=off and no replacements.

Stage 7 — Cut Over Engine Assembly And Public Construction

Completed: 2026-09-30.

Scope: engine.go, configuration facade/helpers, internal/engine, facade adapters, and migration of their direct test setup.

  1. Introduce the Construction Surface exactly as specified above. Remove the superseded source/profile options and convenience types rather than keeping deprecated pass-through wrappers. Keep intentional runtime injection APIs.
  2. Load the combined backend/profile/prompt configuration, construct its runtime registry and indexed snapshot, then assemble renderer, validator, capacity manager, and runner. Return no Engine on construction failure. Translate construction errors to ErrInvalidConfig while preserving LoadError via errors.As. Resource errors include semantic path and safe source context.
  3. Connect indexed prompt/profile lookups to preparation and inspection. Missing selections keep meaningful not-found errors; prompt version ambiguity stays a selection error. Old parse/load error categories need not be manufactured for errors now detected at construction.
  4. Move root test fixtures/setup and maintained example construction to ConfigKit sources, keyed definitions, ProfileSource, and BackendSource so all consumers still compile. Update local-backend examples to choose their ID as a map key. Update expected timing only for the deliberate eager-validation change. Keep behavioral assertions for prompting, overrides, and errors.
  5. Add public tests for a minimal custom local backend and programmatic profile, plus embedded defaults/operator/programmatic tiers. No elaborate consumer setup should be needed merely to send one prompt.

Exit: the public Engine uses only the new loading path. Root/package tests pass; all package/example sources compile. Update GoDoc and consumer construction guidance in this stage so removed options are not presented as usable.

Stage 8 — Complete Frozen Rendering And Lifecycle Integration

Completed: 2026-09-30.

Scope: renderer/runtime consumption of the snapshot, ownership, and lifecycle regressions. Stage 2 already owns acquisition and static syntax validation.

  1. Use captured text and parsed templates without per-run configuration reads, parsing, or inheritance. Bind input helpers per invocation safely; keep missing request data errors and direct-session template bypass behavior.
  2. Verify preparation and execution still handle artifacts and schema compilation at invocation time, honor output overrides, freeze prepared resources, and keep prepared handles bound to their engine. Credentials remain at runtime.
  3. Test an old engine after configuration/resource edits and a newly constructed engine observing the edits. Test concurrent renders with different Vars/input helpers and no data leakage. Use an FS that rejects reads after construction to demonstrate no configuration/content-file reopening during ordinary runs; do not incorrectly prohibit request artifact/schema reads.
  4. Preserve appended-message ordering, structural repair, retries, admission, cancellation, observers, and result metadata through existing regression tests; add only distinct missing cross-boundary cases.

Exit: focused race tests pass for assembled rendering/preparation and lifecycle. No retained callbacks capture ConfigKit resolution contexts or request state.

Stage 9 — Expose Explicit Configuration Inspection

Completed: 2026-09-30.

Scope: the read-only facade and retained ConfigKit inspection adapter.

  1. Implement ConfigurationInspection and its specified methods without exposing Result.Config or filesystem capabilities. Retain a private narrow view of the ConfigKit result; no regeneration of origins from runtime values.
  2. Ensure effective/explanation reports use ConfigKit redaction, including the selected sensitivity predicate. Preserve safe value-free domain diagnostics.
  3. Test a targeted literal-key path with layered/inherited history, detached returned slices/records, writer failures, zero/nil behavior, and redacted secret shaped provider values. Demonstrate inspection still works after source removal and makes no filesystem/provider calls.
  4. Document construction inspection versus InspectProfile and prepared details. Consumers choose report disclosure; do not add CLI commands or automatic logs.

Exit: public inspection tests pass, including concurrent inspection/execution. The runner has no reference to the inspector or ConfigKit metadata types.

Stage 10 — Migrate Examples And Canonical Format Guidance

Completed: 2026-09-30.

Scope: maintained examples and user-facing documentation.

  1. Complete the preparation, execution, and observation example migration begun at public cutover. Preserve their distinct existing semantic assertions; extend the preparation example with a small explicit inspection query if useful.
  2. Update docs/formats.md to own the new keyed syntax, source-group semantics, inheritance/presence/null table, eager validation, snapshot lifetime, and resource-context rules. Link ConfigKit for generic grammar; do not copy its complete parser/inheritance contract.
  3. Update README and docs/consumers/pkg-promptkit.md with minimal local-backend, file/embedded source, programmatic Mapping/ProfileSource, explicit inspection, and engine-replacement workflows. Explain main versus ordered underlays and backend layering in place of registration-only restrictions.
  4. Add concise old-to-new migration guidance in the consumer guide: removed API options, exact IDs, base_profile to extends, zero/false/null, recursive maps, no clear via {}, reserved extends runtime escape, failure timing, and the fact that changing a model/backend does not clear unrelated explicit fields. Remove old automatic reload claims. Release notes later link to this owner.

Exit: all three offline examples run with their semantic checks; documentation links and snippets match the implemented API. No unreleased version is tagged or published, and no speculative release-note version is invented.

Stage 11 — Remove Superseded Machinery And Consolidate Tests

Completed: 2026-09-30.

Scope: dead loading/resolution code and its obsolete tests, module cleanup, and internal architectural documentation.

  1. Delete lazy prompt/profile metadata prepasses, filesystem repositories, fallback-on-error overlays, custom base-chain resolver/depth cap, zero-sentinel profile merging, and temporary stage adapters once no caller needs them. Remove the separate backend-manifest decoder, source-policy audits, and pre-handoff backend registration validation. Keep final-value domain checks. Retain narrow lookup interfaces only where they still simplify real consumers.
  2. Retain useful filecatalog/schema utilities and JSON-value ownership/validation. Remove direct yaml.v3 use and dependency if no remaining owner requires it; do not claim all YAML dependencies disappear when ConfigKit still uses YAML.
  3. Move meaningful regressions from deleted package tests to their new owning boundary. Retire tests about old internals, repeated parser coverage, source-policy enforcement, or superseded semantics. Do not replace lost runtime protection with loader-only tests. Keep private assembly checks separate from external facade tests.
  4. Update docs/internal/overview.md, docs/internal/sources.md, relevant renderer and engine documents, and the implemented-structure paragraphs in architecture policy. Describe the new package/dependency boundary without turning names or chosen adapters into permanent invariants. Update OSS notices with module tidy.

Exit: no legacy source path remains, no internal package imports the public root, runtime/domain packages do not import ConfigKit, and go test ./... passes with the reduced implementation/test inventory.

Stage 12 — Validate Scale And The Complete Consumer Workflow

Completed: 2026-09-30.

Scope: final integration evidence and high-confidence simplification, not another feature expansion or release gate.

  1. Add focused benchmarks for construction with many independent definitions, shared inherited bases, and several tiers; add an already-constructed selection benchmark. Report allocations and input/output shape; inherited materialized output/history may dominate. Do not impose timing thresholds or new caps.
  2. Inspect for repeated full-map copies, per-run provenance calls, rescans, repeated inheritance, and unnecessary double parsing. Fix demonstrated local inefficiencies with straightforward ownership/indexing; no global cache.
  3. Run the repository's existing complete local check script once on the final candidate, including race tests and offline examples. Investigate failures; do not weaken meaningful tests to get a green result. Stage intended new files before the script's tracked-file checks.
  4. Review the feature-roadmap capability list against actual public workflows: independent inspection, partial profile completion, optional credentials, source contexts, artifacts/schemas, prepared ownership, backend capacity, overrides, appended messages, repair/retries, observations, and hashes.
  5. Report completed stages, selected catalog versions, validation evidence, and remaining issues. Minor-release documentation/version selection and roadmap retirement belong to the separately authorized release preparation workflow.

Exit: the feature roadmap's end state is demonstrably implemented, with one configuration lifecycle, explicit operator inspection, no legacy loader, and no newly invented provider checks or human release gates.

The catalog-validation placement question is resolved by the configuration-boundary ADR. No design question remains open here. Catalog publication authority and ordinary module availability remain operational checkpoints for the catalog stages.