Status: ready for implementation; no stages completed by this planning pass.
Implement the [release roadmap](release.md) in the numbered order below. Each
stage is a bounded work unit for a gpt-5.6-terra coding agent; finish its tests
and current documentation before committing it. The completed policy-alignment
record formerly at this path is preserved at
`faf5ff8:docs/roadmap/implementation.md`; use `git show` to read it.
## Scope and settled decisions
Start from completed policy alignment at `faf5ff8`. Follow the
[development guide](../development.md) and applicable adopted policies. Preserve
library behavior, dependencies, the everyday checker, historical release notes,
licensing, and support commitments. This plan authorizes no real release or push.
Use release policy 1.4 and the adoption guide at upstream commit
`d84a38ebab26f048cafbe59a2246700c35d29843`, available from `../policy` or the
existing pinned upstream links. Do not add an upstream-version review. Use shared
wording verbatim unless a substantive ConfigKit decision warrants adaptation.
Preserve exact source metadata; update the local date when revising policy.
The interface is `./scripts/release.sh vMAJOR.MINOR.PATCH`, with the existing
`CONFIGKIT_BASELINE_TOOLCHAIN` prerequisite. Resolve the repository root from the
script location. Retain `scripts/release-check.sh` as its validator and an optional
diagnostic command, never a required prior run. No skip-validation option,
persistent cache, routine confirmation, or automatic commit is needed. Stop using
`.git/configkit-release-candidate`; ignore any old record without deleting it.
Use sequential explicit main-then-tag pushes, not atomic-push negotiation. Keep
Bash 3.2 and existing Git/Go prerequisites; no new release framework is needed.
## Stage 1 — Simplify the release checker and select its gates
Change `scripts/release-check.sh`, checker tests in `release_check_test.go`, and
the affected descriptions in `docs/policy/release.md`, `docs/release.md`, and
`docs/development.md` together. The existing guarded publication blocks remain
operational until Stage 2; do not describe the new command as available yet.
Use this exact gate set with the selected maintained Go 1.25 baseline:
| Gate | Command and rationale |
| --- | --- |
| Full offline race suite | One `go test -mod=readonly -vet=off -race -v ./...`; protects library behavior, ownership, and concurrent use. Includes examples, consumer fixtures, documentation links, and boundary tests. |
| Static analysis | One `go vet -mod=readonly ./...`; full vet provides checks beyond the subset normally run by tests. Disabling test-time vet avoids duplicating that subset. |
| Supported target compilation | `go build -mod=readonly ./...` for Linux amd64 and arm64 with `CGO_ENABLED=0`; these configurations are not covered by native race compilation. |
through explicit destinations/refspecs. A successful push establishes branch
publication without a separate read-back gate. Recheck local candidate and
clean state before tagging; ordinary concurrent local edits must not leak
into publication.
6. Create an annotated tag at the captured commit, using the captured checked-in
note as its message (`git tag -a -F`). Verify its peeled target and capture its
tag-object ID. Push only `refs/tags/<version>:refs/tags/<version>`, without
force or implicit publication of unrelated tags.
7. On successful tag push, report the version/candidate and return success
immediately. No CI polling, remote read-back, module retrieval, hosted release
creation, or routine human sign-off gates completion.
Use straightforward private helpers. These are ordinary release guards, not a
guarantee against hostile local processes or concurrent administrators. Do not
add locks, snapshots, signing requirements, or unrelated Git configuration rules.
### Failure outcomes
After a failed or ambiguous push, perform one bounded authoritative-state check;
do not poll or blindly retry:
| State observed | Behavior |
| --- | --- |
| Main push failed, but remote main equals candidate | Continue through remaining guards and tagging. |
| Main push failed, remote differs or cannot be queried | Stop before tagging; distinguish rejection from unknown outcome and explain recovery. |
| Tag push failed, but remote tag-object ID equals the created annotated tag | Report confirmed publication success; main publication was already established. |
| Tag push failed, remote tag confirmed absent | Report branch-only progress and the unpublished local tag; retain it. |
| Remote tag conflicts | Stop; never replace published contents. |
| Remote tag cannot be queried | Report unknown status; retain local state, do not claim success or safe version reuse. |
Document exact-ref recovery commands that distinguish absence from query failure.
Only after confirming a local tag was never published or used by another channel
may a maintainer delete that unpublished tag and rerun with the same version.
A fresh invocation revalidates; this is failure recovery, not a mandatory double
successful-path run. A correctly published tag needs no rerun. Published source
defects need a new version; transient transport failures do not. Never roll back
main or automatically delete tags to recover.
### Regression coverage and acceptance
Use disposable real Git working repositories and bare remotes. Reuse the existing
fixture-only authoritative-URL substitution or Git URL rewriting, with local-file
transports and isolated identity/signing configuration. No production test-only
bypass flags. Stub the expensive validator with a loggable result; use real
rejection hooks and narrow Git-process wrappers for lost responses/unavailable
queries. Tests must never contact the actual remote or recurse into the suite.
Cover success with main initially behind the candidate and already equal;
single validation; note-derived annotated tag/commit identity; ignored files;
and unrelated local tags remaining unpublished. Cover malformed version, wrong