Prepare ConfigKit v0.1.0

This commit is contained in:
2026-09-07 01:52:38 +00:00
parent 4bd83639a3
commit 729f94fadf
7 changed files with 95 additions and 67 deletions

View File

@@ -21,7 +21,7 @@ public behavior.
| Architecture decisions or future work | [Documentation policy](policy/documentation.md), [deferred scope](roadmap/deferred.md), and relevant ADRs listed below | | Architecture decisions or future work | [Documentation policy](policy/documentation.md), [deferred scope](roadmap/deferred.md), and relevant ADRs listed below |
| Code and test changes | [Architecture policy](policy/architecture.md), [testing policy](policy/testing.md), and the owning contract and tests from the map below | | Code and test changes | [Architecture policy](policy/architecture.md), [testing policy](policy/testing.md), and the owning contract and tests from the map below |
| 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), [release procedure](release.md), and [release-readiness evidence](roadmap/release-readiness.md) | | Release preparation | [Release policy](policy/release.md) and [release procedure](release.md) |
Accepted decisions: Accepted decisions:
@@ -39,8 +39,8 @@ contracts and the component overview for ongoing work. For example:
git show cb5b435:docs/roadmap/remediation.md git show cb5b435:docs/roadmap/remediation.md
``` ```
Outstanding release work and preparation evidence remain in the Release-candidate, publication, and verification work follows the operational
[release-readiness record](roadmap/release-readiness.md). [release procedure](release.md).
## Baseline validation ## Baseline validation

View File

@@ -71,7 +71,6 @@ handling, not secret values.
| Architectural decisions | `docs/adr/` | Context, decisions, alternatives, consequences, and supersession history | | Architectural decisions | `docs/adr/` | Context, decisions, alternatives, consequences, and supersession history |
| Deferred scope | `docs/roadmap/deferred.md` | Deliberate exclusions and the conditions for reconsidering them | | Deferred scope | `docs/roadmap/deferred.md` | Deliberate exclusions and the conditions for reconsidering them |
| Future implementation plans | Task-specific files under `docs/roadmap/` | Unfinished work, task order, acceptance gates, and progress; completed plans retire to Git history | | Future implementation plans | Task-specific files under `docs/roadmap/` | Unfinished work, task order, acceptance gates, and progress; completed plans retire to Git history |
| 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 |

View File

@@ -220,23 +220,5 @@ restating or redefining its requirements.
## Policy Exceptions ## Policy Exceptions
### Temporary bootstrap deferral None. Candidate selection, publication, and post-publication verification remain
mandatory steps in the [release procedure](../release.md), not policy exceptions.
The release procedure and automated source-candidate checker now exist, but no exact
release candidate, version-matched release note, native macOS execution evidence, or
post-publication module retrieval has been validated. Initial implementation may be
completed without fabricating those later facts. This exception does not authorize
publication or waive any candidate, platform, remote, or consumer-verification gate.
Compensating controls: the [release procedure](../release.md) keeps every unvalidated
step as an explicit maintainer gate, and the
[release-readiness evidence](../roadmap/release-readiness.md) records what is closed
and outstanding. No release may be published until an exact committed candidate has
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
adopted. Do not silently weaken the base integrity, validation, documentation,
verification, or immutability guarantees.

72
docs/releases/v0.1.0.md Normal file
View File

