Finalize ConfigKit design and implementation plan

This commit is contained in:
2026-09-06 11:48:22 -05:00
parent 18524330fc
commit 9fc272f7a9
14 changed files with 2386 additions and 1116 deletions

View File

@@ -2,29 +2,119 @@
**Base Policy Version:** 1.0
**Last Updated**: 2026-09-06
**Last Updated:** 2026-09-06
## Base Policy Template
## Purpose and applicability
This document is the base template for the canonical architecture policy,. Repositories that implement this policy should:
ConfigKit is an opinionated Go library for consistent YAML configuration loading
and resolution across consuming applications. This policy governs contributions
now; it does not claim that the target features are implemented. The
[component overview](../internal/overview.md) owns implementation inventory and
[initial roadmap](../roadmap/initial.md) owns unimplemented target behavior.
1. Revise this document to include an architectural policy tailored to the implementing repository, including a description of the repository's purpose, overall intended system shape, and any architectural and/or engineering invariants that must be maintained during future development;
2. Ensure that any supporting documents referenced in the architecture policy are present on the filesystem, even if the initial content is simply `TODO`;
3. Update the `Last Updated` field to the current date; and
4. Remove this heading (`Base Policy Template`) and the associated text.
## Success criteria
As compared to other base policy documents, the Architecture Policy is the document that should be most heavily customized and tailored to the intended architecture of a particular application.
1. **Reduce application infrastructure:** Can applications delete substantial
configuration infrastructure while retaining clear ownership of their domain
rules?
2. **Unify configuration conventions:** Do consumers adopt one consistent
configuration model, with only the flexibility needed to express genuine
application requirements?
## Purpose
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.
This policy defines the purpose of this repository and the architectural principles that contributors
must follow during development.
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.
TODO: Complete this document.
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](release.md).
Non-limiting examples of topics that may be addressed by an architectural policy include:
- Adherence to a hexagonal architecture, including whether external integrations/APIs must be encapsulated within internal adapters (strongly recommended)
- Whether a library is intended to provide a highly flexible API that supports a variety of downstream consumers, or a strongly opinionated API that is intended to enforce consistency across downstream consumers
- Whether an application should support a full DAG, or alternatively a strongly ordered sequence of discrete stages
- Whether the application should use specific external libraries to provide key functionality (e.g., FeedKit, ConfigKit, PromptKit)
- Any explicit architectural non-goals
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 API design](../roadmap/initial.md#consumer-api-design)
describes the proposed surface; this policy does not claim it is implemented.
## 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 to load configuration.
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](../adr/0002-own-yaml-semantics.md).
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](../adr/0001-separate-composition-and-overlay.md).
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.
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](../adr/0003-preserve-presence-and-resolution-history.md).
Detailed syntax and operation tables belong to the target roadmap until their
current configuration contract is implemented.
## 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.
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 roadmap owns the complete 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.

View File

