diff --git a/docs/roadmap/configkit.md b/docs/roadmap/configkit.md new file mode 100644 index 0000000..56bdf09 --- /dev/null +++ b/docs/roadmap/configkit.md @@ -0,0 +1,226 @@ +# ConfigKit Adoption + +## Status And Intent + +Accepted feature direction, drafted on 2026-09-26; not implemented. This +roadmap defines the target behavior and changes from the reviewed baseline. +A separate implementation plan will own sequencing and concrete implementation +steps. The existing `implementation.md` concerns the completed Promptkit upgrade +and is not an implementation plan for this work. + +The user is adopting ConfigKit across an application suite to standardize +configuration semantics. Scriptorium will make a clean cutover to ConfigKit's +native conventions, including intentional breaking changes. Preserving the +legacy loader's behavior is not a goal: there will be no parallel legacy loader, +compatibility mode, or recreation of the old merging rules. + +Alignment applies to application configuration, not to Promptkit-owned prompt, +profile, or schema definitions. Departures from ConfigKit conventions require an +application-specific reason or a genuine ownership boundary, not backward +compatibility alone. The [architecture policy](../policy/architecture.md) and +[ADR 0004](../adr/0004-definition-boundary.md) remain the scope boundaries. + +## Reviewed Baseline + +Scriptorium consumes Promptkit v0.11.0. Its `internal/config` package uses +yaml.v3 directly and manually applies defaults, file settings, and CLI overrides. +It has a parser-specific integer decoder, ignores empty string overrides, and +treats an empty configuration file as defaults-only input. It has no application +configuration imports, selected overlays, or provenance/inspection interface. +The [configuration reference](../config.md), [CLI reference](../cli.md), and +[source internals](../internal/sources.md) own the current behavior. + +The reviewed ConfigKit release is v0.4.0 at commit +`e6ced0d3d1194b58e0b3dc8970089471ba175258`. Adopt that published release as the +initial target, rather than a sibling checkout or unpublished replacement. +Its canonical references are: + +- [Configuration contract](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/e6ced0d3d1194b58e0b3dc8970089471ba175258/docs/config.md). +- [Consumer adoption guide](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/e6ced0d3d1194b58e0b3dc8970089471ba175258/docs/consumers/README.md). +- [Release notes](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/e6ced0d3d1194b58e0b3dc8970089471ba175258/docs/releases/v0.4.0.md). + +ConfigKit requires Go 1.25, within Scriptorium's existing toolchain requirement. +It selects `go.yaml.in/yaml/v4 v4.0.0-rc.6`. Removing Scriptorium's direct parser +usage does not remove yaml.v3 from the dependency graph: Promptkit still uses it. +The initial review passed ConfigKit's default test suite and Scriptorium's +configuration and CLI tests; that is baseline evidence, not migration validation. + +## Target Ownership And Loading Model + +| Owner | Responsibility | +| --- | --- | +| ConfigKit | Application YAML policy, source acquisition, composition, overlays, typed decoding, explicit override application, provenance, and redacted inspection. | +| Scriptorium | Source discovery, application schema and defaults, CLI parsing, recorded application normalization, semantic validation, command prerequisites, and runtime conversion. | +| Promptkit | Framework definition formats, backend semantics, credential lookup, engine defaults, and prompt execution. | + +`internal/config` becomes a small application-specific ConfigKit integration, +not a second general-purpose configuration framework. Execution and inspection +share one configuration definition and loading pipeline. Defaults, selected base +and imports, selected overlay, and explicit application CLI overrides participate +in ConfigKit's lifecycle; resolution and validation follow its upstream rules. +Normalization that changes inspected values is recorded through its resolver. +Runtime conversion does not perform a hidden second merge or apply new defaults +after the inspection snapshot has been created. + +Scriptorium retains its application field names and domain meanings unless a +specific change below requires otherwise. ConfigKit's public root API replaces +direct YAML decoding and parser-specific hooks. Application defaults remain +Scriptorium-owned; omitted framework settings still delegate to Promptkit. +Backend conversion retains deterministic registration and engine-scoped shared +capacity state. This work does not change the HTTP request contract or move +configuration loading into each HTTP request. + +## Native Configuration Semantics + +The target accepts ConfigKit's upstream YAML grammar, schema binding, limits, +composition, and value-presence rules without a legacy preprocessing layer. +Migration-visible changes include: + +- An existing empty file is invalid; `{}` expresses an empty application mapping. + Defaults-only operation with no discovered file uses `NoSource` instead. +- Explicit empty strings, false values, and zeroes replace defaults. They are + not silently treated as omission. Application validation still decides whether + a resulting value is meaningful for its field or selected command. +- Null follows the application's declared nullable types. It is not a universal + spelling for omission. Scalars and structs do not accept null merely because + the former parser tolerated it. +- Anchors, aliases, merge keys, explicit tags, additional documents, unsupported + scalar spellings, and coercions rejected by ConfigKit are rejected here too. +- ConfigKit's reserved `configkit` key and resource limits apply, including in + dynamic application data. These constraints do not apply to independently + loaded Promptkit definitions or HTTP request bodies. +- Dynamic integers in backend `extra_params` use ConfigKit's `int64` + representation. Runtime mapping preserves their supported value semantics + rather than reserializing through YAML or demanding the old Go scalar type. + +Presence remains meaningful at the framework boundary: omitted/null +`transient_retries` delegates to Promptkit, while explicit zero disables retries; +omitted backend queue capacity differs from explicit zero. Application HTTP +size defaults and zero-as-unlimited behavior remain. No new value ranges or +backend restrictions are introduced merely to adopt the library. + +## Discovery, Imports, Overlays, And Paths + +Source discovery remains Scriptorium-owned. The target retains the documented +explicit `--config` selection and ordered system-location search. If neither +implicit candidate exists, loading uses defaults only; a selected file that +fails loading is not silently replaced with defaults. No implicit +working-directory configuration search, environment overlay, or directory scan +is added. + +Application configuration supports ConfigKit's explicit path and glob imports. +Imports compose disjoint definitions; repeated non-mapping definitions are +conflicts, not last-writer-wins overrides. There is no implicit `conf.d` scan. + +An optional `--config-overlay` selects ConfigKit's one named overlay using its +standard `overlays/.yml` location, naming rules, and merge behavior. No +overlay is selected by default. Selecting an active overlay without a base +source follows ConfigKit's rejection of overlays with `NoSource`; Scriptorium +does not invent a root. Application overlays do not replace `--profile`, +`profile_dir`, or Promptkit's execution-profile selection. + +Use the selected file's canonical directory as ConfigKit's default import and +overlay root. This root governs configuration source traversal only. Values of +`prompt_dir`, `profile_dir`, `schema_dir`, and `server.artifact_root` retain +working-directory-relative interpretation; absolute values remain absolute. +This is an explicit application path policy, not an upstream requirement or a +legacy parsing mode. ConfigKit's consumer examples demonstrate alternatives but +do not mandate source-file-relative application paths. This adoption does not +extend import containment to application data or alter HTTP artifact containment. + +## CLI Overrides And Configuration Inspection + +Only flags explicitly supplied by the user become ConfigKit application +override records. Parser defaults do not overwrite file or overlay settings. +Explicit empty values are not dropped. The existing invocation-specific prompt, +profile, input, model, timeout, output, and reporting options remain invocation +state rather than new application configuration fields. In particular, the +run/render retry flag remains a request override; it does not mutate the engine's +application retry setting or backend state. + +Expose application configuration validation, effective redacted YAML, source +provenance, and explanation of an individual configuration path. These are +included features, not merely library capabilities available for future work. +They use ConfigKit diagnostics and inspection records from the shared loading +pipeline, including defaults, imports, overlays, explicit CLI values, and +recorded normalization. No separate inspection-only interpretation is maintained. + +Configuration inspection does not execute prompts, make provider calls, or +resolve API-key values. Application validation is not a promise that every +Promptkit backend or definition is valid or that a provider is reachable. +Command-specific execution prerequisites remain with the relevant command; +inspection can explain an incomplete application configuration without requiring +an executable prompt selection. The implementation plan will specify command +names, flag availability, output streams, and exit behavior without adding a +second CLI framework or an HTTP configuration endpoint. + +Safe diagnostics must not restore raw parser errors or configuration values +that ConfigKit deliberately suppresses. Effective output and explanation use +the upstream redacted renderers; they are inspection output, not guaranteed +reloadable configuration. Dynamic-value sensitivity needs the explicit choice +recorded under Open Questions before inspection is implemented. + +## Credential Boundary And Deferred Features + +Existing `api_key_env` values remain environment-name strings passed to Promptkit. +They do not become ConfigKit `Secret` fields. ConfigKit eagerly resolves effective +typed references and requires nonempty values; that would change Promptkit's +optional/required and selected-credential behavior. This departure from the +secret-reference feature is an ownership decision, not compatibility plumbing. +Raw API-key fields remain unsupported under the existing architecture policy. + +Secrets-directory bootstrap and application schema versioning are deferred until +there is a concrete application need. Their availability in ConfigKit does not +make them mandatory. Hot reload, runtime resource replacement, remote imports, +automatic migrations, and general environment-variable overlays are outside +this adoption. These are scope limits for this feature, not new permanent +prohibitions on future explicitly requested work. + +## Required Changes And Completion Criteria + +- Replace manual decoding/default/override machinery with the shared ConfigKit + integration and retain only application-specific discovery, rules, and mapping. +- Support imports and selected overlays across commands that load application + configuration, and deliver the configuration inspection capabilities above. +- Update application configuration types, presence handling, CLI explicit-set + mapping, and diagnostics to match the selected native semantics. +- Update maintained examples and canonical configuration, CLI, operations, + architecture, and internal documentation when behavior lands. Upstream generic + contracts remain linked rather than copied into a competing specification. +- Add proportionate integration coverage for the cutover: defaults-only input, + explicit values and nulls, imports/conflicts, overlays, CLI precedence, + inspection agreement and redaction, dynamic backend parameters, unchanged + credential ownership, and representative execution/server startup. + ConfigKit owns exhaustive parser and composition tests; Scriptorium tests its + adoption and application boundaries. +- Pin the published dependency and maintain ConfigKit and YAML attribution under + the [OSS policy](../policy/oss.md), using imported-commit source/notice links + and applicable standard and companion license texts. +- Document migration in a release appropriate for the intentional breaking + configuration changes under the [release policy](../policy/release.md). + Release selection and publication remain separate preparation work; this + roadmap adds no release gate, network probe, or new distribution format. + +Completion means one ConfigKit-native application configuration path serves +execution and inspection, the selected user-facing features work, and migrated +examples and regression coverage demonstrate the documented semantics. It does +not require adopting every ConfigKit feature or changing Promptkit definitions. + +## Open Questions + +### Sensitivity Of Arbitrary Backend Parameters + +ConfigKit redacts classified paths; it cannot infer secrets in arbitrary +provider-specific `extra_params`. The new inspection surface needs an explicit +classification policy, including superseded values shown in explanation. + +Recommended: classify each backend's entire `extra_params` container as sensitive +for inspection. That avoids guessing provider-specific secret names and covers +historical values without restricting which parameters may be passed to Promptkit. +The tradeoff is that benign provider options are also hidden. + +Alternative: maintain an explicit application classification of sensitive paths, +leaving other parameter values visible. This gives more useful inspection but +requires a clear mechanism for classifying arbitrary provider options and ongoing +maintenance; key-name heuristics alone are not a reliable substitute. This is an +inspection-policy choice, not authority to reject new backend parameter keys.