7.9 KiB
Architecture Policy
Base Policy Version: 1.0
Last Updated: 2026-09-06
Purpose and applicability
ConfigKit is an opinionated Go library for consistent YAML configuration loading and resolution across consuming applications. This policy governs contributions. The component overview owns implementation inventory, the configuration contract owns implemented behavior, and the initial target record preserves deferred scope.
Success criteria
- Reduce application infrastructure: Can applications delete substantial configuration infrastructure while retaining clear ownership of their domain rules?
- Unify configuration conventions: Do consumers adopt one consistent configuration model, with only the flexibility needed to express genuine application requirements?
Both criteria must hold. ConfigKit should not preserve divergent consumer conventions merely for compatibility, nor impose restrictions that prevent useful domain information from being expressed. Prefer a canonical representation using existing primitives before adding another mechanism. Extend the model when a concrete requirement cannot be accommodated cleanly, not simply because a consumer already implements a different convention.
Use both criteria to evaluate public API changes and consumer adoption. Shared loading, presence tracking, source attribution, and diagnostic plumbing should move out of applications; application types, defaults, normalization, and semantic validation should remain recognizable application code. Replacing that plumbing with equally repetitive callback bookkeeping does not meet the first criterion. Offering alternate parsing, precedence, or composition conventions through escape hatches does not meet the second.
Consumer migrations are expected and may intentionally change configuration syntax. Existing consumer code supplies implementation foundations and evidence of needs; it does not define ConfigKit's compatibility obligations. Once ConfigKit publishes its own contracts, changes to those contracts remain governed by the release policy.
Require representative simple and complex consumer examples to substantiate API designs. Proposed extensions must identify the domain requirement, explain why existing primitives cannot accommodate it cleanly, and show how the extension preserves a coherent model. Application-specific interpretation and validation remain appropriate. Reuse Narratio's applicable infrastructure under these boundaries, and keep simple consumers independent of optional composition features. The consumer adoption guide demonstrates the implemented surface against representative simple and complex shapes.
Responsibility boundaries
ConfigKit owns configuration input processing and the coordination of decoding, resolution, validation, and inspection. Applications own their configuration types, field meanings, defaults, normalization, semantic validation, and schema version policy. Applications also own main-file search conventions, CLI wiring, remote acquisition, runtime initialization, and resource checks.
Library code must not depend on consuming applications or initialize their
runtime resources. It must not perform implicit network access, discover
application-specific paths, or change process-global state during ordinary Load.
The explicit secrets-directory bootstrap is a narrow, opt-in exception: applications
invoke it during startup, and it reports writes, skips and partial failures. It
must never run implicitly as part of configuration loading.
Remote data can enter through application-supplied input without introducing a
network provider into the library.
Public API and dependency direction
Keep one small, coherent public surface for the supported lifecycle. Simple single-document consumers must not need import, profile, or provider machinery. Do not expose parser-specific nodes, errors, or extension hooks through the public API. Parser integration belongs behind a private boundary, as recorded in ADR 0002.
Separate input access, document processing, composition, decoding, metadata, and rendering responsibilities without prescribing an interface or package for each. Dependencies must preserve those boundaries; package splits and abstractions must earn their complexity. Do not impose a full application or hexagonal framework on this library.
Configuration integrity
Composition and intentional overlay are distinct operations. Composition must not silently become last-wins override through file ordering. The decision and alternatives are recorded in ADR 0001.
ConfigKit must define supported YAML semantics explicitly rather than inherit parser defaults. Processing order and diagnostics must be deterministic for the same inputs and options. Invalid input must not produce a successful usable configuration. Do not run application hooks on invalid typed configuration.
User-controlled precedence is application defaults, composed base, selected profile, then explicitly supplied CLI overrides. Applications own flag parsing; ConfigKit owns overlay semantics and provenance. Domain resolution follows these inputs and must remain recorded, not become a hidden override channel.
Preserve node-based composition until the effective input is ready for typed decoding. Preserve presence and source information through processing. Ordinary Go zero values must not be used to infer whether input was absent. Final configuration, metadata, and effective inspection must agree, including application resolution changes; see ADR 0003. Safe historical values and an explanation renderer are part of the implemented contract, including superseded/deleted paths and effective source attribution. Inspection must agree with the final typed snapshot and apply historical sensitivity rules. See ADR 0005. Detailed syntax and operation tables belong to the current configuration contract.
Ownership and confidentiality
Returned configuration and metadata must not share mutable state across loads. ConfigKit must not mutate a result after returning it. Ordinary exported Go values are not language-enforced immutable objects; document caller ownership and the lifetime of captured metadata without promising otherwise.
Secret values enter configuration through typed environment-name references; literal credentials are not a supported configuration convention. Only an explicit accessor exposes a resolved credential to application code. Credential bytes must never enter composition trees, history, or inspection. General environment-variable configuration overlays are an explicit non-goal. Bootstrap must preserve already set variables, including empty ones, and report blocked files without contents. See ADR 0004.
Secrets must be considered throughout error handling and inspection. Library renderers must apply secret classification, and parser errors must not be forwarded blindly when they can include raw input. Do not log configuration implicitly. Applications remain responsible for classifying their secrets and for safe messages supplied by their hooks.
Scope boundaries
Do not introduce automatic directory discovery, network providers, arbitrary merge strategies, additional configuration languages, or application runtime management without concrete consumer evidence and an explicit design decision. The initial target record owns the deferred-feature inventory. Significant boundary changes require an ADR and corresponding policy/contract updates; implementation convenience alone is not a reason to broaden the public API.