@@ -2,170 +2,126 @@
**Base Policy Version:** 1.0
**Last Updated**: 2026-09-06
## Base Policy Template
This document is the base template for the canonical documentation policy. Repositories that implement this policy should:
1. Review the list of documents under the `Canonical Ownership` heading, remove any entries that do not currently apply and are not expected to apply to the current project, and add any additional entries that may be required by the current project;
2. Ensure that each referenced document is present on the filesystem, even if the initial content is simply `TODO`;
3. Update the `Last Updated` field to the current date; and
4. Remove this heading (`Base Policy Template`) and the associated text.
**Last Updated:** 2026-09-06
## Purpose
This policy assigns each documentation topic to one canonical owner. Its goal is
to keep this application's documentation accurate, concise, discoverable, and resistant
to drift for users, operators, developers, integrators, and LLM coding agents.
Assign each documentation topic one canonical owner so ConfigKit's documentation
remains accurate and useful to consumers, maintainers, and implementation agents.
## Core Rules
## Core rules
### One Canonical Owner
### One canonical owner
Each authoritative fact belongs in one document. A non-owning document may give
a short, stable summary for orientation, but it must link to the canonical owner
instead of repeating volatile details.
Each authoritative fact belongs in one owning document or Go declaration's
reference documentation. Other documents may summarize and link to that owner;
they must not maintain competing definitions of commands, API contracts, YAML
semantics, defaults, paths, diagnostics, or compatibility guarantees.
Volatile details include commands, flags, configuration fields and defaults,
module keys, schemas, file names, paths, status codes, retry behavior, and
runtime guarantees. If readers could reasonably treat a statement as a
contract, maintain it only in the owning document.
### Policies, current behavior, and future work
### Current And Future Behavior
- Policies state currently binding contributor rules, including constraints on
future implementation. They do not imply that features already exist.
- Current API/configuration contracts, consumer guidance, and component
documentation describe implemented behavior only, including partial boundaries.
- ADRs record accepted decisions and rationale. Acceptance is not evidence of
implementation; execution status belongs in roadmaps.
- Roadmaps own unimplemented targets, deferred work, and execution status.
Outside `docs/roadmap/`, documentation describes implemented behavior only.
Partial features may be described only to their implemented boundary.
The initial target and implementation plan have separate owners. Do not put
staged steps or progress in `docs/roadmap/initial.md`. The future
`docs/roadmap/implementation.md` will own those details when it is created.
As behavior lands, move its normative definition into the current contract and
replace the roadmap definition with a link. Retire completed roadmap material
as part of release preparation; ADRs preserve significant decision history.
ADRs are the narrow exception: an ADR may record an accepted architectural
decision before implementation, but acceptance must not be presented as proof
that the behavior exists. The roadmap owns implementation status and sequencing
until the decision is implemented. Current architecture, user, operator,
integration, and internal documentation are updated when the behavior lands.
### Audience and examples
### Audience And Detail
Consumer documentation explains how to use the library and what consumers own.
Internal documents explain mechanisms and dependencies. Keep implementation
mechanics out of consumer guidance unless they affect a meaningful choice.
Write for the document's stated audience and include only the detail needed for
its owned topic. User and operator docs should not expose implementation detail.
Developer docs should link to user-facing and external contracts rather than
restate them.
Complete copyable artifacts belong in `examples/`; Go API examples may live in
executable Go example tests beside the relevant package. Prose should use the
smallest useful excerpt and link to the maintained artifact. Examples must be
secret-free and checked against implemented behavior. Clearly label illustrative
future syntax in roadmaps; do not present it as a runnable current example.
### Examples
### Security and privacy
Complete copyable files belong in `examples/`. Documentation may use the
smallest illustrative snippet needed to explain its owned topic, but should link
to maintained examples instead of embedding a second complete copy.
Do not include real credentials, private keys, environment dumps, sensitive input,
or private infrastructure details unless intentionally public. Document secret
handling, not secret values.
Examples must be valid, secret-free, and tested where practical. Commands and
configuration used in documentation should match the application.
## Canonical ownership
### Security And Privacy
| Topic | Owner | Boundary |
| --- | --- | --- |
| Product orientation | `README.md` | Current status, purpose, navigation, and a minimal working example once available |
| Contributor entry point | `docs/development.md` | Reading guide and actual baseline validation commands |
| Architecture rules | `docs/policy/architecture.md` | Responsibilities, dependency constraints, invariants, and scope boundaries |
| Documentation rules | `docs/policy/documentation.md` | Ownership and document lifecycle |
| Testing rules | `docs/policy/testing.md` | Risk-based sufficiency, test boundaries, and maintenance principles |
| Release rules | `docs/policy/release.md` | Compatibility, integrity, gates, immutability, and exceptions |
| Release procedure | `docs/release.md`, when operational | Exact maintainer commands, prerequisites, supported targets, and verification |
| Exported Go API | Go documentation beside declarations | Symbol contracts, errors, ownership, and lifecycle API behavior |
| YAML and resolution semantics | `docs/config.md`, as behavior lands | Syntax, composition, precedence, conversion, and metadata semantics; Go reference docs link here for shared rules |
| Consumer walkthroughs | `docs/consumers/`, when useful | Task-oriented usage and consumer responsibilities, not duplicate API reference |
| Component inventory | `docs/internal/overview.md` | Implemented components and links to their owners |
| Component mechanics | Other `docs/internal/` files, when needed | Detailed implementation behavior and change recipes |
| Architectural decisions | `docs/adr/` | Context, decisions, alternatives, consequences, and supersession history |
| Initial target | `docs/roadmap/initial.md` | Unimplemented end-state and deferred feature scope |
| Implementation plan | Future `docs/roadmap/implementation.md` | Stages, dependencies, acceptance gates, and progress |
| Release readiness gaps | `docs/roadmap/release-readiness.md` | Outstanding release prerequisites and closure evidence |
| Historical release notes | `docs/releases/` | Version-specific historical summaries required by release policy |
| Complete examples | `examples/` and executable Go examples | Maintained artifacts; prose links instead of duplicating full examples |
Documentation and examples must not contain real credentials, private keys,
private environment dumps, sensitive source material, or private infrastructure
details unless intentionally public. Document secret-handling mechanisms, not
secret values.
A listed future owner is not a requirement to create an empty file now. Create
API, consumer, example, and component documents when the corresponding behavior
exists and there is useful content to own. Link only to existing files; use plain
code paths for planned files. Release prerequisites have the explicit temporary
exception recorded in the release policy.
## Canonical Ownership
ConfigKit has no owned HTTP service, application CLI, or runtime operations
interface. Do not create those reference documents for consuming applications.
| Topic | Canonical owner | Owned content | Content owned elsewhere |
| --- | --- | --- | --- |
| Product orientation and minimal end-to-end quickstart | `README.md` | What this application is, why it is useful, one shortest successful invocation, and links onward. | Complete command reference, configuration reference, operational procedures, implementation detail. |
| Contributor entry point | `docs/development.md` | Task-oriented reading guide, minimal contributor orientation, baseline validation commands, and links to canonical docs. | Package inventory, architecture rules, subsystem behavior, detailed change recipes. |
| Application architecture policy | `docs/policy/architecture.md` | System shape, normative ownership, dependency direction, architectural boundaries, invariants, safety properties, and non-goals. | Concrete package inventory, implementation mechanics, contributor procedures, decision history, future work. |
| Documentation policy | `docs/policy/documentation.md` | Documentation ownership, audience boundaries, maintenance rules, and ADR/document lifecycle. | Application architecture or product behavior. |
| Testing policy | `docs/policy/testing.md` | Test philosophy, risk-based sufficiency, test boundaries, doubles, coverage guidance, regression-test policy, and criteria for adding, rewriting, or deleting tests. | Subsystem behavior, application contracts, subsystem-specific test inventories, and implementation plans. |
| Release policy | `docs/policy/release.md` | Versioning and compatibility rules, release integrity and immutability requirements, release-documentation policy, required gates, publication controls, verification requirements, and exception policy. | Repository-specific commands, product installation guidance, CLI version semantics, historical release summaries, and CI implementation detail. |
| Repository-specific release procedure | `docs/release.md` | Maintainer prerequisites, candidate preparation, concrete validation and publication commands, repository and registry guards, deliverable publication, consumer-facing verification, and failure recovery. | General release requirements, product installation guidance, historical release summaries, and current compatibility contracts. |
| CLI contract (if applicable) | `docs/cli.md` | Commands, arguments, flags, invocation semantics, and exit codes. | End-to-end operating procedures, configuration field definitions, runtime filesystem layout, module implementation details. |
| Configuration contract (if applicable) | `docs/config.md` | Discovery and precedence, file schema, fields, defaults, environment overrides, validation rules, and user-selectable module or validator keys. | Complete example files, CLI syntax, runtime state lifecycle, module implementation details. |
| Operations (if applicable) | `docs/operations.md` | Runtime workflows, physical filesystem and state layout, output, cache, and debug handling, resume, cleanup, permissions, recovery, and operational limits. | CLI flag syntax, configuration field definitions, logical output schemas, implementation mechanics. |
| Public HTTP contract (if applicable) | `docs/api.md` | Routes, authentication, media types, request and response schemas, status codes, pagination, caching, idempotency, rate limits, and HTTP retry semantics. | Client walkthroughs, upstream or downstream integration internals, implementation detail. |
| Consumer guidance for the public Go API (if applicable) | `docs/consumers/` | Task-oriented use of the public interface, minimal client examples, and consumer responsibilities. | HTTP wire semantics, external protocol contracts, internal implementation detail. |
| Integration contracts for external components (if applicable) | `docs/integrations/` | External file formats and protocols, upstream and downstream contracts, logical output bundle paths and schemas, media types, and compatibility behavior. | Physical runtime placement and lifecycle, internal transformations, CLI syntax, configuration defaults. |
| Inventory of implemented internal packages | `docs/internal/overview.md` | Current packages and components, their implemented responsibilities, and links to focused internal docs. | Normative architecture, contributor reading policy, external contracts. |
| Behavior and architecture of internal packages | Other files under `docs/internal/` | Implementation flow, internal collaborators and state transitions, package-local guarantees and failures, and relevant tests. | Global architecture invariants, configuration definitions and defaults, external schemas, operator procedures. |
| Architectural decision records | `docs/adr/` | Significant decisions, context, alternatives, rationale, consequences, and supersession history. | Current behavior reference, implementation status, task sequencing. |
| Future work and implementation status | `docs/roadmap/` | Proposed, accepted, deferred, or rejected work; implementation status; sequencing; and task breakdowns. | Implemented behavior reference and architectural decision rationale. |
| Release-note history | `docs/releases/` | One checked-in historical summary for each source release made under the procedure. The note at the immutable tag is that release's record. | Current commands, behavior, contracts, and compatibility definitions. |
| Complete copyable artifacts | `examples/` | Maintained configuration, inputs, and other files intended to be copied or run. | Field-by-field reference, command reference, prose explanation. |
## Boundary rules
Documents that do not exist are required only when the corresponding interface
or responsibility exists. Do not create placeholder API, consumer, integration,
or operations documents for behavior the application does not have.
Architecture owns governing constraints; ADRs explain why; contracts describe
implemented semantics; internal documentation explains how. A roadmap may link
to all of them but must not become a second current reference.
## Boundary Rules
Release policy owns guarantees; the release procedure owns commands. A release
note cannot redefine a compatibility contract or replace a current-documentation
update. The note at an immutable tag is that release's historical record.
### Orientation
This policy owns what documentation may disclose. Architecture owns security
invariants. Current configuration and Go API contracts own secret-classification
and rendering behavior when implemented; internal docs own their mechanisms.
The README owns product orientation. The developer guide routes contributors.
Architecture owns normative structure. Internal overview owns the current
concrete component map. These documents may link to one another but should not
maintain parallel package or behavior descriptions.
## Architectural decision records
### Commands, Configuration, And Operations
Use sequential filenames, such as `0001-separate-composition-and-overlay.md`,
and the lightweight Nygard structure: title, status, date, context, decision,
alternatives considered, and consequences.
CLI documentation answers how to invoke the application. Configuration
documentation answers what settings mean. Operations answers what happens to
runtime state and how to operate or recover the application. When a workflow
crosses these topics, choose the document that owns the task and link to the
other contracts.
Accepted decision content is immutable. A changed decision requires a new ADR
and a superseded status/link in the old one. Navigation links may be repaired
when specification ownership moves without rewriting historical rationale.
Rejected architectural alternatives belong in ADRs; deferred or rejected product
features belong in roadmaps. Do not create an ADR for every routine choice.
### Releases
## Maintenance and verification
The release policy defines requirements and invariants that every release must
satisfy. The repository-specific release procedure defines the commands and
workflow maintainers use to satisfy that policy. Release notes are immutable
historical summaries, not current-state contract owners: the checked-in note at
an immutable tag records that release, while current canonical documentation
must change with the behavior it describes. Do not use a release procedure or
release note to weaken policy, redefine current behavior, or defer required
documentation updates.
### Contracts And Implementation
Integration and API documents define externally observable shapes and
semantics. Internal documents explain how this application implements or consumes those
contracts. Internal docs may name a field, file, or protocol to identify a
dependency, but must link to its canonical contract for the definition.
### Security Topics
This policy owns what documentation and examples may contain. Architecture owns
application security invariants. Configuration owns credential-supply
mechanisms. Operations owns permissions and handling of sensitive runtime
artifacts. Internal docs own implementation mechanisms only.
## Architecture Decision Records
Use sequentially numbered ADR filenames such as
`0001-record-architecture-decisions.md`. Follow the lightweight Nygard format:
1. title;
2. status;
3. date;
4. context;
5. decision;
6. alternatives considered;
7. consequences.
Treat the decision content of an accepted ADR as immutable. When a decision
changes, create a new ADR and update the earlier ADR's status to superseded.
Rejected architectural alternatives belong in the ADR; rejected product ideas
belong in the roadmap.
## Maintenance
When behavior changes, update its canonical owner in the same change. If
ownership moves, remove the old definition and replace it with a link where
navigation remains useful.
Update the owning current documentation in the same change that implements or
changes behavior. When ownership moves, remove the old definition and preserve
useful navigation links.
Before completing documentation work:
- verify affected behavior and examples;
- check commands, flags, fields, defaults, schemas, and paths against their
implementation;
- keep unimplemented behavior in the roadmap, subject to the ADR exception;
- remove stale references and validate links;
- confirm that non-owning documents summarize and link rather than redefine;
- confirm that no secrets or sensitive private data were added.
- verify claims against the implementation or clearly identify future design;
- check changed local links, paths, fragments, examples, and commands;
- preserve the distinction between policy, decisions, target behavior, and status;
- check canonical ownership and remove stale or duplicate definitions;
- inspect formatting and whitespace;
- ensure no sensitive data was introduced.

