157 lines
9.5 KiB
Markdown
157 lines
9.5 KiB
Markdown
# Consumer Adoption Guide
|
|
|
|
ConfigKit removes parser setup, strict decoding, presence bookkeeping, import and
|
|
selected-overlay traversal, precedence, provenance, secret lookup, and safe inspection from
|
|
applications. Consumers still own their configuration structs, defaults, semantic
|
|
validation, schema-version policy, CLI parsing, runtime matching and conversion,
|
|
resource checks, remote acquisition, and service initialization.
|
|
|
|
The maintained [`examples/consumers`](../../examples/consumers) package demonstrates
|
|
sanitized shapes using only ConfigKit and the Go standard library:
|
|
|
|
| Shape | Demonstrated fit | Application code deliberately retained |
|
|
| --- | --- | --- |
|
|
| Narratio-like | Fresh defaults, explicit partial imports, artifact maps, recorded inherited defaults, normalization, and source ownership | Artifact meaning and the separate `model_profile` domain field |
|
|
| Notarius-like | Canonical object bindings, a string-backed schema version accepting string or integer YAML, strict dynamic options, and `int64` dynamic integers | Catalog selection, allowed option keys, range-checked conversion to runtime `int` |
|
|
| WeatherReporter-like | Defaults-only loading, report maps, canonical module objects, typed option unions, explicit CLI records, and typed secret startup | Report/module compatibility, rejection of explicitly empty domain lists, CLI parsing, and startup ordering |
|
|
| Seriatim-like | Independent strict ordered speaker and autocorrect rule files | First-match and ordered replacement algorithms; no central application configuration file |
|
|
| Bundled file | Simple native `fs.FS` source through ordinary `Load` | Selection and lifetime of the application-owned embedded filesystem |
|
|
| Layered catalog | Embedded defaults with an import, a mapping underlay, an independent host main file, explicit false/zero input, and source-relative resource access | Domain validation and opening/interpreting the template resource |
|
|
|
|
The YAML under [`testdata`](../../examples/consumers/testdata) is loaded by the
|
|
executable examples and ordinary tests. It contains no private application data,
|
|
credentials, network calls, or dependency on a sibling checkout.
|
|
|
|
The Notarius-shaped fixtures deliberately load both `version: 4` and
|
|
`version: "4"` into the same string-backed application field. Its version checker
|
|
still owns the supported identifier; fractional numeric input and unsupported
|
|
integer identifiers remain negative examples.
|
|
|
|
## Happy path
|
|
|
|
An application defines ordinary types and passes one explicit source. Optional
|
|
features appear only when the application needs them:
|
|
|
|
```go
|
|
result, err := configkit.Load[Config](configkit.File(path), configkit.Options[Config]{
|
|
Definition: rules,
|
|
Imports: useDeclaredImports,
|
|
Overlay: selectedConfigOverlay,
|
|
Overrides: explicitlySetFlags,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return start(result.Config)
|
|
```
|
|
|
|
Simple consumers use neither imports nor selected overlays. A complex consumer can opt into
|
|
both without redefining their syntax. ConfigKit overlays are configuration overlays;
|
|
they do not select or replace an application's LLM, model, pipeline, report, or
|
|
execution profile concepts.
|
|
|
|
## Native filesystem and layered input
|
|
|
|
[`LoadBundled`](../../examples/consumers/layered.go) keeps the simple `Load` shape:
|
|
it selects a file in an application-owned embedded filesystem and needs no
|
|
underlay setup. [`LoadCatalog`](../../examples/consumers/layered.go) uses
|
|
`LoadLayered` with an imported embedded-defaults group, a separate
|
|
`Mapping` group, and a host main file supplied by its caller. The groups
|
|
compose strictly within themselves and recursively across precedence boundaries;
|
|
the main file's explicit `false` and `0` replace lower values without being
|
|
mistaken for omissions. Its validator owns allowed modes and resource-name policy.
|
|
|
|
[`ReadWelcome`](../../examples/consumers/layered.go) follows the effective field's
|
|
origin location to a source ID, queries `Result.SourceContext`, and opens the
|
|
resource relative to that context's `BaseDir`. It does not assume the main file
|
|
owns a retained underlay value. A composite origin needs an application choice;
|
|
ConfigKit does not guess a directory. The context query is passive, while later
|
|
resource reads observe the caller-owned filesystem or a freshly opened host root
|
|
and may fail independently of the completed configuration load. The
|
|
[configuration contract](../config.md#source-resource-contexts) owns exact
|
|
lifetime and precedence rules.
|
|
|
|
Known module catalogs should use canonical object entries with a module identifier
|
|
and typed options. A small union struct is sufficient when the available option
|
|
fields are known; validation selects which fields apply to each module. Runtime-
|
|
selected catalogs may retain `map[string]any`, whose integers are `int64`; applications
|
|
validate keys and ranges and convert only at their runtime boundary. Neither shape
|
|
needs YAML reserialization, a parser hook, a ConfigKit registry, or a generic subtree
|
|
conversion API.
|
|
|
|
## Source-aware application path policy
|
|
|
|
[`LoadNotariusPaths`](../../examples/consumers/consumers.go) is the maintained
|
|
path-bearing example. Its application resolver uses `Resolution.InputInfo` and
|
|
`Resolution.Source` before normalizing: relative CLI input uses an explicitly
|
|
supplied invocation directory, retained defaults use the canonical main source,
|
|
and a file-authored scalar uses its one declaring source. Absolute paths remain
|
|
unchanged. Its executable test covers the matching effective YAML and explanation
|
|
history, source-file ownership, and a symlink opened through an alias; canonical
|
|
target-file directories, rather than the alias directory or process working
|
|
directory, are the selected bases.
|
|
|
|
The selected example policy leaves a relative value unchanged and emits a warning
|
|
when a CLI base is absent or file provenance is missing or composite. That is an
|
|
application choice, not a ConfigKit fallback: consumers can instead reject it or
|
|
choose another explicit base. The example intentionally performs neither target
|
|
existence checks nor confinement checks.
|
|
|
|
## Intentional migration changes
|
|
|
|
The examples preserve domain meaning while adopting one configuration convention:
|
|
|
|
- Explicit empty strings, lists, zeroes, false values, and nulls remain intentional.
|
|
ConfigKit accepts an empty list structurally; WeatherReporter-shaped validation
|
|
rejects an explicitly or programmatically supplied empty module/template list as a
|
|
domain rule. Loaded and constructed values use the same validator.
|
|
- Canonical module and object bindings replace string shorthand. Unknown fields and
|
|
incompatible option shapes fail at their semantic paths.
|
|
- Schema versions remain string-backed in application types. A configured
|
|
`VersionRule` accepts string or strict decimal-integer YAML at its exact path and
|
|
supplies the spelling to both the checker and a plain string destination.
|
|
- Integers inside dynamic options are portable `int64` values. Runtime `int`
|
|
conversion is explicit and range checked.
|
|
- Strict YAML intentionally rejects duplicate keys, aliases, merge keys, unsupported
|
|
tags/scalars, trailing documents, and unknown typed fields. Diagnostics expose
|
|
stable classifications and safe paths, not copied parser text.
|
|
- General environment-variable configuration overlays retire. Application CLI
|
|
parsers translate only explicitly set configuration flags into `Override` records.
|
|
Separate invocation state remains outside configuration.
|
|
- Credential fields migrate to environment-name `Secret` references. Applications
|
|
explicitly call `LoadSecretsDir` before `Load` when they choose file bootstrap;
|
|
blocked empty variables remain blocked, and ordinary `Load` never changes the
|
|
process environment.
|
|
|
|
### Selected-overlay migration
|
|
|
|
To adopt the current selected-overlay API, rename `Options.Profile`,
|
|
`LayerProfile`, and `CodeProfile*` references to their `Overlay` equivalents; move
|
|
selected files from `profiles/<name>.yml` to `overlays/<name>.yml`; update any
|
|
handling of the `overlay` layer and `overlay.*` diagnostic strings; then rebuild.
|
|
The [configuration contract](../config.md#selected-overlays) is the canonical
|
|
behavioral reference. Application-owned profile concepts, such as `model_profile`,
|
|
are unchanged, and any CLI flag rename remains the application's decision.
|
|
|
|
These examples are migration evidence, not completed changes to Narratio, Notarius,
|
|
WeatherReporter, or Seriatim. Updating those repositories, their deployed YAML, CLI
|
|
wiring, runtime catalogs, and operational documentation remains separate downstream
|
|
work.
|
|
|
|
## Maintained API examples
|
|
|
|
Every nontrivial initial API sketch has a compiled example or a
|
|
focused behavioral owner:
|
|
|
|
| Roadmap surface | Maintained owner |
|
|
| --- | --- |
|
|
| `Load`, `NoSource`, validation, versions, resolution, `SecretEnv`, overrides, and explanation | Executable examples in [`example_test.go`](../../example_test.go) |
|
|
| Source/import/selected-overlay pipeline rules and artifact defaults | Narratio-shaped executable example and fixture |
|
|
| Canonical module objects and dynamic option handling | WeatherReporter- and Notarius-shaped examples and migration tests |
|
|
| `LoadSecretsDir`, bootstrap reporting, typed lookup, CLI explanation | `Example_weatherStartup` |
|
|
| Native filesystem, grouped underlays, programmatic mapping, retained resource context | `Example_nativeFilesystem`, `Example_layeredCatalog`, and their focused consumer tests |
|
|
| Results, metadata, diagnostics, effective output, and writer failures | Focused root-package load, provenance, rendering, and explanation tests |
|
|
|
|
The package-level import-boundary test covers the consumer examples too: supported
|
|
usage names no YAML dependency, parser type, parser option, or parser error chain.
|