@@ -0,0 +1,72 @@
# ConfigKit v0.1.0
This is the first source release of ConfigKit, an opinionated Go library for strict,
explainable YAML configuration loading.
## Summary
ConfigKit provides one typed loading lifecycle for file, byte, reader, and
defaults-only inputs. It supports bounded explicit imports, strict composition,
selected profiles, explicit CLI overrides, application-owned defaults and recorded
resolution, semantic validation, provenance, redacted effective output, and safe
historical explanation.
Typed environment-name secret references and an explicit secrets-directory bootstrap
keep credential acquisition separate from ordinary loading. Maintained consumer
examples demonstrate simple and composed application shapes without exposing the
private YAML parser dependency.
See the [configuration contract](../config.md) and
[consumer adoption guide](../consumers/README.md) for current behavior and examples.
## Compatibility
This is the initial public release, so there is no earlier ConfigKit release to
upgrade from. The module requires Go 1.25 or newer and supports Linux and macOS on
amd64 and arm64. Candidate validation uses patched Go 1.25 and Go 1.26 toolchains;
native Linux and macOS evidence is required in addition to cross-builds.
Configuration intentionally uses a strict YAML subset. Duplicate keys, aliases,
anchors, merge keys, unsupported tags and scalar forms, trailing documents, and
unknown typed fields are rejected. Composition rejects overlapping non-mapping
definitions; replacement occurs only through selected profiles, explicit CLI
overrides, or recorded application resolution.
The private parser dependency remains explicitly pinned to
`go.yaml.in/yaml/v4 v4.0.0-rc.6`, which was still the newest available v4 release when
the candidate was prepared. No upstream YAML declarations are part of ConfigKit's
public API.
## Upgrade
No action is required for an earlier ConfigKit version because this is the first
release. New consumers can add the module with:
```sh
go get gitea.maximumdirect.net/eric/ConfigKit@v0.1.0
```
The authoritative host may require its normal private-module credentials. Consumers
adapting existing application configuration should review the intentional migration
differences in the [consumer adoption guide](../consumers/README.md), particularly
strict YAML, string schema versions, explicit empty/null behavior, canonical module
objects, `int64` dynamic integers, explicit CLI records, and typed secret references.
## Changes
- Added opaque file, byte, reader, and defaults-only sources with fixed resource
limits and safe structured diagnostics.
- Added an owned strict YAML model, typed schema binding, detached defaults and
results, canonical projection, and private parser isolation.
- Added explicit path/glob imports, deterministic strict composition, canonical
source identity and containment, and selected profile overlays.
- Added layered presence, origins, chronological history, version checks, recorded
defaulting and normalization, and read-only semantic validation.
- Added secret classification, deterministic redacted effective YAML, typed
environment references, and bounded explicit secrets-directory bootstrap reports.
- Added parser-neutral explicit CLI overrides and safe structured/human historical
value explanations, including removed and superseded values.
- Added maintained Narratio-, Notarius-, WeatherReporter-, and Seriatim-shaped
examples and migration coverage using only ConfigKit and the standard library.
- Added race and bounded fuzz coverage plus a two-toolchain, offline, cross-platform
source-release checker and maintainer runbook.

View File

