Decode typed configuration over defaults
This commit is contained in:
@@ -552,69 +552,21 @@ Applications own flags and commands that select this behavior.
|
||||
|
||||
## Static defaults and null
|
||||
|
||||
Applications supply a defaults factory that creates a fresh configuration per
|
||||
load. Mutable maps, slices, and pointers must not be shared between factory
|
||||
results. ConfigKit must not retain mutable aliases between returned loads or
|
||||
between the application result and its internal metadata snapshots.
|
||||
|
||||
Defaults obey the same recursive mapping/atomic replacement rules as a lower
|
||||
layer, rather than incidental decoder behavior:
|
||||
|
||||
| Configured input | Effect on defaults |
|
||||
| --- | --- |
|
||||
| Absent field | Keep the default |
|
||||
| Explicit false, zero, or empty string | Replace the default |
|
||||
| Partial mapping, including a string-keyed Go map | Retain omitted default children/entries |
|
||||
| `{}` over an existing mapping | Retain its default children |
|
||||
| Sequence, including `[]` | Replace the entire default sequence |
|
||||
| Partial object represented by a pointer | Retain children of a non-nil default object; otherwise allocate and use ordinary zero values for omitted children |
|
||||
| Allowed null | Replace with nil; suppress lower defaults |
|
||||
|
||||
The factory supplies actual defaults; ConfigKit does not invent per-entry
|
||||
defaults for newly introduced map entries or sequence elements. Application
|
||||
resolution may supply those. Go zero values are part of the initial typed
|
||||
baseline; do not imply that the application explicitly declared every zero as
|
||||
a domain default. Avoid serialization through `omitempty` that would erase
|
||||
baseline values or presence information.
|
||||
|
||||
Null is valid for pointers, maps, slices, and dynamic `any` values. It is invalid
|
||||
for ordinary scalar fields, structs, and arrays. Thus `workers: null` cannot
|
||||
silently leave an integer default intact. Applications can further reject null
|
||||
through validation. Null never means reset to the application default.
|
||||
The defaults merge and nullability model is implemented privately. The
|
||||
[current defaults and typed-decoding contract](../config.md#defaults-and-typed-decoding)
|
||||
owns recursive mapping, atomic sequence, pointer allocation, explicit-presence,
|
||||
null, and detached-baseline behavior. The public defaults factory and result
|
||||
lifecycle remain target work in the sections below.
|
||||
|
||||
## Typed decoding
|
||||
|
||||
The schema-binding portion of this target is implemented. The [current application
|
||||
schema contract](../config.md#application-schema-binding) owns root/type support,
|
||||
field and tag binding, inlining, text-codec pairing, and schema-aware path rules.
|
||||
The remaining document-to-value behavior below is target decoding work.
|
||||
|
||||
Strictness must be enforced by ConfigKit across the effective tree:
|
||||
|
||||
- Unknown struct fields, type mismatches, overflow, and invalid null are errors.
|
||||
- Without an inline map, unmatched keys remain errors. Default inline-map entries
|
||||
colliding with declared fields are checked when runtime defaults are introduced.
|
||||
- String-keyed maps accept application-defined keys. Struct values inside them
|
||||
remain strict. `map[string]any` permits arbitrary keys and recursively accepts
|
||||
the supported scalar/container model; application validation owns its schema.
|
||||
- Do not coerce numbers or booleans to strings, or quoted numbers to numeric
|
||||
fields. Integer targets require integer syntax and range checks. Float targets
|
||||
accept finite decimal numbers subject to representable range checks.
|
||||
- Dynamic integer values use checked `int64`, and fractional/exponent values use
|
||||
checked finite `float64`; values outside those ranges require a typed schema
|
||||
or a quoted string rather than silent rounding of integer nodes.
|
||||
- Support `time.Duration` from a duration string. Custom scalar types must
|
||||
implement both `encoding.TextUnmarshaler` and `encoding.TextMarshaler` so
|
||||
decoding and inspection have an agreed representation. Duration integers are
|
||||
rejected. See the [type and projection contract](#supported-types-and-projection).
|
||||
- Parser-specific unmarshal hooks are not a public extension mechanism. Do not
|
||||
let them bypass key, null, or type policy. Custom structural decoders are
|
||||
deferred; unsupported type shapes fail with a clear schema diagnostic.
|
||||
|
||||
Keep parser nodes and errors internal under the
|
||||
[upstream isolation contract](#yaml-dependency-and-public-api-isolation).
|
||||
The field-binding model must also support defaults, provenance, secret
|
||||
classification, and rendering consistently.
|
||||
Schema binding and strict document-to-value decoding are implemented privately.
|
||||
The [current application schema contract](../config.md#application-schema-binding)
|
||||
owns root/type support, field and tag binding, inlining, codec pairing, and
|
||||
schema-aware path rules. The [current defaults and typed-decoding contract](../config.md#defaults-and-typed-decoding)
|
||||
owns strict conversions, container application, presence, safe failures, and initial
|
||||
origins. Public lifecycle integration, layered provenance, secret handling, and
|
||||
rendering remain target work below.
|
||||
|
||||
## Recorded resolution and validation
|
||||
|
||||
|
||||
Reference in New Issue
Block a user