4.1 KiB
ADR 0008: Synchronous, Complete-on-Return Configuration Loading
Status
Proposed draft for review. The configuration contract describes the implemented loading lifecycle. The source-backed underlays roadmap owns its application to the planned source and resource-context APIs.
Date
2026-09-29
Context
Applications need a clear point at which configuration is ready for use. Completing configuration processing and inspection metadata together gives applications a coherent result whose values and origins agree. A bounded loading lifecycle also makes resource ownership and startup failures straightforward to reason about.
ConfigKit's architecture goals emphasize complete configuration, inspectable provenance, predictable behavior, and minimal consumer bookkeeping. Applications own their execution lifecycle and the timing of configuration acquisition.
Decision
Make loading a synchronous, complete-on-return operation. Within each load, ConfigKit completes input assembly, defaulting, typed decoding, configured application resolution, secret lookup, validation, and snapshotting before returning the final configuration and metadata. Reported failures return diagnostics and a nil result.
Release all library-owned loading handles before returning on success or failure. The resulting configuration and metadata are independently usable, caller-owned data with a retained inspection snapshot. Caller-supplied readers and filesystems remain under caller ownership and lifetime control.
After the call completes, ConfigKit remains inactive until explicitly invoked again. Applications normally load once at or near startup and may initiate additional loads when needed. Each load follows the same lifecycle and source reuse contracts. Inspection, rendering, and separately requested operations run in response to explicit application calls.
For the planned resource-context capability, retain source context as passive information or a borrowed caller-supplied filesystem. Subsequent resource access acquires its own handles with explicit ownership. This preserves a clear boundary between configuration completion and application resource use.
These choices give consumers one completion boundary for configuration and provenance, predictable resource lifetimes, and control over when ConfigKit runs. Application callbacks remain responsible for their own effects and resources.
Alternatives considered
- Background watching or refresh. Can automate responses to source changes, but adds scheduling, shutdown, publication, and resource-lifetime concerns to the library. Explicit calls keep those responsibilities with the application.
- Lazy completion after return. Can defer work until particular values are used, but moves configuration failures into application execution and makes the readiness of values and metadata harder to establish.
- Transactional atomic loading. Could imply simultaneous observation of all external inputs and rollback of callback effects. Filesystems, environment variables, and application callbacks do not share a transaction mechanism. Synchronous completion provides the required usable-result boundary without promising those external guarantees.
- Retain loading handles in results. Can preserve open filesystem access, but gives configuration results an ongoing resource lifecycle and cleanup obligation. Passive source context supports later explicit resource access while keeping loading resources scoped to the load call.
Consequences
Applications can treat successful return as the point at which the final configuration and its metadata are ready for use. Startup loading remains simple, and additional loads have an explicit application-owned trigger.
Configuration inspection operates on retained data. Resource access observes the backing resource when explicitly requested and has its own failure and ownership boundary. Implementations of new source kinds and layering features preserve the same completion boundary, including cleanup on reported load failures.