View File

@@ -2,30 +2,7 @@
**Base Policy Version:** 0.1.0
**Last Updated**: 2026-09-06
## Base Policy Template
This document is the base template for the canonical release policy.
Repositories that implement this policy should:
1. Retain the substantive requirements of this policy unless a documented
repository constraint requires an exception;
2. Define the repository-specific release procedure, validation commands,
supported deliverables, and verification commands in `docs/release.md`;
3. Ensure that every document and script required by the adopted policy and
procedure is present on the filesystem;
4. Add stricter repository-specific requirements where the product, delivery
channels, or threat model require them;
5. Record every exception under `Policy Exceptions`, including its rationale
and compensating controls;
6. Update the `Last Updated` field to the current date; and
7. Remove this heading (`Base Policy Template`) and the associated text.
The base policy is a standard, not a collection of optional recommendations.
An implementing repository should customize its release mechanics without
silently weakening the common integrity, validation, documentation,
verification, or immutability guarantees below.
**Last Updated:** 2026-09-06
## Purpose
@@ -38,6 +15,26 @@ The repository-specific commands that implement these requirements belong in
`docs/release.md`. Historical release summaries belong in `docs/releases/`.
Neither document may weaken this policy.
## ConfigKit applicability
ConfigKit adopts a source-only Go module release model. The source tag and
version-matched release note are the declared deliverables. Standalone binaries,
container images, and separate binary/package-registry publication are not
required. This does not waive source compilation, module hygiene, testing, or
consumer-facing module retrieval and build verification.
The release procedure must define the module path, authoritative remote,
supported Go versions and operating-system/architecture targets, prerequisite
dependency acquisition, and the exact verification commands once established.
The default tests themselves remain deterministic and offline. Additional
publication channels require documented deliverables and verification before use.
The Go API, documented YAML/resolution semantics, and structured diagnostic
contracts all participate in compatibility review. A signature-preserving change
can still break consumers. Human diagnostic wording is stable only where a
contract expressly promises it. Minimum Go version and platform support changes
also require an explicit compatibility assessment.
## Release Model
A release consists of:
@@ -111,7 +108,7 @@ This release ...
## Changes
```
Use an explicit statement such as "No action required" when a section has no
Use an explicit statement such as "No action required" when a section has no
substantive content.
Release notes are immutable historical summaries. They should link to current
@@ -138,7 +135,7 @@ The required gates are:
- validation of maintained examples, configuration, schemas, generated
sources, and documentation commands where applicable;
- review of changed local documentation links;
- removal of obsolute roadmap documents under `docs/roadmap/` that describe
- removal of obsolete roadmap documents under `docs/roadmap/` that describe
completed work included in the release;
- review for unintended files, generated output, credentials, private data,
and unrelated changes; and
@@ -220,3 +217,22 @@ name the primary branch, authoritative remote, tag form, published
deliverables, supported build targets, release automation responsibilities,
and consumer verification path. It must link to this policy instead of
restating or redefining its requirements.
## Policy Exceptions
### Temporary bootstrap deferral
The release procedure (`docs/release.md`) and complete release-check command are
not yet present because ConfigKit has no Go module or implementation to validate.
Their creation is temporarily deferred during initial development. This exception
permits implementation work; it does not permit publishing a release without
any gate required above.
Compensating controls: no release may be published until the
[release-readiness gaps](../roadmap/release-readiness.md) are closed, the runbook
and checker exist, and the exact candidate passes all applicable gates. The
maintainer preparing the first release owns closure. Remove this temporary
exception when readiness is verified. Any other exception requires a documented repository constraint, rationale,
compensating controls, scope, and closure condition here; none is currently
adopted. Do not silently weaken the base integrity, validation, documentation,
verification, or immutability guarantees.

View File

@@ -2,17 +2,7 @@
**Base Policy Version:** 1.0
**Last Updated**: 2026-09-06
## Base Policy Template
This document is the base template for the canonical testing policy,. Repositories that implement this policy should:
1. Review the policy, remove any rules that must not apply to the current project, and add any additional rules that are required by the current project;
2. Update the `Last Updated` field to the current date; and
3. Remove this heading (`Base Policy Template`) and the associated text.
Most projects will not require any revisions to the substantive testing policy rules as written below.
**Last Updated:** 2026-09-06
## Purpose
@@ -20,6 +10,29 @@ Our tests exist to make **incorrect changes expensive and correct changes cheap*
We do not optimize for test count, line coverage, exhaustive isolation, or the fewest possible tests. We optimize for sufficient confidence in important behavior while imposing as little unnecessary friction as possible on future development.
## ConfigKit-specific priorities
Configuration semantics are compatibility contracts, even when Go signatures do
not change. Apply the risk rules below especially to presence/default behavior,
composition, provenance, and error classification. Keep detailed behavior cases
with their owning contracts and tests rather than duplicating them in this policy.
Use real temporary files for import traversal, symlinks, and source identity.
Document platform prerequisites for filesystem cases and make any unsupported
case explicit rather than silently dropping its coverage. Use labeled in-memory
input where filesystem behavior is irrelevant.
Verify agreement among final resolved values, presence, provenance, and effective
rendering. Protect against secret disclosure on both successful inspection and
failure paths, and against mutable defaults or results leaking across loads.
Use focused fuzzing for parser boundaries and semantic/filesystem path handling;
keep deterministic seed regressions in the ordinary suite. Extended fuzz runs
need a documented bounded invocation when introduced.
Baseline commands belong in the [development guide](../development.md). Release
gates belong in the [release policy](release.md) and its eventual runbook. This
policy does not imply that those tools or tests already exist.
## Every test has a cost
Testing is not an unqualified good. Every test imposes both an immediate cost and a continuing lifetime cost.
@@ -59,7 +72,8 @@ Use a **classical/Detroit-style** approach:
- Prefer package-level behavioral tests over tests coupled to private helpers or internal call sequences.
- Treat exact collaborator interactions as testable behavior only when the interaction itself is a requirement.
Examples of appropriate seams include clocks, randomness, subprocesses, remote APIs, object storage, email, and paid LLM calls.
For ConfigKit, controlled input readers and filesystem failures are useful seams.
Prefer actual parsing, composition, and decoding over mocks of their call order.
## Test execution requirements
@@ -176,13 +190,15 @@ Use a test-controlled limit and measure the behavior relative to that limit. Do
Each behavior should have a clear test owner.
- Parser tests own parsing cases.
- Validator tests own validation rules.
- Domain tests own transformations and invariants.
- Adapter tests own external integration behavior.
- Orchestrator tests own coordination and failure propagation.
- CLI tests own argument and configuration mapping.
- End-to-end tests prove that representative assembled workflows work.
- YAML boundary tests own syntax and policy enforcement.
- Composition and overlay tests own their operation semantics.
- Decoding tests own type binding, defaults, and strictness.
- Metadata and rendering tests own provenance queries and safe inspection.
- Filesystem tests own source access and import identity behavior.
- Lifecycle tests own hook ordering, failure propagation, and representative
agreement across the assembled configuration pipeline.
These are responsibility boundaries, not a required package layout.
Higher-level tests should not repeat every lower-level case. A single intentional policy change should not require unrelated edits across many test files.
@@ -215,7 +231,6 @@ Use:
- table-driven tests for meaningful behavioral categories and boundaries;
- `t.TempDir()` for real filesystem behavior;
- `httptest.Server` for realistic HTTP interactions;
- fuzz tests for parsers, normalization, path handling, and broad input spaces;
- golden files only when the complete output is intentionally stable;
- integration tests where correctness depends on component interaction; and
@@ -223,7 +238,8 @@ Use:
Avoid exact error-string assertions unless the wording is itself contractual. Prefer `errors.Is`, `errors.As`, typed errors, or structured error fields.
At CLI boundaries, prefer exit classifications, structured output, and the smallest stable semantic fragment needed to identify the error. Do not snapshot complete diagnostic wording unless it is contractual.
At the public library boundary, prefer diagnostic codes, paths, and source
locations over complete message snapshots. Assert wording only when contractual.
Golden-file updates must require an explicit local flag. CI must not update golden files automatically, and reviewers must inspect the semantic diff before accepting an update.
@@ -235,7 +251,7 @@ Coverage is a diagnostic, not a target.
Use it to find untested critical branches and unexpectedly weak packages. Do not write low-value tests solely to increase a percentage, and do not infer test quality from coverage alone.
Pure domain logic will often warrant higher coverage than CLI wiring or external adapters. Uneven coverage is acceptable when it reflects risk.
Dense configuration semantics will often warrant higher coverage than simple input wiring. Uneven coverage is acceptable when it reflects risk.
Increasing coverage is valuable only when the newly covered behavior protects a meaningful risk at an acceptable cost.
@@ -303,7 +319,7 @@ A test suite is sufficient when:
- legitimate internal changes usually do not require test edits; and
- additional tests would mostly repeat existing protection or preserve inconsequential implementation details.
Sufficiency is a risk judgment, not a coverage percentage or test count. Reassess it as the application, its users, and the consequences of failure evolve.
Sufficiency is a risk judgment, not a coverage percentage or test count. Reassess it as the library, its consumers, and the consequences of failure evolve.
The governing rule is: