Prepare ConfigKit v0.1.0
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 |
|
||||||
|
|
||||||
|
|||||||
@@ -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
72
docs/releases/v0.1.0.md
Normal 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.
|
||||||
@@ -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.
|
|
||||||
@@ -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" {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user