@@ -1,39 +0,0 @@
# Release Readiness
## Status and ownership
ConfigKit's implementation is prepared for release-candidate validation, but no
release candidate has been selected or publication authorized. The maintainer
preparing the first release owns the remaining gates under the
[temporary bootstrap exception](../policy/release.md#temporary-bootstrap-deferral).
Completed implementation, remediation, and initial-target records have retired to
Git history at `cb5b435`. [Deferred scope](deferred.md) remains separate. This
record retains preparation evidence and unresolved release gates until their
closure is recorded under the operational [release procedure](../release.md).
## Preparation evidence
| Preparation item | Status and evidence |
| --- | --- |
| 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. |
| 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. |
| 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. |
| Maintainability remediation | Closed: all nine stages completed in `cb5b435`; the full checker passed on 2026-09-07 with Go 1.25.5 and Go 1.26.7 on Linux/amd64. The recorded audit found all 186 exported declarations unchanged, no dependency changes, and passing native FIFO/symlink/permission tests. |
| Roadmap retirement | Closed for current-source preparation: completed implementation, remediation, and initial-target records were removed, navigation repaired, and deferred scope retained separately. Maintainer rechecks for any newly completed roadmap material when selecting the candidate. |
| 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. |
| 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. |
| 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. |
## Outstanding release gates
| Gate | Owner and closure evidence |
| --- | --- |
| 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. |
| 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.

View File

@@ -37,6 +37,7 @@ func TestCheckScriptsHandleFilenamesAndStopOnFailure(t *testing.T) {
write(filepath.Join(root, "scripts", scriptName), script, 0700) write(filepath.Join(root, "scripts", scriptName), script, 0700)
write(filepath.Join(root, "go.mod"), []byte("module example.invalid/check\n"), 0600) write(filepath.Join(root, "go.mod"), []byte("module example.invalid/check\n"), 0600)
write(filepath.Join(root, "go.sum"), nil, 0600) write(filepath.Join(root, "go.sum"), nil, 0600)
write(filepath.Join(root, "obsolete.go"), []byte("package obsolete\n"), 0600)
files := []string{"nested/a space.go", "nested/a\nnewline.go"} files := []string{"nested/a space.go", "nested/a\nnewline.go"}
for _, file := range files { for _, file := range files {
write(filepath.Join(root, file), []byte("package example\n"), 0600) write(filepath.Join(root, file), []byte("package example\n"), 0600)
@@ -54,13 +55,16 @@ func TestCheckScriptsHandleFilenamesAndStopOnFailure(t *testing.T) {
t.Fatalf("git init: %v %s", err, out) t.Fatalf("git init: %v %s", err, out)
} }
// HEAD is required by the whitespace gate. Commit only the module baseline. // HEAD is required by the whitespace gate. Commit only the module baseline.
for _, args := range [][]string{{"add", "go.mod", "go.sum"}, {"-c", "user.name=Test", "-c", "user.email=test@example.invalid", "-c", "commit.gpgsign=false", "commit", "-qm", "Test fixture"}} { for _, args := range [][]string{{"add", "go.mod", "go.sum", "obsolete.go"}, {"-c", "user.name=Test", "-c", "user.email=test@example.invalid", "-c", "commit.gpgsign=false", "commit", "-qm", "Test fixture"}} {
cmd := exec.Command("git", args...) cmd := exec.Command("git", args...)
cmd.Dir = root cmd.Dir = root
if out, err := cmd.CombinedOutput(); err != nil { if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("git fixture: %v %s", err, out) t.Fatalf("git fixture: %v %s", err, out)
} }
} }
if err := os.Remove(filepath.Join(root, "obsolete.go")); err != nil {
t.Fatal(err)
}
cmd := exec.Command("/bin/bash", filepath.Join(root, "scripts", scriptName)) cmd := exec.Command("/bin/bash", filepath.Join(root, "scripts", scriptName))
cmd.Env = append(os.Environ(), "PATH="+bin+string(os.PathListSeparator)+os.Getenv("PATH"), "CONFIGKIT_BASELINE_TOOLCHAIN=test-baseline", "CONFIGKIT_NEWER_TOOLCHAIN=test-newer", "CONFIGKIT_TEST_FMT_LOG="+log, "CONFIGKIT_TEST_GO_LOG="+calls) cmd.Env = append(os.Environ(), "PATH="+bin+string(os.PathListSeparator)+os.Getenv("PATH"), "CONFIGKIT_BASELINE_TOOLCHAIN=test-baseline", "CONFIGKIT_NEWER_TOOLCHAIN=test-newer", "CONFIGKIT_TEST_FMT_LOG="+log, "CONFIGKIT_TEST_GO_LOG="+calls)
if name == "failed-go-check" { if name == "failed-go-check" {

View File

@@ -25,8 +25,13 @@ bash -n scripts/release-check.sh
temporary_dir=$(mktemp -d) temporary_dir=$(mktemp -d)
trap 'rm -rf -- "$temporary_dir"' EXIT trap 'rm -rf -- "$temporary_dir"' EXIT
git ls-files --cached --others --exclude-standard -z | candidate_manifest=$temporary_dir/candidate-files
tar --null --files-from=- --create --file=- | while IFS= read -r -d '' candidate_file; do
if [[ -e "$candidate_file" || -L "$candidate_file" ]]; then
printf '%s\0' "$candidate_file" >>"$candidate_manifest"
fi
done < <(git ls-files --cached --others --exclude-standard -z)
tar --null --files-from="$candidate_manifest" --create --file=- |
tar --extract --file=- --directory="$temporary_dir" tar --extract --file=- --directory="$temporary_dir"
( (
cd "$temporary_dir" cd "$temporary_dir"
@@ -37,7 +42,9 @@ diff -u go.sum "$temporary_dir/go.sum"
go_files=() go_files=()
while IFS= read -r -d '' go_file; do while IFS= read -r -d '' go_file; do
go_files+=("$go_file") if [[ -f "$go_file" ]]; then
go_files+=("$go_file")
fi
done < <(git ls-files --cached --others --exclude-standard -z -- '*.go') done < <(git ls-files --cached --others --exclude-standard -z -- '*.go')
if ((${#go_files[@]})); then if ((${#go_files[@]})); then
unformatted=$(gofmt -l -- "${go_files[@]}") unformatted=$(gofmt -l -- "${go_files[@]}")
@@ -49,6 +56,9 @@ fi
git diff --check HEAD -- git diff --check HEAD --
while IFS= read -r -d '' candidate_file; do while IFS= read -r -d '' candidate_file; do
if [[ ! -f "$candidate_file" ]]; then
continue
fi
case "$candidate_file" in case "$candidate_file" in
*.go|*.md|*.sh|go.mod|go.sum|LICENSE|.gitignore|AGENTS.md) *.go|*.md|*.sh|go.mod|go.sum|LICENSE|.gitignore|AGENTS.md)
if LC_ALL=C grep -nE '[[:blank:]]+$' -- "$candidate_file"; then if LC_ALL=C grep -nE '[[:blank:]]+$' -- "$candidate_file"; then