Make consumer documentation easier to follow
This commit is contained in:
@@ -1,24 +1,35 @@
|
||||
# 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.
|
||||
ConfigKit loads configuration into your application's Go types. You provide
|
||||
those types, defaults, and application rules. ConfigKit reads and combines the
|
||||
selected inputs, checks their types, and returns values with source information.
|
||||
Your application still owns CLI parsing, resource reads, remote acquisition, and
|
||||
runtime initialization.
|
||||
|
||||
Import the public root package as `"go.maximumdirect.net/configkit"`; its package
|
||||
name remains `configkit`.
|
||||
Import `"go.maximumdirect.net/configkit"`; the package name is `configkit`.
|
||||
Start with one file, then choose the tasks your application needs:
|
||||
|
||||
| Task | Start here |
|
||||
| --- | --- |
|
||||
| Load one file | [Happy path](#happy-path) and the [README example](../../README.md#load-a-configuration-file) |
|
||||
| Supply fixed defaults and check application rules | [Defaults and application rules](#defaults-and-application-rules) |
|
||||
| Add bundled defaults beneath application settings | [Native filesystem and layered input](#native-filesystem-and-layered-input) |
|
||||
| Select files or an overlay | [Discovery](#explicit-main-file-discovery), [import defaults](#import-defaults-and-selection-inspection), and the [overlay reference](../config.md#selected-overlays) |
|
||||
| Reuse settings or combine record lists | [Inheritance](#named-sibling-inheritance) and [identified sequences](#identified-prompt-sequences) |
|
||||
| Handle credentials | [Typed-secret reference](../config.md#typed-secret-references) and the [startup example](../../examples/consumers/consumers_test.go) |
|
||||
| Inspect sources, earlier values, or changes | [Inspect a completed load](#inspect-a-completed-load) and [diffs](#effective-configuration-diffs) |
|
||||
| Upgrade an existing consumer | [Migration guidance](#intentional-migration-changes) |
|
||||
|
||||
## Choosing a loading entry point
|
||||
|
||||
- Use [`Load`](../../lifecycle.go) with one source for an ordinary configuration.
|
||||
[`SearchConfig`](../../discovery.go) is also a source, so its explicit
|
||||
discovery result can be passed to `Load` or used as the main input to
|
||||
[`LoadLayered`](../../layered.go).
|
||||
- Use `LoadLayered` when inputs must be composed in underlay groups before the
|
||||
main source. Each [`Input`](../../layered.go) owns its source, filesystem,
|
||||
destination, and import choice. The overlay filesystem context is selected
|
||||
independently in [`LayeredOptions`](../../layered.go).
|
||||
[`SearchConfig`](../../discovery.go) is also a source; pass it to `Load` or use
|
||||
it as the main input to [`LoadLayered`](../../layered.go).
|
||||
- Use `LoadLayered` when several inputs should supply lower-priority defaults
|
||||
beneath the main source. Each underlay group combines its inputs strictly.
|
||||
Each [`Input`](../../layered.go) owns its source, filesystem, destination, and
|
||||
import choice. The overlay filesystem context is selected independently in
|
||||
[`LayeredOptions`](../../layered.go).
|
||||
- Load-wide rules belong to [`Options`](../../lifecycle.go) or
|
||||
[`LayeredOptions`](../../layered.go): the application definition (including
|
||||
version policy), import defaults, and explicit overrides. These do not turn
|
||||
@@ -33,68 +44,68 @@ file and layered cases. For import-focused adoption, see the
|
||||
discovery composed with sequences, see the
|
||||
[sequence catalog](../../examples/consumers/sequence_catalog.go).
|
||||
|
||||
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 |
|
||||
| Mounted collections | Entry-declared relative destinations, nested metadata/prompt/profile imports, local inheritance, and a version-only higher-tier override | Collection IDs, profile meaning, and opening/interpreting prompt resources |
|
||||
| Named presets | One-load sibling inheritance, explicit false, nested destination resolution, and source/derivation inspection | Choosing and executing a preset |
|
||||
| Effective configuration diff | Same-type frozen effective comparisons for two selected files or base-versus-overlay impact | Source/options selection and consumer-owned safe presentation |
|
||||
| Shared source-version checks | One `Definition.Version` policy for accepted declarations across participating source documents, with optional or required declarations and sanitized evidence | Choosing which declarations the application accepts; final assembled schema and domain validation |
|
||||
| Sequence catalogs | Declared collection operations, record inheritance, typed CLI and resolution, inspection, exact and wildcard application registrations | Catalog meaning and final domain validation |
|
||||
|
||||
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:
|
||||
Define the Go configuration type, choose one source, and call `Load`. Handle a
|
||||
load error before starting the application with `result.Config`. The
|
||||
[README example](../../README.md#load-a-configuration-file) shows this complete
|
||||
minimal loading function. An explicitly missing file is an error; use `NoSource`
|
||||
when you deliberately want defaults without a main document.
|
||||
|
||||
### Defaults and application rules
|
||||
|
||||
Using the README's `Config` type, an application can add reusable rules:
|
||||
|
||||
```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
|
||||
definition := configkit.Definition[Config]{
|
||||
Defaults: func() Config { return Config{Enabled: true, Workers: 2} },
|
||||
Validate: func(value *Config, validation *configkit.Validation) {
|
||||
if value.Workers < 0 {
|
||||
validation.Error(configkit.Keys("workers"), "must be nonnegative")
|
||||
}
|
||||
},
|
||||
}
|
||||
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.
|
||||
Pass this definition in `Options[Config]{Definition: definition}` when calling
|
||||
`Load`. Supplied `enabled: false` or `workers: 0` replaces those defaults.
|
||||
Use `Resolve` when a value must be derived or normalized before validation, and
|
||||
record that change with the provided helpers. The
|
||||
[callback reference](../config.md#recorded-application-resolution) compares the
|
||||
helpers; [executable examples](../../example_test.go) show full definitions.
|
||||
|
||||
### Inspect a completed load
|
||||
|
||||
Keep the result when you need to explain configuration. Use
|
||||
`result.Metadata().Lookup(configkit.Keys("workers"))` to inspect whether input
|
||||
supplied the value and which source or application step supplied it. Follow an
|
||||
origin's source ID with `result.Source(id)` when you need its source record.
|
||||
|
||||
Use `Explain` for earlier values, `WriteExplanation` for a readable explanation,
|
||||
and `WriteEffective` for safe YAML describing the final saved state. These
|
||||
operations describe the completed load even if your application later changes
|
||||
`result.Config`. The [inspection reference](../config.md#layered-metadata)
|
||||
explains returned values, copies, and hidden information.
|
||||
|
||||
Add imports, a selected overlay, or explicitly set CLI values through options
|
||||
only when needed. An overlay changes configuration; choosing an LLM, report, or
|
||||
execution profile remains application logic.
|
||||
|
||||
## Explicit main-file discovery
|
||||
|
||||
Applications choose the search conventions and their precedence, then pass the
|
||||
resulting `SearchConfig` source to the same `Load` or `LoadLayered` entry point.
|
||||
For example, the maintained sequence catalog puts a caller-selected file before
|
||||
a custom directory fallback while keeping its underlay and overlay choices
|
||||
independent. See [`sequence_catalog.go`](../../examples/consumers/sequence_catalog.go)
|
||||
and its [behavior tests](../../examples/consumers/sequence_catalog_test.go), plus
|
||||
the [working-directory executable example](../../examples/consumers/discovery_test.go).
|
||||
Together, the root-owned [discovery API](../../discovery.go) and [configuration
|
||||
discovery contract](../config.md#configuration-discovery) define ordered
|
||||
concatenation, directory-first Cartesian expansion, optional exhaustion, and
|
||||
selected-file behavior. [ADR 0019](../adr/0019-explicit-configuration-discovery.md)
|
||||
resulting `SearchConfig` source to the same `Load` or `LoadLayered` entry
|
||||
point. For example, the maintained sequence catalog puts a caller-selected
|
||||
file before a custom directory fallback while keeping its underlay and overlay
|
||||
choices independent. See
|
||||
[`sequence_catalog.go`](../../examples/consumers/sequence_catalog.go) and its
|
||||
[behavior tests](../../examples/consumers/sequence_catalog_test.go), plus the
|
||||
[working-directory executable
|
||||
example](../../examples/consumers/discovery_test.go). Together, the [discovery
|
||||
API](../../discovery.go) and [configuration discovery
|
||||
contract](../config.md#configuration-discovery) explain the order of attempted
|
||||
files, what happens when no file is found, and why a selected-file failure
|
||||
stops the search. [ADR 0019](../adr/0019-explicit-configuration-discovery.md)
|
||||
records why discovery is explicitly selected.
|
||||
|
||||
## Import defaults and selection inspection
|
||||
@@ -143,13 +154,14 @@ priority values remain present. Its resolver records a derived endpoint URL afte
|
||||
overlay application, and its nested typed secret reference is classified before
|
||||
the resulting records are presented.
|
||||
|
||||
The maintained [behavior tests and executable examples](../../examples/consumers/diff_test.go)
|
||||
use temporary files and disposable secret values. Presenters should use
|
||||
`ValueSnapshot.Present` for absence, record membership for change, and
|
||||
`HiddenChanged` for a withheld change indicator. Do not parse the redaction marker
|
||||
or add separately rendered full contexts that lack combined sensitivity. The
|
||||
[configuration contract](../config.md#effective-configuration-diffs) owns shared
|
||||
equality, granularity, and disclosure semantics.
|
||||
The maintained [behavior tests and executable
|
||||
examples](../../examples/consumers/diff_test.go) use temporary files and
|
||||
disposable secret values. Presenters should use `ValueSnapshot.Present` for
|
||||
absence, record membership for change, and `HiddenChanged` for a withheld
|
||||
change indicator. Do not parse the redaction marker or add separately rendered
|
||||
full contexts that lack combined sensitivity. The [configuration
|
||||
contract](../config.md#effective-configuration-diffs) owns shared equality,
|
||||
granularity, and disclosure semantics.
|
||||
|
||||
## Named sibling inheritance
|
||||
|
||||
@@ -276,10 +288,9 @@ path-bearing example. Its application resolver uses `Resolution.EntryInfo` 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.
|
||||
unchanged. Its executable test checks the resulting YAML and explanation
|
||||
history. When the configuration filename is a symlink, this example uses the
|
||||
actual target file's directory as the base for file-authored paths.
|
||||
|
||||
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
|
||||
@@ -289,7 +300,15 @@ existence checks nor confinement checks.
|
||||
|
||||
## Intentional migration changes
|
||||
|
||||
The examples preserve domain meaning while adopting one configuration convention:
|
||||
When upgrading, start with the changes relevant to your dependency and inputs:
|
||||
|
||||
1. Update the module requirement and Go imports together as described below.
|
||||
2. Replace old public names using the old/new table.
|
||||
3. Update any layer or diagnostic-code strings stored or compared by your code.
|
||||
4. Review YAML and startup changes that apply to your application, then rebuild
|
||||
and run its configuration tests.
|
||||
|
||||
The maintained examples illustrate these configuration changes:
|
||||
|
||||
- Explicit empty strings, lists, zeroes, false values, and nulls remain intentional.
|
||||
ConfigKit accepts an empty list structurally; WeatherReporter-shaped validation
|
||||
@@ -323,11 +342,13 @@ Go imports together, selecting a revision or release that declares the new modul
|
||||
path. The package name remains `configkit`; the configuration model and public
|
||||
symbol names are unchanged by this identity migration.
|
||||
|
||||
Old and new import paths identify distinct Go packages, including distinct named
|
||||
types. Coordinate adoption with any dependencies that exchange ConfigKit values
|
||||
with your application; changing a requirement alone does not make those types
|
||||
interchangeable. The maintained examples use the new path, but other repositories
|
||||
must manage their own migrations.
|
||||
Go treats the old and new import paths as different packages, with different
|
||||
named types. For example, if another library returns a ConfigKit `Path` or
|
||||
`Secret` using the old import, your application cannot use it as the new
|
||||
package's type just by changing a module requirement. Coordinate migration
|
||||
with dependencies that pass ConfigKit values to or from your application. The
|
||||
maintained examples use the new path, but other repositories must manage their
|
||||
own migrations.
|
||||
|
||||
Historical tags keep their original module declarations and contents. Older
|
||||
releases such as v0.10.2 still use the old path and cannot be installed under the
|
||||
@@ -363,12 +384,13 @@ compatibility aliases:
|
||||
| History diagnostic string `"explain.limit_exceeded"` | `"history.limit_exceeded"` |
|
||||
|
||||
The YAML import keys `follow` and `hidden`, the `configkit:"secret"` tag, and
|
||||
typed `Secret` references are unchanged. Consumers that compare literal strings
|
||||
or keep serialized diagnostic/provenance expectations may need to update those
|
||||
alongside Go references. This repository guidance does not claim that downstream
|
||||
applications have migrated and does not select a release version for this
|
||||
breaking pre-v1 change. `ChangeKind` and its inspection constants remain; use
|
||||
`Default` and `Normalize` when the helper should both assign and record a value.
|
||||
typed `Secret` references are unchanged. If your application compares or
|
||||
stores layer names or diagnostic codes as strings, update those strings
|
||||
alongside Go references. This repository guidance does not claim that
|
||||
downstream applications have migrated and does not select a release version
|
||||
for this breaking pre-v1 change. `ChangeKind` and its inspection constants
|
||||
remain; use `Default` and `Normalize` when the helper should both assign and
|
||||
record a value.
|
||||
|
||||
### Selected-overlay migration
|
||||
|
||||
@@ -380,10 +402,40 @@ 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.
|
||||
### Background on the examples
|
||||
|
||||
These examples demonstrate migration shapes. They do not claim that Narratio,
|
||||
Notarius, WeatherReporter, or Seriatim has been migrated. Updating those
|
||||
repositories, their deployed YAML, CLI wiring, runtime catalogs, and
|
||||
operational documentation remains separate downstream work.
|
||||
|
||||
## Example background
|
||||
|
||||
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 |
|
||||
| --- | --- | --- |
|
||||
| Artifact defaults and normalization (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 |
|
||||
| Versions and dynamic options (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` |
|
||||
| Module validation and credential startup (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 |
|
||||
| Independent ordered rule files (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 |
|
||||
| Mounted collections | Entry-declared relative destinations, nested metadata/prompt/profile imports, local inheritance, and a version-only higher-tier override | Collection IDs, profile meaning, and opening/interpreting prompt resources |
|
||||
| Named presets | One-load sibling inheritance, explicit false, nested destination resolution, and source/derivation inspection | Choosing and executing a preset |
|
||||
| Effective configuration diff | Same-type frozen effective comparisons for two selected files or base-versus-overlay impact | Source/options selection and consumer-owned safe presentation |
|
||||
| Shared source-version checks | One `Definition.Version` policy for accepted declarations across participating source documents, with optional or required declarations and sanitized evidence | Choosing which declarations the application accepts; final assembled schema and domain validation |
|
||||
| Sequence catalogs | Declared collection operations, record inheritance, typed CLI and resolution, inspection, exact and wildcard application registrations | Catalog meaning and final domain validation |
|
||||
|
||||
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.
|
||||
|
||||
## Maintained API examples
|
||||
|
||||
|
||||
Reference in New Issue
Block a user