Add maintained consumer migration examples

This commit is contained in:
2026-09-06 22:26:14 +00:00
parent 6ef240b1a0
commit a8bfb8848d
23 changed files with 855 additions and 95 deletions

View File

@@ -989,95 +989,10 @@ public records, replay ordering, redaction, rendering, and allocation bounds.
### Module-specific options
Use a canonical object entry with an explicit module identifier and options
mapping. Shorthand strings and custom structural decoders are not required to
express the domain information. For a known application module catalog, model
the available option fields with ordinary typed structs; application validation
selects the meaningful fields and rejects incompatible combinations.
Illustrative YAML for an application that supports two modules:
```yaml
modules:
- module: chunker
options:
window_units: 12
- module: discussion
options:
sections: [short_term]
```
The corresponding typed configuration and validator need no second parser:
```go
type ModuleOptions struct {
WindowUnits *int `yaml:"window_units"`
Sections []string `yaml:"sections"`
}
type ModuleSpec struct {
Module string `yaml:"module"`
Options ModuleOptions `yaml:"options"`
}
type ModuleConfig struct {
Modules []ModuleSpec `yaml:"modules"`
}
func validateModules(cfg *ModuleConfig, v *configkit.Validation) {
for index, spec := range cfg.Modules {
path := configkit.Keys("modules").Index(index)
switch spec.Module {
case "chunker":
if spec.Options.WindowUnits == nil || *spec.Options.WindowUnits < 1 {
v.Error(path.Key("options").Key("window_units"), "must be a positive integer")
}
if spec.Options.Sections != nil {
v.Error(path.Key("options").Key("sections"), "not supported by this module")
}
case "discussion":
if spec.Options.WindowUnits != nil {
v.Error(path.Key("options").Key("window_units"), "not supported by this module")
}
if len(spec.Options.Sections) == 0 {
v.Error(path.Key("options").Key("sections"), "must contain at least one section")
}
default:
v.Error(path.Key("module"), "unsupported module")
}
}
}
func ReadModuleConfig(path string) (*configkit.Result[ModuleConfig], error) {
return configkit.Load(configkit.File(path), configkit.Options[ModuleConfig]{
Definition: configkit.Definition[ModuleConfig]{Validate: validateModules},
})
}
```
The pointer and nil-slice states above express optional domain values; this
application treats explicit null as unselected for those optional alternatives.
ConfigKit rejects unknown fields and invalid scalar types. The application owns
which supported options apply to a module and their domain constraints. Larger
catalogs may use nested typed option objects rather than one flat options struct.
Neither shape requires a library registry, parser hook, or configurable merge rule.
For an application whose option schema is genuinely selected at runtime,
`map[string]any` remains available. ConfigKit owns parsing, paths, and the single
dynamic scalar representation; application validation owns the selected schema,
including allowed keys and value constraints. Conversion into runtime module
arguments is application code. Dynamic integers remain checked `int64`; existing
`int` assertions must be adapted with range checks when converting to `int`.
The initial API does not add a generic subtree-conversion helper. Prefer typed
configuration where option shapes are known, and direct domain validation where
they are dynamic. Do not introduce a second YAML marshal/decode round trip as the
blessed pattern. Reconsider a narrow conversion helper only if a concrete dynamic
catalog demonstrates substantial duplicated type-binding infrastructure that
ordinary models cannot remove. Such a helper would have to retain strictness and
source attribution; that is a separate justified extension, not an escape hatch
for legacy shorthand. Configuration inspection describes the validated input
model, not the application's separately constructed runtime module objects.
Canonical typed and dynamic module options are implemented through the ordinary
schema. The [current module-options contract](../config.md#canonical-module-options)
and [consumer adoption guide](../consumers/README.md) own the maintained object
forms, validation boundary, and executable examples.
### Supported types and projection