Prepare source release validation

This commit is contained in:
2026-09-06 22:47:12 +00:00
parent 2836f825b6
commit f42ecc70c3
21 changed files with 721 additions and 1205 deletions

View File

@@ -2,7 +2,7 @@
An opinionated Go library for applications that use YAML configuration files. An opinionated Go library for applications that use YAML configuration files.
ConfigKit is in early implementation. Its current loader accepts one strict YAML ConfigKit's initial loader accepts one strict YAML
source (or explicit defaults-only input), optionally traverses explicit path and glob source (or explicit defaults-only input), optionally traverses explicit path and glob
imports, strictly composes their disjoint definitions, applies typed defaults, and imports, strictly composes their disjoint definitions, applies typed defaults, and
can overlay one selected fixed profile and check an application schema version. It can overlay one selected fixed profile and check an application schema version. It
@@ -33,6 +33,9 @@ func ReadConfig(path string) (Config, error) {
The [configuration contract](docs/config.md) describes implemented behavior. The The [configuration contract](docs/config.md) describes implemented behavior. The
[consumer adoption guide](docs/consumers/README.md) provides maintained Narratio-, [consumer adoption guide](docs/consumers/README.md) provides maintained Narratio-,
Notarius-, WeatherReporter-, and Seriatim-shaped examples and migration guidance. Notarius-, WeatherReporter-, and Seriatim-shaped examples and migration guidance.
The [initial target design](docs/roadmap/initial.md) describes planned behavior. The [initial target record](docs/roadmap/initial.md) links implemented feature owners
The [implementation plan](docs/roadmap/implementation.md) owns the pending stages. and preserves deliberately deferred scope. The [implementation plan](docs/roadmap/implementation.md)
See the [development guide](docs/development.md) for repository orientation. records completion evidence until release-candidate preparation retires it. See the
[development guide](docs/development.md) for repository orientation and the
[release procedure](docs/release.md) for maintainer-only candidate and publication
steps.

View File

@@ -20,8 +20,8 @@ Use distinct strict-composition and intentional-overlay operations. Composition
rejects conflicting definitions; overlay provides explicit precedence. Keep the rejects conflicting definitions; overlay provides explicit precedence. Keep the
operations opinionated rather than adding arbitrary per-field merge strategies. operations opinionated rather than adding arbitrary per-field merge strategies.
The [architecture policy](../policy/architecture.md) owns the governing boundary; The [architecture policy](../policy/architecture.md) owns the governing boundary;
the [target design](../roadmap/initial.md#composition-and-overlay) owns the planned the [current configuration contract](../config.md#strict-document-composition) owns
operation table until its current contract lands. the operation table and selected-profile overlay behavior.
## Alternatives considered ## Alternatives considered

View File

@@ -20,7 +20,8 @@ ConfigKit defines its supported YAML policy and keeps parser integration private
Application types and diagnostics must not require parser-specific public types. Application types and diagnostics must not require parser-specific public types.
Use a small internal boundary rather than a general parser/provider framework. Use a small internal boundary rather than a general parser/provider framework.
The [architecture policy](../policy/architecture.md) owns this constraint; the The [architecture policy](../policy/architecture.md) owns this constraint; the
[target design](../roadmap/initial.md#yaml-and-scalar-policy) owns planned syntax. [current YAML document](../config.md#yaml-documents) and
[scalar](../config.md#scalars) contracts own the implemented syntax.
## Alternatives considered ## Alternatives considered

View File

@@ -22,8 +22,9 @@ values. Keep application defaults and normalization application-owned, but recor
resolution changes so final inspection and metadata describe the actual resolved resolution changes so final inspection and metadata describe the actual resolved
snapshot. Do not promise language-enforced immutability of exported Go values. snapshot. Do not promise language-enforced immutability of exported Go values.
The [architecture policy](../policy/architecture.md) owns these invariants; the The [architecture policy](../policy/architecture.md) owns these invariants; the
[target design](../roadmap/initial.md#recorded-resolution-and-validation) owns the [current resolution contract](../config.md#recorded-application-resolution) and
planned recording mechanism and ownership semantics. [ownership contract](../config.md#typed-projection-and-ownership) own the implemented
recording mechanism and ownership semantics.
## Alternatives considered ## Alternatives considered

View File

@@ -21,8 +21,9 @@ Existing environment variables win even when empty. Report skipped files and
partial failures without values. Keep bootstrap provenance separate from later partial failures without values. Keep bootstrap provenance separate from later
lookup provenance rather than imply an unchanged environment between calls. lookup provenance rather than imply an unchanged environment between calls.
General environment-variable configuration overlays are not on the roadmap. General environment-variable configuration overlays are not on the roadmap.
The [feature roadmap](../roadmap/initial.md#secret-references-and-explicit-bootstrap) The [current reference contract](../config.md#typed-secret-references) and
owns the unimplemented contract; stages remain in the implementation plan. [bootstrap contract](../config.md#explicit-secrets-directory-bootstrap) own the
implemented behavior.
## Alternatives considered ## Alternatives considered

View File

@@ -19,8 +19,9 @@ node tree before typed decoding, retaining the existing parser adapter boundary.
Recorded domain resolution follows input selection. Provide safe structured Recorded domain resolution follows input selection. Provide safe structured
historical values and an explanation renderer in the initial release, building historical values and an explanation renderer in the initial release, building
on ADR 0003's presence and audited resolution decision. Applications own commands. on ADR 0003's presence and audited resolution decision. Applications own commands.
The [feature roadmap](../roadmap/initial.md#cli-overrides) owns the exact override The [current override contract](../config.md#explicit-cli-overrides) and
contract and [explanation contract](../roadmap/initial.md#historical-value-explanation). [explanation contract](../config.md#historical-value-explanation) own the implemented
behavior.
## Alternatives considered ## Alternatives considered

View File

@@ -567,7 +567,7 @@ executes application methods or parser-specific hooks.
Exported struct fields use an explicit `yaml` name or the lowercase Go field name. Exported struct fields use an explicit `yaml` name or the lowercase Go field name.
Unexported fields and `yaml:"-"` are ignored. `omitempty` is accepted but does not Unexported fields and `yaml:"-"` are ignored. `omitempty` is accepted but does not
change binding or future projection. An explicit `yaml:",inline"` flattens a struct change binding or projection. An explicit `yaml:",inline"` flattens a struct
or pointer-to-struct, or designates at most one string-keyed inline map for otherwise or pointer-to-struct, or designates at most one string-keyed inline map for otherwise
unmatched names. Ambiguous names, named inline fields, multiple inline maps, and unmatched names. Ambiguous names, named inline fields, multiple inline maps, and
unsupported or malformed tag options are schema errors. Embedded fields are ordinary unsupported or malformed tag options are schema errors. Embedded fields are ordinary
@@ -673,7 +673,7 @@ any sequence change reports the sequence path and never invents correspondence
between old and new indices. Cross-kind and null/container changes replace the between old and new indices. Cross-kind and null/container changes replace the
affected path. affected path.
These mechanisms currently support later decoding, resolution auditing, metadata, These mechanisms support decoding, resolution auditing, metadata,
and rendering. They are not a public generic conversion or cloning API. and rendering. They are not a public generic conversion or cloning API.
## Safe failures ## Safe failures

View File

@@ -81,9 +81,9 @@ WeatherReporter, or Seriatim. Updating those repositories, their deployed YAML,
wiring, runtime catalogs, and operational documentation remains separate downstream wiring, runtime catalogs, and operational documentation remains separate downstream
work. work.
## Maintained roadmap examples ## Maintained API examples
Every nontrivial API sketch from the feature roadmap has a compiled example or a Every nontrivial initial API sketch has a compiled example or a
focused behavioral owner: focused behavioral owner:
| Roadmap surface | Maintained owner | | Roadmap surface | Maintained owner |

View File

@@ -1,7 +1,7 @@
# Development # Development
This is the contributor entry point for ConfigKit. Read the task-specific owners This is the contributor entry point for ConfigKit. Read the task-specific owners
below before making changes. The repository is in early implementation: its public below before making changes. Its public
loader currently covers strict selected sources, explicit path/glob import graphs, loader currently covers strict selected sources, explicit path/glob import graphs,
composition, selected profile overlays, typed defaults, schema-version checks, composition, selected profile overlays, typed defaults, schema-version checks,
explicit CLI overrides, recorded application resolution, semantic validation, explicit CLI overrides, recorded application resolution, semantic validation,
@@ -23,10 +23,10 @@ redacted effective rendering and historical value explanation. The
| --- | --- | | --- | --- |
| Repository orientation or component responsibility | [Architecture policy](policy/architecture.md) and [component overview](internal/overview.md) | | Repository orientation or component responsibility | [Architecture policy](policy/architecture.md) and [component overview](internal/overview.md) |
| Documentation changes | [Documentation policy](policy/documentation.md) and the owning document | | Documentation changes | [Documentation policy](policy/documentation.md) and the owning document |
| Architecture decisions or future work | [Documentation policy](policy/documentation.md), [initial target design](roadmap/initial.md), and relevant ADRs listed below | | Architecture decisions or future work | [Documentation policy](policy/documentation.md), [initial target record](roadmap/initial.md), and relevant ADRs listed below |
| Code and test changes | [Architecture policy](policy/architecture.md), [testing policy](policy/testing.md), and owning contracts/tests as they are introduced | | Code and test changes | [Architecture policy](policy/architecture.md), [testing policy](policy/testing.md), and owning contracts/tests as they are introduced |
| Examples or copyable assets | The owning implemented contract and [consumer adoption guide](consumers/README.md) | | Examples or copyable assets | The owning implemented contract and [consumer adoption guide](consumers/README.md) |
| Release preparation | [Release policy](policy/release.md) and [release-readiness gaps](roadmap/release-readiness.md); the operational runbook will be added before release | | Release preparation | [Release policy](policy/release.md), [release procedure](release.md), and [release-readiness evidence](roadmap/release-readiness.md) |
Accepted decisions: Accepted decisions:

View File

@@ -28,8 +28,8 @@ the owning implementation work extracts a symbol or case.
- Use sanitized local fixtures only. Audio, transcripts, credentials, private - Use sanitized local fixtures only. Audio, transcripts, credentials, private
configuration, and whole application package trees are application-only. configuration, and whole application package trees are application-only.
- Record the exact copied/generalized symbols and tests in the owning section when - Record the exact copied/generalized symbols and tests in the owning section when
extraction occurs. An entry below assigns evidence; it does not claim extraction extraction occurs. Assignment prose records the original work boundary; dated
or behavior is implemented. implementation records state what was actually generalized.
## Narratio evidence ## Narratio evidence
@@ -86,8 +86,8 @@ collection, conflict construction, and recursive mapping join in `compose.go` ad
the assigned production symbols. `TestComposeDocumentsJoinsDisjointMappingsAndTracksClaims`, the assigned production symbols. `TestComposeDocumentsJoinsDisjointMappingsAndTracksClaims`,
`TestComposeDocumentsRejectsEveryPresentNonMappingOverlap`, and `TestComposeDocumentsRejectsEveryPresentNonMappingOverlap`, and
`TestComposeDocumentsReportsAllClaimantsAtExactLocations` adapt the assigned cases. `TestComposeDocumentsReportsAllClaimantsAtExactLocations` adapt the assigned cases.
The planned empty-mapping difference is covered separately: empty mappings retain The intentional empty-mapping difference is covered separately: empty mappings retain
container provenance but contribute no child claims. No unplanned semantic deviation container provenance but contribute no child claims. No other semantic deviation
from the extracted additive composer was required. from the extracted additive composer was required.
### Imports ### Imports
@@ -122,9 +122,9 @@ declaration-order, disjoint composition, keyed-entry, all-source conflict, unsaf
target, alias, imported parse/schema, and relative-resolution cases. ConfigKit adds target, alias, imported parse/schema, and relative-resolution cases. ConfigKit adds
recursive bounded DFS, `os.OpenRoot` confinement, canonical symlink identity, recursive bounded DFS, `os.OpenRoot` confinement, canonical symlink identity,
cycle/diamond route locations, optional-path semantics, aggregate budgets, and cycle/diamond route locations, optional-path semantics, aggregate budgets, and
fragment version-placement enforcement. The planned glob syntax is parsed but fragment version-placement enforcement. That checkpoint parsed glob syntax behind an
remains explicitly unavailable for its next owning work; hard links intentionally explicit unsupported gate that the subsequent glob implementation removed; hard
replace Narratio's same-file rejection with path identity. links intentionally replace Narratio's same-file rejection with path identity.
Glob-import implementation record (2026-09-06): ConfigKit retains the extracted Glob-import implementation record (2026-09-06): ConfigKit retains the extracted
declaration order, import failures, composition, and identity cases while adding the declaration order, import failures, composition, and identity cases while adding the
@@ -133,7 +133,7 @@ new `expandImportGlob`, `readGlobMatches`, and pattern-validation mechanisms in
directories, hard links, contained and escaping symlinks, unmatched declarations, directories, hard links, contained and escaping symlinks, unmatched declarations,
malformed and recursive patterns, escaped metacharacters, character classes, malformed and recursive patterns, escaped metacharacters, character classes,
permission failures, explicit `conf.d` use, and entry/candidate budgets. This work permission failures, explicit `conf.d` use, and entry/candidate budgets. This work
has no Narratio production equivalent; it uses the planned standard-library has no Narratio production equivalent; it uses the selected standard-library
`path.Match` and bounded `File.ReadDir` adaptation rather than its flat loader. `path.Match` and bounded `File.ReadDir` adaptation rather than its flat loader.
### Profiles and overlay ### Profiles and overlay
@@ -199,8 +199,8 @@ inspection cases across one default/import/profile/resolution workflow. ConfigKi
adds chronological descendant history for parent and whole-sequence operations, adds chronological descendant history for parent and whole-sequence operations,
composite empty-mapping origins, canonical resolution reasons/dependencies, private composite empty-mapping origins, canonical resolution reasons/dependencies, private
snapshot agreement, defensive nested copies, and concurrent load isolation. Value snapshot agreement, defensive nested copies, and concurrent load isolation. Value
rendering, redaction, explanation, commands, generated attribution, diffs, and That checkpoint deliberately left rendering, redaction, explanation, commands,
digests remain assigned to their later owning work. generated attribution, diffs, and digests outside its scope.
Effective-rendering implementation record (2026-09-06): ConfigKit adapts Narratio's Effective-rendering implementation record (2026-09-06): ConfigKit adapts Narratio's
deterministic effective-output and side-effect-free inspection cases in deterministic effective-output and side-effect-free inspection cases in
@@ -212,7 +212,8 @@ resolved values, text-scalar snapshot reuse, application YAML-hook isolation,
non-disclosure through failures and record formatting, caller mutation, and writer non-disclosure through failures and record formatting, caller mutation, and writer
failures. Unlike Narratio's marshal/reparse path, ConfigKit renders only its owned failures. Unlike Narratio's marshal/reparse path, ConfigKit renders only its owned
frozen tree and substitutes redaction before the upstream dumper boundary. Historical frozen tree and substitutes redaction before the upstream dumper boundary. Historical
value explanation and secret references remain assigned to later work. value explanation and secret references were implemented at their later owning
boundaries and are exercised by the consumer startup example below.
### Defaults, presence, and domain resolution ### Defaults, presence, and domain resolution

View File

@@ -20,17 +20,17 @@ module and package documentation boundary. Its implemented public primitives are
- a per-operation private reflection descriptor graph in `schema.go` for supported - a per-operation private reflection descriptor graph in `schema.go` for supported
types, YAML field binding, inlining, secret tags, recursion, and semantic paths; types, YAML field binding, inlining, secret tags, recursion, and semantic paths;
- descriptor-driven canonical projection, detached typed cloning, cycle/limit - descriptor-driven canonical projection, detached typed cloning, cycle/limit
enforcement, and structural comparison in `projection.go`; and enforcement, and structural comparison in `projection.go`;
- strict schema-driven decoding over detached defaults in `decode.go`, including - strict schema-driven decoding over detached defaults in `decode.go`, including
mapping/sequence semantics, null and numeric policy, safe codec errors, presence, mapping/sequence semantics, null and numeric policy, safe codec errors, presence,
baseline/final trees, and initial default/input origins; and baseline/final trees, and initial default/input origins;
- public lifecycle coordination in `load.go`, bounded canonical import DFS in - public lifecycle coordination in `load.go`, bounded canonical import DFS in
`imports.go`, pattern-directed glob expansion in `glob.go`, version-report contexts `imports.go`, pattern-directed glob expansion in `glob.go`, version-report contexts
in `validation.go`, and detached layered metadata/history assembly in in `validation.go`, and detached layered metadata/history assembly in
`load_metadata.go`; and `load_metadata.go`;
- recorded application defaulting and normalization in `resolution.go`, including - recorded application defaulting and normalization in `resolution.go`, including
explicitness queries, helper verification, structural mutation audit, coalesced explicitness queries, helper verification, structural mutation audit, coalesced
intent, private before/after snapshots, and resolution metadata integration; and intent, private before/after snapshots, and resolution metadata integration;
- post-resolution schema-aware report collection and validator mutation detection in - post-resolution schema-aware report collection and validator mutation detection in
`validation.go`, completing the public callback lifecycle after composed input; `validation.go`, completing the public callback lifecycle after composed input;
- opaque typed environment references and per-load name resolution in - opaque typed environment references and per-load name resolution in
@@ -38,13 +38,15 @@ module and package documentation boundary. Its implemented public primitives are
validator-state auditing; validator-state auditing;
- explicit bounded startup environment bootstrap and safe partial reporting in - explicit bounded startup environment bootstrap and safe partial reporting in
`secrets.go`; `secrets.go`;
- fixed-point tag/predicate/dependency sensitivity classification in `secret.go`; and - fixed-point tag/predicate/dependency sensitivity classification in `secret.go`;
- frozen-snapshot redaction and canonical effective output in `render.go`; - frozen-snapshot redaction and canonical effective output in `render.go`;
- bounded immutable input applications, safe historical replay, detached explanation - bounded immutable input applications, safe historical replay, detached explanation
records, and deterministic human rendering in `explain.go`, with the records, and deterministic human rendering in `explain.go`, with the
only upstream dumper integration isolated in `internal/yaml/write.go`; and only upstream dumper integration isolated in `internal/yaml/write.go`;
- a separate maintained `examples/consumers` package with four sanitized consumer - a separate maintained `examples/consumers` package with four sanitized consumer
shapes, fixtures, domain validators, and runtime-boundary functions. shapes, fixtures, domain validators, and runtime-boundary functions; and
- a fail-fast source-candidate checker in `scripts/release-check.sh`, with local
documentation-link and public import-boundary gates owned by root-package tests.
The [configuration contract](../config.md) owns implemented input, schema, decoding, The [configuration contract](../config.md) owns implemented input, schema, decoding,
loading lifecycle, path imports, composition, profile/CLI overlay, version checking, loading lifecycle, path imports, composition, profile/CLI overlay, version checking,
@@ -54,15 +56,13 @@ explanation, and ownership behavior.
The [consumer adoption guide](../consumers/README.md) owns current application-fit The [consumer adoption guide](../consumers/README.md) owns current application-fit
and migration guidance. and migration guidance.
The source-extraction inventory records the application foundations assigned to The source-extraction inventory records the application foundations used by the
future implementation work: implementation:
- [Extraction inventory](extraction.md) - [Extraction inventory](extraction.md)
This document will inventory additional components and link to their current
contracts and focused internal documentation as they are introduced.
The [architecture policy](../policy/architecture.md) owns binding boundaries and The [architecture policy](../policy/architecture.md) owns binding boundaries and
invariants. The [initial target design](../roadmap/initial.md) describes planned invariants. The [initial target record](../roadmap/initial.md) links current feature
behavior; it is not an inventory of implemented features. See the owners and preserves deferred scope; it is not an implementation inventory. See the
[development guide](../development.md) for contributor orientation and validation. [development guide](../development.md) for contributor orientation and validation
and the [release procedure](../release.md) for source-candidate gates.

View File

@@ -7,10 +7,10 @@
## Purpose and applicability ## Purpose and applicability
ConfigKit is an opinionated Go library for consistent YAML configuration loading ConfigKit is an opinionated Go library for consistent YAML configuration loading
and resolution across consuming applications. This policy governs contributions and resolution across consuming applications. This policy governs contributions.
now; it does not claim that the target features are implemented. The The [component overview](../internal/overview.md) owns implementation inventory, the
[component overview](../internal/overview.md) owns implementation inventory and [configuration contract](../config.md) owns implemented behavior, and the
[initial roadmap](../roadmap/initial.md) owns unimplemented target behavior. [initial target record](../roadmap/initial.md) preserves deferred scope.
## Success criteria ## Success criteria
@@ -48,8 +48,8 @@ existing primitives cannot accommodate it cleanly, and show how the extension
preserves a coherent model. Application-specific interpretation and validation preserves a coherent model. Application-specific interpretation and validation
remain appropriate. Reuse Narratio's applicable infrastructure under these remain appropriate. Reuse Narratio's applicable infrastructure under these
boundaries, and keep simple consumers independent of optional composition boundaries, and keep simple consumers independent of optional composition
features. The [consumer API design](../roadmap/initial.md#consumer-api-design) features. The [consumer adoption guide](../consumers/README.md) demonstrates the
describes the proposed surface; this policy does not claim it is implemented. implemented surface against representative simple and complex shapes.
## Responsibility boundaries ## Responsibility boundaries
@@ -103,12 +103,12 @@ decoding. Preserve presence and source information through processing. Ordinary
values must not be used to infer whether input was absent. Final configuration, values must not be used to infer whether input was absent. Final configuration,
metadata, and effective inspection must agree, including application resolution metadata, and effective inspection must agree, including application resolution
changes; see [ADR 0003](../adr/0003-preserve-presence-and-resolution-history.md). changes; see [ADR 0003](../adr/0003-preserve-presence-and-resolution-history.md).
Safe historical values and an explanation renderer belong to the initial target, Safe historical values and an explanation renderer are part of the implemented contract,
including superseded/deleted paths and effective source attribution. Inspection including superseded/deleted paths and effective source attribution. Inspection
must agree with the final typed snapshot and apply historical sensitivity rules. must agree with the final typed snapshot and apply historical sensitivity rules.
See [ADR 0005](../adr/0005-explicit-overrides-and-safe-explanation.md). See [ADR 0005](../adr/0005-explicit-overrides-and-safe-explanation.md).
Detailed syntax and operation tables belong to the target roadmap until their Detailed syntax and operation tables belong to the
current configuration contract is implemented. [current configuration contract](../config.md).
## Ownership and confidentiality ## Ownership and confidentiality
@@ -136,6 +136,7 @@ for safe messages supplied by their hooks.
Do not introduce automatic directory discovery, network providers, arbitrary Do not introduce automatic directory discovery, network providers, arbitrary
merge strategies, additional configuration languages, or application runtime merge strategies, additional configuration languages, or application runtime
management without concrete consumer evidence and an explicit design decision. management without concrete consumer evidence and an explicit design decision.
The roadmap owns the complete deferred-feature inventory. Significant boundary The [initial target record](../roadmap/initial.md#explicit-non-goals-and-deferred-scope)
owns the deferred-feature inventory. Significant boundary
changes require an ADR and corresponding policy/contract updates; implementation changes require an ADR and corresponding policy/contract updates; implementation
convenience alone is not a reason to broaden the public API. convenience alone is not a reason to broaden the public API.

View File

@@ -62,24 +62,24 @@ handling, not secret values.
| Documentation rules | `docs/policy/documentation.md` | Ownership and document lifecycle | | Documentation rules | `docs/policy/documentation.md` | Ownership and document lifecycle |
| Testing rules | `docs/policy/testing.md` | Risk-based sufficiency, test boundaries, and maintenance principles | | 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 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 | | Release procedure | `docs/release.md` | Exact maintainer commands, prerequisites, supported targets, and verification |
| Exported Go API | Go documentation beside declarations | Symbol contracts, errors, ownership, and lifecycle API behavior | | 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, secret references/bootstrap, and explanation semantics; Go reference docs link here for shared rules | | YAML and resolution semantics | `docs/config.md`, as behavior lands | Syntax, composition, precedence, conversion, secret references/bootstrap, and explanation 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 | | 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 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 | | 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 | | Architectural decisions | `docs/adr/` | Context, decisions, alternatives, consequences, and supersession history |
| Initial target | `docs/roadmap/initial.md` | Unimplemented end-state and deferred feature scope | | Initial target record | `docs/roadmap/initial.md` | Implemented-feature owner links and deferred feature scope until roadmap retirement |
| Implementation plan | `docs/roadmap/implementation.md` | Stages, dependencies, acceptance gates, and progress | | Implementation plan | `docs/roadmap/implementation.md` | Stages, dependencies, acceptance gates, and progress |
| Release readiness gaps | `docs/roadmap/release-readiness.md` | Outstanding release prerequisites and closure evidence | | Release readiness evidence | `docs/roadmap/release-readiness.md` | Closed preparation gaps and outstanding candidate/publication evidence until roadmap retirement |
| Historical release notes | `docs/releases/` | Version-specific historical summaries required by release policy | | 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 | | Complete examples | `examples/` and executable Go examples | Maintained artifacts; prose links instead of duplicating full examples |
A listed future owner is not a requirement to create an empty file now. Create A listed owner is not a requirement to create an empty file before it has useful
API, consumer, example, and component documents when the corresponding behavior content. 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 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 code paths for planned files. Unvalidated candidate and publication work has the
exception recorded in the release policy. explicit temporary exception recorded in the release policy.
ConfigKit has no owned HTTP service, application CLI, or runtime operations ConfigKit has no owned HTTP service, application CLI, or runtime operations
interface. Do not create those reference documents for consuming applications. interface. Do not create those reference documents for consuming applications.

View File

@@ -222,17 +222,21 @@ restating or redefining its requirements.
### Temporary bootstrap deferral ### Temporary bootstrap deferral
The release procedure (`docs/release.md`) and complete release-check command are The release procedure and automated source-candidate checker now exist, but no exact
not yet present because ConfigKit has no Go module or implementation to validate. release candidate, version-matched release note, native macOS execution evidence, or
Their creation is temporarily deferred during initial development. This exception post-publication module retrieval has been validated. Initial implementation may be
permits implementation work; it does not permit publishing a release without completed without fabricating those later facts. This exception does not authorize
any gate required above. publication or waive any candidate, platform, remote, or consumer-verification gate.
Compensating controls: no release may be published until the Compensating controls: the [release procedure](../release.md) keeps every unvalidated
[release-readiness gaps](../roadmap/release-readiness.md) are closed, the runbook step as an explicit maintainer gate, and the
and checker exist, and the exact candidate passes all applicable gates. The [release-readiness evidence](../roadmap/release-readiness.md) records what is closed
maintainer preparing the first release owns closure. Remove this temporary and outstanding. No release may be published until an exact committed candidate has
exception when readiness is verified. Any other exception requires a documented repository constraint, rationale, the required release note, passes all applicable automated and native-platform gates,
is verified against `origin/main`, and completes guarded tag publication and clean
consumer retrieval. The maintainer preparing the first release owns closure. Remove
this temporary exception when that evidence is recorded and obsolete roadmap files
are retired. Any other exception requires a documented repository constraint, rationale,
compensating controls, scope, and closure condition here; none is currently compensating controls, scope, and closure condition here; none is currently
adopted. Do not silently weaken the base integrity, validation, documentation, adopted. Do not silently weaken the base integrity, validation, documentation,
verification, or immutability guarantees. verification, or immutability guarantees.

View File

@@ -39,7 +39,7 @@ boundaries. No credential bytes may appear in inspection or failure fixtures'
expected output; use disposable canaries to prove non-disclosure. expected output; use disposable canaries to prove non-disclosure.
Baseline commands belong in the [development guide](../development.md). Release Baseline commands belong in the [development guide](../development.md). Release
gates belong in the [release policy](release.md) and its eventual runbook. This gates belong in the [release policy](release.md) and [maintainer runbook](../release.md). This
policy does not imply that those tools or tests already exist. policy does not imply that those tools or tests already exist.
## Every test has a cost ## Every test has a cost

240
docs/release.md Normal file
View File

@@ -0,0 +1,240 @@
# ConfigKit Release Procedure
This is the maintainer runbook for ConfigKit's [release policy](policy/release.md).
ConfigKit publishes one source-only Go module: the immutable source tag and the
matching checked-in release note are the deliverables. There is no application
binary, container image, generated package, or separate registry publication.
## Release identity and support
- Module: `gitea.maximumdirect.net/eric/ConfigKit`
- Primary branch: `main`
- Authoritative remote: `origin`, expected to fetch from
`https://gitea.maximumdirect.net/eric/ConfigKit.git`
- Tags: stable Semantic Versions such as `v0.1.0`; prerelease tags are not supported
- Minimum Go language/toolchain line: Go 1.25, tested with a supported patched
Go 1.25 toolchain and one newer supported toolchain
- Build targets: Linux and macOS on amd64 and arm64
The automated checker cross-builds all four targets. Before release, the maintainer
must also obtain native test, race, symlink, and permission-fixture evidence on Linux
and macOS; cross-compilation is not native execution evidence.
## 1. Prepare access and tools
The release maintainer owns this procedure. Work in a dedicated clone with Git, Bash,
and two supported Go toolchains available. Configure private-host Git and Go module
access through the normal credential manager before starting. Keep tokens, passwords,
SSH material, and environment dumps outside the repository and command transcript.
Verify access without displaying credentials:
```sh
git remote get-url origin
git ls-remote origin HEAD
```
The remote URL must equal the authoritative URL above. Select the latest supported
patch in the Go 1.25 line and a newer supported toolchain. The values below are the
toolchains used while this runbook was introduced; update them to supported patch
releases during candidate preparation and record the actual versions in the release
note or validation record.
```sh
export CONFIGKIT_BASELINE_TOOLCHAIN=go1.25.5
export CONFIGKIT_NEWER_TOOLCHAIN=go1.26.7
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go version
GOTOOLCHAIN="$CONFIGKIT_NEWER_TOOLCHAIN" go version
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go mod download
GOTOOLCHAIN="$CONFIGKIT_NEWER_TOOLCHAIN" go mod download
```
Those commands explicitly acquire toolchains and dependencies. The checker itself
sets `GOPROXY=off` and fails if its required cache is incomplete.
## 2. Select the version and review compatibility
Choose an unused stable version and compare the candidate with the previous tag.
For the first release, review the whole public surface and current contracts.
```sh
release_version=v0.1.0
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
git show-ref --verify --quiet "refs/tags/$release_version" && exit 1 || :
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
printf 'remote tag already exists: %s\n' "$release_version" >&2
exit 1
else
test $? -eq 2
fi
git log --oneline --decorate --no-merges
```
Review exported Go signatures and ownership, YAML and scalar behavior, precedence,
diagnostic codes, minimum Go version, and platform support. Before `v1.0.0`, any
intentional incompatible minor-release change must be explained with consumer action;
patch releases must remain compatible within their minor line. Review the maintained
consumer examples and the migration guide even when signatures did not change.
Reassess `go.yaml.in/yaml/v4` rather than using `@latest` implicitly:
```sh
go list -m -versions go.yaml.in/yaml/v4
go list -m -json go.yaml.in/yaml/v4@latest
```
If changing the explicit pin, make that a reviewed dependency change and rerun the
complete checker, especially parser policy, limits, diagnostics, and rendering tests.
If retaining a prerelease pin, record that decision in Compatibility.
## 3. Write the release note
Create `docs/releases/$release_version.md` before selecting the candidate. It must
begin with `# ConfigKit $release_version` and contain `Summary`, `Compatibility`,
`Upgrade`, and `Changes` sections. Use “No action required” where appropriate. Link
to current canonical contracts instead of copying their definitions. Do not create a
release note until there is a real candidate and reviewed content.
## 4. Validate the source candidate
Run the complete checker from the repository root after dependencies have been
acquired. It validates module manifests in a disposable copy, both supported Go
toolchains, offline default tests, the native race detector, vet, native builds,
CGO-disabled cross-builds, formatting and whitespace (including untracked files),
examples, package isolation, and local documentation links.
```sh
./scripts/release-check.sh
```
`go vet` is the repository's static-analysis baseline. No additional linter is
claimed. Links to current ConfigKit files and headings are strict. Recorded links to
sibling consumer source are checked when those checkouts exist and are otherwise
inapplicable in an isolated clone; their immutable revisions remain recorded in the
extraction inventory.
Complete these manual gates and record their evidence with the candidate:
- The maintainer reviews compatibility and downstream migration impact against
`docs/config.md`, Go API comments, and the consumer guide.
- The maintainer inspects `git status --short`, `git diff`, and the candidate file
list for credentials, private data, generated output, unintended files, and
unrelated changes.
- The maintainer records successful native checker runs on Linux and macOS, including
filesystem capability tests. If either host is unavailable, release remains
blocked unless platform support is formally narrowed in current documentation.
- The maintainer removes completed, obsolete documents under `docs/roadmap/`, repairs
inbound links, and reruns the checker. ADR rationale remains historical.
- The maintainer reviews the exact version-matched release note for accuracy and
confirms it describes only deliverables that will actually be published.
## 5. Commit, push, and record the candidate
Commit all candidate source, contract, example, roadmap-retirement, and release-note
changes, rerun the checker against that clean commit, then push only `main` and record
the exact commit in Git metadata local to the clone:
```sh
git add .
git commit --message "Prepare ConfigKit $release_version"
./scripts/release-check.sh
test -z "$(git status --porcelain=v1 --untracked-files=all)"
git push origin HEAD:refs/heads/main
git rev-parse HEAD | tee .git/configkit-release-candidate
candidate_commit=$(cat .git/configkit-release-candidate)
```
If review changes the source after this point, create and validate a new candidate;
do not reuse the recorded commit.
## 6. Run publication guards
Immediately before tagging, fetch the authoritative branch and tags, restore the
recorded variables if this is a new shell, and execute every guard:
```sh
release_version=v0.1.0
candidate_commit=$(cat .git/configkit-release-candidate)
git fetch --prune origin main
git fetch --tags origin
test "$(git branch --show-current)" = main
test -z "$(git status --porcelain=v1 --untracked-files=all)"
test "$(git rev-parse HEAD)" = "$candidate_commit"
test "$(git rev-parse refs/remotes/origin/main)" = "$candidate_commit"
test "$(git remote get-url origin)" = 'https://gitea.maximumdirect.net/eric/ConfigKit.git'
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
test -f "docs/releases/$release_version.md"
test "$(sed -n '1p' "docs/releases/$release_version.md")" = "# ConfigKit $release_version"
for heading in Summary Compatibility Upgrade Changes; do
grep -Fxq "## $heading" "docs/releases/$release_version.md"
done
git show-ref --verify --quiet "refs/tags/$release_version" && exit 1 || :
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
printf 'remote tag already exists: %s\n' "$release_version" >&2
exit 1
else
test $? -eq 2
fi
```
Confirm the recorded automated and manual approvals apply to exactly
`$candidate_commit`. A successful older run is not evidence for a changed commit.
## 7. Tag and publish the exact ref
Create one annotated tag at the guarded commit, verify its peeled target, and push
only that ref. Do not use `git push --tags`.
```sh
git tag --annotate "$release_version" --message "ConfigKit $release_version" "$candidate_commit"
test "$(git rev-list -n 1 "$release_version")" = "$candidate_commit"
git push origin "refs/tags/$release_version:refs/tags/$release_version"
```
The pushed tag completes the declared source-only publication. No Gitea release
object or binary upload is required.
## 8. Verify publication and clean consumer retrieval
Verify the authoritative tag and then retrieve that exact version into a new module
without a local `replace` directive. Private-host credentials must already be
configured. Use direct origin retrieval unless an explicitly approved internal Go
proxy is the publication channel.
```sh
remote_tag_commit=$(git ls-remote origin "refs/tags/$release_version^{}" | awk '{print $1}')
test "$remote_tag_commit" = "$candidate_commit"
consumer_dir=$(mktemp -d)
(
cd "$consumer_dir"
go mod init example.invalid/configkit-release-check
GOPRIVATE=gitea.maximumdirect.net GOPROXY=direct go get "gitea.maximumdirect.net/eric/ConfigKit@$release_version"
cat > main.go <<'EOF'
package main
import configkit "gitea.maximumdirect.net/eric/ConfigKit"
func main() {
_ = configkit.NoSource()
}
EOF
gofmt -w main.go
go test ./...
go build ./...
go list -m -f '{{.Path}} {{.Version}}' gitea.maximumdirect.net/eric/ConfigKit
)
rm -rf -- "$consumer_dir"
```
The final `go list` output must show the exact module path and `$release_version`.
Record the result with the release evidence.
## 9. Handle failures without replacement
Before publication, fix the candidate, rerun every gate, commit, push, and record a
new exact candidate. An unpublished local tag may be deleted only after verifying it
was never pushed or used by another release channel.
After publication, never move, delete, or recreate the tag and never replace its
release note. Correct the defect on `main`, choose a new semantically appropriate
version, and repeat this procedure. A supported advisory or deprecation mechanism
may warn consumers about the old version but cannot change its contents.

View File

@@ -2,8 +2,8 @@
## Status and ownership ## Status and ownership
Status: implementation in progress; Stages 1–15 are complete and later stages are Status: implementation complete; Stages 1–22 are complete. Release-candidate
pending. selection and publication remain separate maintainer work.
Audience: a `gpt-5.6-terra` coding agent implementing one stage per prompt, in Audience: a `gpt-5.6-terra` coding agent implementing one stage per prompt, in
ascending order. Each stage depends on every earlier stage being complete. ascending order. Each stage depends on every earlier stage being complete.
@@ -85,7 +85,7 @@ the adapter, YAML-policy, diagnostics, limits, and rendering regressions. A fina
upstream version is preferred when it passes those checks; if the RC is retained, upstream version is preferred when it passes those checks; if the RC is retained,
record that decision in release readiness and compatibility review. record that decision in release readiness and compatibility review.
Follow the feature's [upstream isolation contract](initial.md#yaml-dependency-and-public-api-isolation). Follow the feature's [upstream isolation contract](../policy/architecture.md#public-api-and-dependency-direction).
Translate upstream API changes internally without changing ConfigKit declarations Translate upstream API changes internally without changing ConfigKit declarations
or consumer requirements. Never re-export upstream aliases/options/plugins, expose or consumer requirements. Never re-export upstream aliases/options/plugins, expose
parser errors through wrapping, or pass parser-created objects through `any`. parser errors through wrapping, or pass parser-created objects through `any`.
@@ -97,8 +97,8 @@ unverified upstream versions or add a selectable-parser framework.
### Updated extraction map ### Updated extraction map
Use the source revisions and adaptation policies owned by the feature's Use the source revisions and adaptation policies owned by the feature's
[foundation](initial.md#existing-implementation-foundation) and [foundation](../internal/extraction.md) and
[secret bootstrap](initial.md#secret-references-and-explicit-bootstrap) sections. [secret bootstrap](../config.md#typed-secret-references) sections.
Paths below are relative to the named sibling repository. Reinspect them in Paths below are relative to the named sibling repository. Reinspect them in
Stage 1 and record the exact revision actually copied. The maintainer is the sole Stage 1 and record the exact revision actually copied. The maintainer is the sole
author of the relevant application code and has authorized its reuse and relicensing author of the relevant application code and has authorized its reuse and relicensing
@@ -154,9 +154,9 @@ syscall-level confinement, path discovery, or a public filesystem-provider API.
### Secret, override, and history implementation bounds ### Secret, override, and history implementation bounds
Follow the feature contracts for [secrets](initial.md#secret-references-and-explicit-bootstrap), Follow the feature contracts for [secrets](../config.md#typed-secret-references),
[CLI overrides](initial.md#cli-overrides), and [CLI overrides](../config.md#explicit-cli-overrides), and
[explanation](initial.md#historical-value-explanation). Introduce these public APIs [explanation](../config.md#historical-value-explanation). Introduce these public APIs
only in Stages 16–19. Earlier stages cover ordinary types and file/profile layers; only in Stages 16–19. Earlier stages cover ordinary types and file/profile layers;
they must not expose an unresolved secret as a completed load or silently accept they must not expose an unresolved secret as a completed load or silently accept
an override option. Extend the shared descriptor/projection graph for `Secret` an override option. Extend the shared descriptor/projection graph for `Secret`
@@ -303,8 +303,8 @@ Completion evidence (2026-09-06):
No deviations were required. Paths, diagnostics, parsing, and all later behavior No deviations were required. Paths, diagnostics, parsing, and all later behavior
remain assigned to subsequent stages. remain assigned to subsequent stages.
Read: feature [foundation](initial.md#existing-implementation-foundation), Read: feature [foundation](../internal/extraction.md),
[consumer fit](initial.md#consumer-fit-and-intentional-migrations), all policies. [consumer fit](../consumers/README.md), all policies.
Tasks: Tasks:
@@ -353,8 +353,8 @@ Completion evidence (2026-09-06):
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
metadata population and configuration lifecycle behavior remain later work. metadata population and configuration lifecycle behavior remain later work.
Read: feature [paths](initial.md#paths-and-presence), Read: feature [paths](../config.md#layered-metadata),
[diagnostics](initial.md#provenance-diagnostics-and-redaction), public metadata API. [diagnostics](../config.md#safe-failures), public metadata API.
Tasks: Tasks:
@@ -408,8 +408,8 @@ Completion evidence (2026-09-06):
`go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64. No `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64. No
deviations were required; typed binding and decoding remain later work. deviations were required; typed binding and decoding remain later work.
Read: feature [YAML policy](initial.md#yaml-and-scalar-policy), Read: feature [YAML policy](../config.md#yaml-documents),
[source constructors](initial.md#entry-point-and-reusable-application-definition). [source constructors](../config.md#single-source-loading).
Start with the extraction map's parser and strict-loader cases; the old Start with the extraction map's parser and strict-loader cases; the old
second-document acceptance defect is already fixed in Narratio. second-document acceptance defect is already fixed in Narratio.
@@ -485,8 +485,8 @@ Completion evidence (2026-09-06):
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
typed value operations remain later work. typed value operations remain later work.
Read: feature [typed decoding](initial.md#typed-decoding) and Read: feature [typed decoding](../config.md#defaults-and-typed-decoding) and
[type/projection contract](initial.md#supported-types-and-projection). [type/projection contract](../config.md#application-schema-binding).
Tasks: Tasks:
@@ -537,8 +537,8 @@ Completion evidence (2026-09-06):
Go 1.26.7 on linux/amd64. No deviations were required; defaults and typed decoding Go 1.26.7 on linux/amd64. No deviations were required; defaults and typed decoding
remain later work. remain later work.
Read: feature [ownership](initial.md#recorded-resolution-and-validation) and Read: feature [ownership](../config.md#recorded-application-resolution) and
[type/projection contract](initial.md#supported-types-and-projection). [type/projection contract](../config.md#application-schema-binding).
Tasks: Tasks:
@@ -590,7 +590,7 @@ Completion evidence (2026-09-06):
and `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; and `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
public loading and schema-version checks remain later work. public loading and schema-version checks remain later work.
Read: feature [defaults/null](initial.md#static-defaults-and-null) and typed decoding. Read: feature [defaults/null](../config.md#defaults-and-typed-decoding) and typed decoding.
Tasks: Tasks:
@@ -651,9 +651,9 @@ Completion evidence (2026-09-06):
`go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64. No `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64. No
deviations were required; resolution and semantic validation remain later work. deviations were required; resolution and semantic validation remain later work.
Read: feature [lifecycle](initial.md#resolution-lifecycle), Read: feature [lifecycle](../config.md#single-source-loading),
[version hook](initial.md#schema-checking-and-secret-classification), [version hook](../config.md#application-schema-binding),
[results](initial.md#results-errors-and-inspection). [results](../config.md#safe-failures).
Tasks: Tasks:
@@ -715,7 +715,7 @@ Completion evidence (2026-09-06):
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
semantic validation remains later work. semantic validation remains later work.
Read: feature [resolution callbacks](initial.md#resolution-and-validation-callbacks). Read: feature [resolution callbacks](../config.md#recorded-application-resolution).
Tasks: Tasks:
@@ -776,8 +776,8 @@ Completion evidence (2026-09-06):
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
imports and profiles remain deliberately unavailable. imports and profiles remain deliberately unavailable.
Read: feature [diagnostic callbacks](initial.md#resolution-and-validation-callbacks) Read: feature [diagnostic callbacks](../config.md#recorded-application-resolution)
and [schema reports](initial.md#schema-checking-and-secret-classification). and [schema reports](../config.md#application-schema-binding).
Tasks: Tasks:
@@ -824,7 +824,7 @@ Completion evidence (2026-09-06):
[current composition contract](../config.md#strict-document-composition) owns the [current composition contract](../config.md#strict-document-composition) owns the
implemented semantics; public import wiring remains deferred to subsequent work. implemented semantics; public import wiring remains deferred to subsequent work.
Read: feature [composition table](initial.md#composition-and-overlay). Read: feature [composition table](../config.md#strict-document-composition).
Extract Narratio's additive composer and conflict tests before writing equivalent Extract Narratio's additive composer and conflict tests before writing equivalent
code. Change empty-map expectations to the feature table and retain exact locations. code. Change empty-map expectations to the feature table and retain exact locations.
@@ -883,7 +883,7 @@ Completion evidence (2026-09-06):
`go test -race ./...`, `go vet ./...`, `go build ./...`, `go mod tidy -diff`, and `go test -race ./...`, `go vet ./...`, `go build ./...`, `go mod tidy -diff`, and
`git diff --check` with Go 1.26.7 on linux/amd64. `git diff --check` with Go 1.26.7 on linux/amd64.
Read: feature [import graph](initial.md#explicit-imports-and-source-identity). Read: feature [import graph](../config.md#explicit-imports).
Extract the flat import loader and tests, then generalize its graph, identity and Extract the flat import loader and tests, then generalize its graph, identity and
containment rules. Do not treat its root-only declarations as ConfigKit's contract. containment rules. Do not treat its root-only declarations as ConfigKit's contract.
@@ -1008,7 +1008,7 @@ Completion evidence (2026-09-06):
Verified `go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`, Verified `go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`,
and `git diff --check` with Go 1.26.7 on linux/amd64. and `git diff --check` with Go 1.26.7 on linux/amd64.
Read: feature [profiles](initial.md#profiles), composition/overlay table. Read: feature [profiles](../config.md#selected-profiles), composition/overlay table.
Extract Narratio's overlay mechanics and profile tests; preserve the intentional Extract Narratio's overlay mechanics and profile tests; preserve the intentional
null/kind and profile-selection differences listed in the feature roadmap. null/kind and profile-selection differences listed in the feature roadmap.
@@ -1064,8 +1064,8 @@ Completion evidence (2026-09-06):
Verified `go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`, Verified `go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`,
`go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64. `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64.
Read: feature [presence](initial.md#paths-and-presence), Read: feature [presence](../config.md#layered-metadata),
[history](initial.md#provenance-diagnostics-and-redaction), metadata API. [history](../config.md#safe-failures), metadata API.
Use Narratio's effective ownership and inspection tests as extraction evidence. Use Narratio's effective ownership and inspection tests as extraction evidence.
Its source-only records need locations and complete historical operations. Its source-only records need locations and complete historical operations.
@@ -1123,8 +1123,8 @@ Completion evidence (2026-09-06):
`go build ./...`, `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on `go build ./...`, `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on
linux/amd64. linux/amd64.
Read: feature [redaction](initial.md#provenance-diagnostics-and-redaction), Read: feature [redaction](../config.md#safe-failures),
[secret predicate](initial.md#schema-checking-and-secret-classification), result API. [secret predicate](../config.md#application-schema-binding), result API.
Reuse Narratio's deterministic effective-output and non-disclosure cases. Render Reuse Narratio's deterministic effective-output and non-disclosure cases. Render
from the owned typed projection, without its marshal/parse reconstruction. from the owned typed projection, without its marshal/parse reconstruction.
@@ -1195,7 +1195,7 @@ Completion evidence (2026-09-06):
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
environment-backed typed secret references remain later work. environment-backed typed secret references remain later work.
Read: [secret bootstrap contract](initial.md#secret-references-and-explicit-bootstrap), Read: [secret bootstrap contract](../config.md#typed-secret-references),
architecture responsibility boundary, testing policy, and WeatherReporter's architecture responsibility boundary, testing policy, and WeatherReporter's
`internal/config/secrets.go` and corresponding `config_test.go` cases; also `internal/config/secrets.go` and corresponding `config_test.go` cases; also
Narratio's `internal/app/secrets_env.go`, its tests, and bounded-read helper. Narratio's `internal/app/secrets_env.go`, its tests, and bounded-read helper.
@@ -1267,7 +1267,7 @@ Completion evidence (2026-09-06):
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
CLI overrides remain later work. CLI overrides remain later work.
Read: [secret reference contract](initial.md#secret-references-and-explicit-bootstrap), Read: [secret reference contract](../config.md#typed-secret-references),
shared descriptor/projection rules and lifecycle, Stage 16 report boundary. shared descriptor/projection rules and lifecycle, Stage 16 report boundary.
Tasks: Tasks:
@@ -1337,7 +1337,7 @@ Completion evidence (2026-09-06):
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required; `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
safe historical-value explanation remains later work. safe historical-value explanation remains later work.
Read: [override contract](initial.md#cli-overrides), overlay/presence/version rules, Read: [override contract](../config.md#explicit-cli-overrides), overlay/presence/version rules,
source ordering, and the secret-reference boundary. source ordering, and the secret-reference boundary.
Tasks: Tasks:
@@ -1403,7 +1403,7 @@ Completion evidence (2026-09-06):
`go build ./...`, `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on `go build ./...`, `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on
linux/amd64. No deviations were required; consumer ergonomics remain later work. linux/amd64. No deviations were required; consumer ergonomics remain later work.
Read: [explanation contract](initial.md#historical-value-explanation), redaction Read: [explanation contract](../config.md#historical-value-explanation), redaction
rules, and history bounds above. rules, and history bounds above.
Generalize Narratio's semantic-record and inspection tests. They cover effective Generalize Narratio's semantic-record and inspection tests. They cover effective
@@ -1598,7 +1598,47 @@ Acceptance:
## Stage 22 — Prepare release validation and reconcile documentation ## Stage 22 — Prepare release validation and reconcile documentation
Status: pending. Status: complete.
Completion evidence (2026-09-06):
- Added the [maintainer release procedure](../release.md) for the existing
`origin/main`, module `gitea.maximumdirect.net/eric/ConfigKit`, source-only stable
tags, Go 1.25 minimum and newer-toolchain validation, and Linux/macOS amd64/arm64
targets. It supplies candidate recording, clean branch/index/worktree and exact
remote-commit guards, version/release-note/tag checks, precise single-ref tag
publication, clean consumer retrieval without `replace`, and immutable correction
steps. Private-host access is a prerequisite without embedding credentials or
environment dumps.
- Added fail-fast [`scripts/release-check.sh`](../../scripts/release-check.sh). It
verifies cached dependencies and runs offline disposable-copy module hygiene,
default tests on Go 1.25.5 and Go 1.26.7, vet and native builds on both, a native
race run, CGO-disabled builds for linux/amd64, linux/arm64, darwin/amd64, and
darwin/arm64, repository-wide Go formatting and text whitespace including
untracked files, executable examples, consumer fixtures, public import isolation,
and local documentation links. Toolchain/dependency acquisition remains an
explicit preceding runbook step.
- Added `TestLocalDocumentationLinks`, which strictly verifies repository-local files
and Markdown headings while treating recorded sibling-source links as applicable
only when those optional checkouts exist. The runbook makes immutable extraction
revisions authoritative in isolated release clones.
- Reconciled README, development, configuration, consumer, architecture/testing/
documentation/release policies, component and extraction inventories, and ADR
navigation with current behavior. Reduced the implemented feature roadmap to a
target record linking current owners and retaining only foundations plus explicit
non-goals/deferred scope. The implementation plan and readiness record remain until
an actual candidate retires completed roadmap files as required by release policy.
- Reassessed the YAML v4 dependency with `go list -m -versions` and
`go list -m -json ...@latest`; `v4.0.0-rc.6` remained the newest available release
on 2026-09-06, so the tested explicit pin was retained. `go doc -all` and
`TestDependencyImportBoundary` confirmed public documentation is renderable and no
upstream YAML type/import leaks outside the private adapter or maintained examples.
- The complete checker passed on linux/amd64 with Go 1.25.5 and Go 1.26.7. The
[release-readiness evidence](release-readiness.md) keeps exact candidate/release
note, native macOS execution, compatibility/content approval, roadmap retirement,
authoritative remote/tag guards, and post-publication retrieval explicitly open
under the revised bootstrap exception. No tag, push, downstream migration, release
note, or publication occurred.
Read: release policy in full and [release-readiness gaps](release-readiness.md). Read: release policy in full and [release-readiness gaps](release-readiness.md).

File diff suppressed because it is too large Load Diff

View File

@@ -2,24 +2,36 @@
## Status and ownership ## Status and ownership
ConfigKit is not release-ready. This document tracks outstanding release ConfigKit's implementation is prepared for release-candidate validation, but no
prerequisites under the [temporary bootstrap exception](../policy/release.md#temporary-bootstrap-deferral). release candidate has been selected or publication authorized. The maintainer
It is not the library implementation plan and does not assign implementation preparing the first release owns the remaining gates under the
stages. The maintainer preparing the first release owns closure. [temporary bootstrap exception](../policy/release.md#temporary-bootstrap-deferral).
This evidence record remains until candidate preparation retires completed roadmap
material in favor of the operational [release procedure](../release.md) and normal
release notes.
## Outstanding prerequisites ## Preparation evidence
| Gap | Evidence required to close | | Preparation item | Status and evidence |
| --- | --- | | --- | --- |
| No Go module or declared support matrix | Established module path, supported Go versions and platform targets documented in the release procedure | | Module and support matrix | Closed: the runbook records module `gitea.maximumdirect.net/eric/ConfigKit`, minimum Go 1.25 with a patched 1.25 plus newer supported toolchain, and Linux/macOS on amd64/arm64. |
| No release runbook | `docs/release.md` exists with the prerequisites, commands, publication guards, and verification required by release policy | | Maintainer release procedure | Closed: `docs/release.md` owns access prerequisites, candidate recording, complete validation, exact remote/commit/tag guards, source-only publication, consumer retrieval, and correction. |
| No complete release checker | A documented command exists and exercises every applicable automated candidate gate; manual gates and inapplicable checks are explicit | | Automated source checker | Closed for current-source preparation: `scripts/release-check.sh` passed on 2026-09-06 with Go 1.25.5 and Go 1.26.7 on linux/amd64. It performs disposable-copy module hygiene, cached/offline tests, race, vet, native and four-target cross-builds, formatting/whitespace, examples, import isolation, and local-link gates. The exact candidate must rerun it. |
| No consumer verification procedure | Runbook verifies retrieval of the exact released module version and a representative consumer build without local replacement directives | | Consumer verification procedure | Closed as procedure: the runbook retrieves an exact published version into a clean temporary module with no local replacement and tests/builds it. Actual retrieval remains a post-publication gate. |
| No verified secret/precedence/explanation contracts | Current contracts and passing bootstrap skip/partial-failure, secret isolation, CLI precedence, and safe historical-value regressions; representative consumer examples | | Secret/precedence/explanation evidence | Closed locally: current contracts and deterministic tests cover bootstrap skip/partial failure, credential isolation, defaults/base/profile/CLI precedence, historical redaction, and maintained consumer startup examples. |
| No validated release candidate | Version-matched release note, current contracts/examples, and complete checks against the exact committed candidate | | Parser dependency reassessment | Closed for preparation: on 2026-09-06, `go list -m -versions go.yaml.in/yaml/v4` and `go list -m -json go.yaml.in/yaml/v4@latest` both showed `v4.0.0-rc.6` as the newest available release. The explicit pin is retained; a candidate compatibility review must reassess and record it again. |
No release can proceed while these prerequisites remain open. Close items only ## Outstanding release gates
on evidence from actual files and checks, not proposed commands. Record closure
evidence here while this roadmap remains active. Once all gaps are closed, | Gate | Owner and closure evidence |
remove the bootstrap exception and retire this document in favor of the | --- | --- |
operational runbook and normal release records. | Exact candidate and release note | Maintainer selects an unused stable version, writes `docs/releases/<version>.md`, commits all release changes, runs the checker against that exact clean commit, pushes it to `origin/main`, and records the commit. |
| Native platform execution | Maintainer records applicable checker, race, symlink, and permission-fixture results on native Linux and macOS. Current local evidence is Linux/amd64 only; cross-builds do not close macOS execution. |
| Compatibility, migration, and content review | Maintainer records public API/configuration/diagnostic review, downstream migration impact, release-note approval, and inspection for credentials, private data, generated output, unintended files, and unrelated changes. |
| Roadmap retirement | Maintainer removes obsolete completed files under `docs/roadmap/`, repairs inbound links, and reruns the checker as part of the candidate. This record and the implementation plan intentionally remain while no candidate exists. |
| Remote publication guards | Maintainer fetches authoritative `origin/main` and tags immediately before publication and proves branch, clean worktree/index, candidate commit, remote commit, release note, approvals, and unused version all agree. |
| Tag and retrieval verification | After authorization, maintainer pushes only the exact immutable source tag, verifies its peeled remote commit, and retrieves/tests/builds the exact version in a clean consumer module without `replace`. |
No tag, push, downstream migration, release note, or release publication was
performed during implementation. A green local checker does not close the exact
candidate, native macOS, remote, or post-publication gates.

151
documentation_test.go Normal file
View File

@@ -0,0 +1,151 @@
package configkit
import (
"bufio"
"fmt"
"net/url"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"unicode"
)
var markdownLinkPattern = regexp.MustCompile(`(?m)(?:^|[[:space:]])\[[^\]]*\]\(([^)[:space:]]+)`)
func TestLocalDocumentationLinks(t *testing.T) {
repository, err := filepath.Abs(".")
if err != nil {
t.Fatal(err)
}
var failures []string
err = filepath.WalkDir(repository, func(path string, entry os.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if entry.IsDir() {
if entry.Name() == ".git" {
return filepath.SkipDir
}
return nil
}
if filepath.Ext(path) != ".md" {
return nil
}
content, readErr := os.ReadFile(path)
if readErr != nil {
return readErr
}
for _, match := range markdownLinkPattern.FindAllStringSubmatch(string(content), -1) {
target := strings.Trim(match[1], "<>")
if strings.Contains(target, "://") || strings.HasPrefix(target, "mailto:") {
continue
}
filePart, fragment, _ := strings.Cut(target, "#")
decoded, decodeErr := url.PathUnescape(filePart)
if decodeErr != nil {
failures = append(failures, fmt.Sprintf("%s: invalid escaped link %q", relativePath(repository, path), target))
continue
}
linked := path
if decoded != "" {
linked = filepath.Clean(filepath.Join(filepath.Dir(path), filepath.FromSlash(decoded)))
}
_, statErr := os.Stat(linked)
outside := linked != repository && !strings.HasPrefix(linked, repository+string(filepath.Separator))
if os.IsNotExist(statErr) && outside && optionalSiblingSource(repository, linked) {
continue // Recorded sibling-source links are optional in isolated clones.
}
if statErr != nil {
failures = append(failures, fmt.Sprintf("%s: missing local link %q", relativePath(repository, path), target))
continue
}
if fragment != "" && filepath.Ext(linked) == ".md" && !markdownHasFragment(linked, fragment) {
failures = append(failures, fmt.Sprintf("%s: missing fragment in %q", relativePath(repository, path), target))
}
}
return nil
})
if err != nil {
t.Fatal(err)
}
if len(failures) != 0 {
t.Fatalf("documentation link failures:\n%s", strings.Join(failures, "\n"))
}
}
func optionalSiblingSource(repository, linked string) bool {
relative, err := filepath.Rel(filepath.Dir(repository), linked)
if err != nil || relative == "." || filepath.IsAbs(relative) {
return false
}
parts := strings.Split(filepath.ToSlash(relative), "/")
if len(parts) == 0 {
return false
}
switch strings.ToLower(parts[0]) {
case "narratio", "notarius", "weatherreporter", "seriatim":
return true
default:
return false
}
}
func markdownHasFragment(path, wanted string) bool {
file, err := os.Open(path)
if err != nil {
return false
}
defer file.Close()
wanted, err = url.PathUnescape(wanted)
if err != nil {
return false
}
seen := make(map[string]int)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if !strings.HasPrefix(line, "#") {
continue
}
heading := strings.TrimSpace(strings.TrimLeft(line, "#"))
base := markdownFragment(heading)
count := seen[base]
seen[base]++
fragment := base
if count > 0 {
fragment = fmt.Sprintf("%s-%d", base, count)
}
if fragment == wanted {
return true
}
}
return false
}
func markdownFragment(heading string) string {
var result strings.Builder
previousSpace := false
for _, character := range strings.ToLower(heading) {
switch {
case unicode.IsLetter(character), unicode.IsDigit(character), character == '_', character == '-':
result.WriteRune(character)
previousSpace = false
case unicode.IsSpace(character):
if result.Len() > 0 && !previousSpace {
result.WriteByte('-')
previousSpace = true
}
}
}
return strings.TrimRight(result.String(), "-")
}
func relativePath(root, path string) string {
relative, err := filepath.Rel(root, path)
if err != nil {
return path
}
return filepath.ToSlash(relative)
}

75
scripts/release-check.sh Executable file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
repository_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
cd "$repository_dir"
baseline_toolchain=${CONFIGKIT_BASELINE_TOOLCHAIN:?set CONFIGKIT_BASELINE_TOOLCHAIN to a cached supported Go 1.25 patch release}
newer_toolchain=${CONFIGKIT_NEWER_TOOLCHAIN:?set CONFIGKIT_NEWER_TOOLCHAIN to a cached newer supported Go toolchain}
run_go() {
local toolchain=$1
shift
GOTOOLCHAIN="$toolchain" GOPROXY=off go "$@"
}
check_toolchain() {
local toolchain=$1
GOTOOLCHAIN="$toolchain" GOPROXY=off go version >/dev/null
run_go "$toolchain" mod download
}
check_toolchain "$baseline_toolchain"
check_toolchain "$newer_toolchain"
bash -n scripts/release-check.sh
temporary_dir=$(mktemp -d)
trap 'rm -rf -- "$temporary_dir"' EXIT
git ls-files --cached --others --exclude-standard -z |
tar --null --files-from=- --create --file=- |
tar --extract --file=- --directory="$temporary_dir"
(
cd "$temporary_dir"
GOTOOLCHAIN="$baseline_toolchain" GOPROXY=off go mod tidy
)
diff -u go.mod "$temporary_dir/go.mod"
diff -u go.sum "$temporary_dir/go.sum"
mapfile -d '' go_files < <(git ls-files --cached --others --exclude-standard -z -- '*.go')
if ((${#go_files[@]})); then
unformatted=$(gofmt -l -- "${go_files[@]}")
if [[ -n "$unformatted" ]]; then
printf 'gofmt required for:\n%s\n' "$unformatted" >&2
exit 1
fi
fi
git diff --check HEAD --
while IFS= read -r -d '' candidate_file; do
case "$candidate_file" in
*.go|*.md|*.sh|go.mod|go.sum|LICENSE|.gitignore|AGENTS.md)
if LC_ALL=C grep -nE '[[:blank:]]+$' -- "$candidate_file"; then
printf 'trailing whitespace found in %s\n' "$candidate_file" >&2
exit 1
fi
;;
esac
done < <(git ls-files --cached --others --exclude-standard -z)
for toolchain in "$baseline_toolchain" "$newer_toolchain"; do
run_go "$toolchain" test ./...
run_go "$toolchain" vet ./...
run_go "$toolchain" build ./...
done
run_go "$newer_toolchain" test -race ./...
run_go "$newer_toolchain" test . -run '^Example'
run_go "$newer_toolchain" test ./examples/consumers
run_go "$newer_toolchain" test . -run '^TestLocalDocumentationLinks$'
run_go "$newer_toolchain" test . -run '^TestDependencyImportBoundary$'
for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64; do
target_os=${target%/*}
target_arch=${target#*/}
GOTOOLCHAIN="$newer_toolchain" GOPROXY=off CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" go build ./...
done