From 55fd42921a34c726d9431fbcb779fcfedddf8b1e Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 7 Sep 2026 01:52:38 +0000 Subject: [PATCH] Prepare ConfigKit v0.1.0 --- docs/development.md | 6 +-- docs/policy/documentation.md | 1 - docs/policy/release.md | 22 +--------- docs/releases/v0.1.0.md | 72 +++++++++++++++++++++++++++++++ docs/roadmap/release-readiness.md | 39 ----------------- release_check_test.go | 6 ++- scripts/release-check.sh | 16 +++++-- 7 files changed, 95 insertions(+), 67 deletions(-) create mode 100644 docs/releases/v0.1.0.md delete mode 100644 docs/roadmap/release-readiness.md diff --git a/docs/development.md b/docs/development.md index daa1869..4dc8fcd 100644 --- a/docs/development.md +++ b/docs/development.md @@ -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 | | 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) | -| 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: @@ -39,8 +39,8 @@ contracts and the component overview for ongoing work. For example: git show cb5b435:docs/roadmap/remediation.md ``` -Outstanding release work and preparation evidence remain in the -[release-readiness record](roadmap/release-readiness.md). +Release-candidate, publication, and verification work follows the operational +[release procedure](release.md). ## Baseline validation diff --git a/docs/policy/documentation.md b/docs/policy/documentation.md index ebbbb24..b439a3a 100644 --- a/docs/policy/documentation.md +++ b/docs/policy/documentation.md @@ -71,7 +71,6 @@ handling, not secret values. | 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 | | 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 | | Complete examples | `examples/` and executable Go examples | Maintained artifacts; prose links instead of duplicating full examples | diff --git a/docs/policy/release.md b/docs/policy/release.md index 2104e5f..e83bdb0 100644 --- a/docs/policy/release.md +++ b/docs/policy/release.md @@ -220,23 +220,5 @@ restating or redefining its requirements. ## Policy Exceptions -### Temporary bootstrap deferral - -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. +None. Candidate selection, publication, and post-publication verification remain +mandatory steps in the [release procedure](../release.md), not policy exceptions. diff --git a/docs/releases/v0.1.0.md b/docs/releases/v0.1.0.md new file mode 100644 index 0000000..6f2d0bb --- /dev/null +++ b/docs/releases/v0.1.0.md @@ -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. diff --git a/docs/roadmap/release-readiness.md b/docs/roadmap/release-readiness.md deleted file mode 100644 index d5d99e3..0000000 --- a/docs/roadmap/release-readiness.md +++ /dev/null @@ -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/.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. diff --git a/release_check_test.go b/release_check_test.go index 7b1d745..3df41db 100644 --- a/release_check_test.go +++ b/release_check_test.go @@ -37,6 +37,7 @@ func TestCheckScriptsHandleFilenamesAndStopOnFailure(t *testing.T) { 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.sum"), nil, 0600) + write(filepath.Join(root, "obsolete.go"), []byte("package obsolete\n"), 0600) files := []string{"nested/a space.go", "nested/a\nnewline.go"} for _, file := range files { 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) } // 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.Dir = root if out, err := cmd.CombinedOutput(); err != nil { 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.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" { diff --git a/scripts/release-check.sh b/scripts/release-check.sh index b779a48..07947ce 100755 --- a/scripts/release-check.sh +++ b/scripts/release-check.sh @@ -25,8 +25,13 @@ 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=- | +candidate_manifest=$temporary_dir/candidate-files +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" ( cd "$temporary_dir" @@ -37,7 +42,9 @@ diff -u go.sum "$temporary_dir/go.sum" go_files=() 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') if ((${#go_files[@]})); then unformatted=$(gofmt -l -- "${go_files[@]}") @@ -49,6 +56,9 @@ fi git diff --check HEAD -- while IFS= read -r -d '' candidate_file; do + if [[ ! -f "$candidate_file" ]]; then + continue + fi 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