Prepare ConfigKit v0.4.2 release

This commit is contained in:
2026-09-28 01:44:54 +00:00
parent a36ed3deba
commit 67c0369018
5 changed files with 45 additions and 451 deletions

45
docs/releases/v0.4.2.md Normal file
View File

@@ -0,0 +1,45 @@
# ConfigKit v0.4.2
This patch release simplifies and safeguards source publication and aligns
maintainer policy and licensing guidance. Library behavior is unchanged.
## Summary
Maintainers can now publish a prepared release with one guarded command. It
validates the exact committed candidate, checks the authoritative destination,
and pushes only the candidate on `main` and its annotated version tag. The
[release procedure](../release.md) explains preparation and partial-publication
recovery; successful tag publication completes the source-only release without
waiting for CI or consumer retrieval.
## Compatibility
No Go code, public API, configuration semantics, diagnostic behavior, or
dependencies changed from v0.4.1. The minimum Go version remains 1.25. Linux
amd64 and arm64 remain release-validated; macOS remains best-effort. The YAML
dependency remains `go.yaml.in/yaml/v4 v4.0.0-rc.6`.
## Upgrade
Select this version and rebuild:
```sh
go get gitea.maximumdirect.net/eric/ConfigKit@v0.4.2
```
No application-code or configuration migration is required from v0.4.1.
## Changes
- Add guarded single-command publication with exact candidate, version, and
remote checks; note-derived annotated tags; and bounded failed-push recovery.
- Keep one offline race suite, one full vet pass, and Linux amd64/arm64 builds
as release gates. Formatting and whitespace remain development checks;
dependency tidiness is reviewed when dependencies change.
- Align adopted policies and contributor guidance with their pinned upstream
revision, and include the CC BY-SA 4.0 license text and attribution for
adapted policy material. The project grant remains LGPL-3.0-or-later.
- Retire completed release-workflow and policy-alignment planning records while
preserving their history in Git. Deferred scope remains documented.
[COPYRIGHT](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.4.2/COPYRIGHT) | [LICENSE](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.4.2/LICENSE) | [ATTRIBUTION](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.4.2/docs/oss/attribution.md)

View File

@@ -1,222 +0,0 @@
# Release Workflow Implementation Plan
Status: implemented on 2026-09-28. All stages are complete.
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
**Completed 2026-09-28.** The checker now runs one readonly offline race suite
with test-time vet disabled, one full vet pass, and CGO-disabled Linux amd64/arm64
builds. The disposable module audit and release formatting/whitespace scans were
removed. Focused checker tests, Bash syntax checks, and the real Go 1.25.14
release checker passed on Linux.
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. |
Keep `GOPROXY=off`, baseline availability/cache diagnostics, fail-fast behavior,
and verbose skip reporting. Dependency/toolchain acquisition is explicit
preparation; there is no automatic upgrade or latest-version survey. Readonly
module commands prevent incidental manifest edits, not impose a new tidy policy.
Remove the disposable-copy module-tidiness audit, release formatting/whitespace
scans, and their unused machinery. Formatting/whitespace remain ordinary
development checks in `scripts/check.sh`; module tidiness is reviewed when
dependencies change. Offline tests/builds establish that the candidate compiles
and works with its declared dependencies. Remove policy wording that makes the
removed checks mandatory release gates. Shell syntax checks belong to development
validation, not a separate publication gate. Do not change the everyday checker.
Split the shared checker regression expectations where their contracts differ.
Retain unusual-filename and whitespace tests for the everyday checker. Controlled
Go subprocesses should verify the release toolchain/offline settings, one suite,
one vet pass, the two target builds, and stopping after failure. Do not recursively
execute the real full suite in a checker-orchestration test.
Acceptance: focused `TestCheckScripts` tests and Bash syntax checks pass. Run the
real revised checker with prepared baseline dependencies on Linux. Do not also
run the everyday suite just to repeat its checks. macOS and newer-toolchain
validation remain optional.
## Stage 2 — Implement single-command publication and recovery
**Completed 2026-09-28.** Added the executable single-command publisher, exact
candidate and destination guards, one checker invocation, explicit main-then-tag
pushes, note-derived annotated tags, and bounded failed-push state checks.
Disposable Git fixtures covered success, refusals, branch-only progress,
conflicting tags, and unknown outcomes without contacting the real remote.
Bash syntax checks, focused tests, the offline default suite, local links, and
whitespace review passed.
Add executable `scripts/release.sh`, calling the existing validator once rather
than duplicating it. Replace `TestReleaseRunbookGuards` with tests of the actual
script: prose headings cease to be an executable interface. Update the release
policy and runbook in this stage to describe implemented behavior and recovery.
### Candidate and publication flow
1. Accept exactly one stable version argument using the existing no-leading-zero
Semantic Version format. Require `main` and a clean index/worktree including
nonignored untracked files. Ignored local files alone do not block release.
Verify the existing authoritative `origin` endpoint and ensure pushes actually
target it, accounting for separately configured push URLs and multiple push
destinations. Do not publish to an unnoticed additional destination or print
credentials in diagnostics.
2. Capture the full candidate commit ID. Read `docs/releases/<version>.md` from
that commit and require the first line `# ConfigKit <version>`. Meaningful
summary and applicable compatibility/upgrade content are ordinary preparation,
not automated prose judgments or four mandatory headings. Retain the existing
footer and local note-review requirements without a new network check.
3. Require the version unused locally and on the authoritative remote. Query the
exact remote tag, distinguishing absence from query failure. Read remote main
and check that publication can advance it without discarding history; main
already at the candidate is acceptable. No all-remotes or all-tags survey.
4. Run `scripts/release-check.sh` once. Failure stops before any push/tag creation.
Recheck branch, cleanliness, candidate identity, and unused version state after
validation. Changed candidates require a fresh invocation after correction and
commit; do not automatically commit or repair the checkout.
5. Push the captured commit explicitly to `refs/heads/main`, without force or
incidental follow-tags publication. Override broad configured push defaults
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
branch/destination, dirty/changed candidate, missing/mismatched note, local/remote
tag collision, failed validation, non-fast-forward main, and the meaningful
failure outcomes above. A note without empty boilerplate headings must pass.
Assert resulting refs and exit status, not helper structure or exact diagnostics.
Verify completion has no CI/consumer-tool dependency.
Acceptance: Bash syntax checks, focused checker/publication tests, and the offline
default suite pass. The script is tested only against fixtures. Current docs must
no longer require a manually recorded candidate before single-command publication.
## Stage 3 — Complete documentation alignment and integrated validation
**Completed 2026-09-28.** Reconciled the adopted release policy with its pinned
upstream source and ConfigKit decisions; aligned the runbook, development guide,
and roadmap records with the implemented command. Bash syntax, focused release
tests, local documentation links, whitespace review, and the final real baseline
release checker passed on Linux. No publication or push was performed.
Reconcile `docs/policy/release.md` with the pinned upstream release policy. Adopt
shared paragraphs verbatim except for substantive local decisions. Remove the
temporary deferral, all-remotes freshness rule, and stale prospective v0.3.0 note
instruction. Preserve known-published-version nonreuse, ConfigKit compatibility,
source-only deliverables, annotated tags, selected gate rationale, Linux support,
best-effort macOS, no-CI completion, and historical exceptions. No compensating
controls are required merely to use successful-tag-push completion.
Keep base version 1.4 and its existing pinned source; update the local date.
Existing attribution and license scope already cover these edits. Do not change
other policies, copyright/license grants, or historical release notes unnecessarily.
Review `docs/release.md` as the operational owner: preparation, one publication
command, completion, partial/unknown-state recovery, and distinctly optional
diagnostics. Retain exact version-specific licensing footer URLs and optional
consumer retrieval; neither adds a network gate. Remove duplicate manual publish
instructions. Update `docs/development.md` navigation, gate summary, and test map.
Search active documentation/scripts for stale candidate-file, section-template,
module-tidiness gate, CI-wait, and manual publication instructions. Fix affected
links without rewriting historical records.
Correct the completed policy roadmap's implementation-record reference to
`faf5ff8:docs/roadmap/implementation.md`, since this path now owns the new plan.
Mark release-roadmap implementation status accurately after acceptance. Preserve
unfinished/deferred work; retirement belongs to actual release preparation.
Run Bash syntax checks, focused orchestration tests, documentation-link tests,
and `git diff --check`. Run the revised real release checker once on the final
implementation with prepared baseline dependencies. Reuse that successful suite
result instead of separately repeating examples, boundaries, vet, builds, or the
everyday suite. Report missing prerequisites rather than claiming success. Never
invoke publication against origin as an acceptance test.
Acceptance: scripts, policy, and runbook agree; tests protect selected behavior
without extra contracts; current docs describe only implemented behavior. Commit
each completed unit with a plain-English message and report validation/workspace
state without publishing. No product decisions remain open in this plan.

View File

@@ -1,19 +0,0 @@
# Standard Policy Documentation Alignment
Status: implemented on 2026-09-28. The completed implementation record and
validation evidence are preserved at `faf5ff8:docs/roadmap/implementation.md`.
ConfigKit's seven [adopted policies](../policy/meta.md) now identify the pinned
Standard Repository Policies revision
`d84a38ebab26f048cafbe59a2246700c35d29843` and their local adaptations.
The [developer guide](../development.md#policy-reading-guide) routes tasks to
applicable policies. [COPYRIGHT](../../COPYRIGHT) and the
[attribution notices](../oss/attribution.md) identify the separately licensed
adapted policy and orientation material.
The [release policy](../policy/release.md) and
[maintainer runbook](../release.md) own current release requirements and
operations. The separate [release-workflow roadmap](release.md) records the
subsequent publication-automation work.
These completed records remain until normal release preparation retires them.

View File

@@ -1,126 +0,0 @@
# Single-Command Release Workflow and Gate Review
Status: implemented on 2026-09-28. The
[implementation plan](implementation.md) records the completed work and checks.
## Intent and baseline
Make source releases simple for humans and agents: one publication command
validates the final committed candidate, checks publication state, and publishes
only the intended refs. Keep the minimum gates justified by ConfigKit's actual
risks, with no routine human intervention or waiting for CI.
Local baseline: `0adb94f59e44827908eff401d4381a398fe17107` (v0.4.1).
The upstream reference is release policy v1.4 at
`d84a38ebab26f048cafbe59a2246700c35d29843`:
[standard release policy](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/release.md).
At the planning baseline, `scripts/release-check.sh` performed local validation; the runbook separately
records a candidate commit and executes shell blocks for guards, branch push,
annotated tagging, and tag push. The checker runs module hygiene, formatting and
whitespace checks, one race-enabled suite, vet, and Linux amd64/arm64 cross-builds
using a maintained Go 1.25 patch. Publication completes on successful tag push.
The implementation plan records the subsequent gate selection and publication
command. Current requirements belong to the
[release policy](../policy/release.md) and [runbook](../release.md).
## Target release contract
ConfigKit remains a source-only Go module hosted at its authoritative Gitea
remote. Releases identify a final committed source revision on `main`, one fresh
immutable annotated version tag, and a matching checked-in release note.
No binary distribution, hosted release object, or registry publication is added.
The publication command owns validation, candidate identity, guards, and explicit
ref publication. Preparation still supplies the version, committed release note,
and dependencies/toolchain; the command must not silently edit or commit source,
choose a version, or upgrade dependencies. Publication remains subject to user
authorization, not the standing local-commit policy.
The command validates the exact candidate once. An optional validation-only mode
may support diagnosis but is not a prerequisite followed by duplicate validation.
Do not require both everyday and release checkers. An implementation need not
introduce a persistent validation cache merely to replace the former manual record.
Mechanical guards ensure a clean worktree/index on the primary branch, an unused
valid version locally and on the authoritative remote, a matching release note,
and exact agreement between validated source and tagged source. Publish only
intended refs without discarding remote history. Ignored local files are not
release content and do not alone prevent publication.
A successful intended tag push, with the source commit available on authoritative
main, completes the release. Never wait for or poll CI, module availability,
consumer installation, or optional verification. Do not add a successful-push
remote read-back gate. If future artifact channels are adopted, delivery status
must remain separate; this task introduces none.
## Selected gate rationale
Keep the full deterministic offline suite as the core check. The selected gates
below provide distinct protection without repeating validation. Their rationale
belongs in the adopted release policy, with commands in the runbook and tooling.
| Check | Selected end state and rationale |
| --- | --- |
| Race detector | One full race-enabled suite protects ownership and concurrent loads; no second ordinary suite. |
| Vet | One full vet pass provides additional static analysis; disable the smaller test-time vet pass to avoid overlap. |
| Module hygiene | Tidiness belongs to dependency-change review, not a recurring release audit. Offline tests/builds use readonly module mode to avoid incidental manifest edits. |
| Formatting and whitespace | Ordinary development checks, not publication gates; the everyday checker remains unchanged. |
| Linux amd64/arm64 builds | Retain both CGO-disabled builds: they cover supported configurations distinct from native race compilation. |
| Toolchain selection | One maintained Go 1.25 patch, with no second-toolchain gate or per-release latest-version research. |
Examples, consumer fixtures, documentation links, and import/public boundary tests
are already in the suite; they must not become separately repeated release checks.
macOS remains best-effort. No human sign-off, new linter, hardware requirement,
scanner, credentials-dependent test, or remote application probe is introduced.
## Documentation and recovery
Align `docs/policy/release.md` with upstream shared wording, preserving explicit
ConfigKit decisions and the selected gate rationale. The successful-tag-push rule
is a normal supported choice under the new upstream policy, not an exception
requiring newly invented compensating controls.
Make `docs/release.md` a short executable runbook for preparation and the single
command. New notes use a proportionate summary and applicable compatibility and
upgrade information rather than mandatory empty sections. Preserve the licensing
footer and version-specific immutable links. Derive annotated-tag summary content
from the checked-in note. Keep historical notes unchanged.
Validation or guard failure stops publication with actionable diagnostics and no
force updates. A failed or ambiguous push requires resolving authoritative remote
state before retrying or reporting success. A transient failure does not itself
require a new version. Published tags remain immutable; removing an unpublished
local tag requires confirmation it was never published. Explain partial progress
such as a successful branch push followed by a failed tag push.
## Changes needed and scope
The work affects `docs/policy/release.md`, `docs/release.md`, release shell tooling,
`release_check_test.go`, and relevant contributor guidance. Reuse existing
validation mechanisms where appropriate; avoid a general release framework.
Tests should exercise success and meaningful failure/recovery paths in disposable
local repositories, without real publication or credentials. Match coverage to
the chosen push strategy and protect against unintended refs or stale candidates.
Preserve provenance and licensing established by the completed
[policy roadmap](policy.md).
Operational documentation changes land with the implementation they describe.
No library behavior, dependency update, release tag, or push is authorized by
implementing this roadmap alone.
## Publication strategy
Use explicit main-then-tag pushes inside the command. This matches the proven
local workflow and avoids a new dependency on atomic-push support. A branch-only
intermediate result is possible; recovery distinguishes it from completed or
unknown publication. Atomic publication is not part of this target.
## Completion criteria
One documented command publishes a prepared candidate with the reviewed minimum
gate set, no duplicate suite runs, and automated exact-source safeguards. Local
regression tests demonstrate successful publication and safe failure handling.
The policy, runbook, and scripts agree, and successful tag publication is reported
without waiting for external completion evidence.

View File

@@ -1,84 +0,0 @@
# Release Workflow Review Findings
Status: both findings addressed. The original findings below are retained as
review history until normal release-preparation retirement.
## Resolution and verification
- Publication, fetch, and recovery now use the same validated named `origin`.
Pushes retain exact refspecs and disabled implicit tags, and override the
remote's mirror default for that invocation only. No new gate was introduced.
- A disposable-Git regression failed against the original publisher and passes
with the fix for normal publication and lost main/tag push responses. It also
checks that broad push defaults do not publish or delete unrelated refs and
that the rewrite destination receives no refs.
- Optional consumer verification explicitly initializes the selected version.
Executing the documented block with a local Go stub verified the exact module
argument with both an initially unset and an initially stale version variable,
without network retrieval.
- Focused publication tests passed. Final validation passed: Bash syntax,
whitespace review, and the Go 1.25.14 release checker (race suite including
documentation links, full vet, and both Linux target builds).
Reviewed implementation through `3d0093e` against the release roadmap and
completed implementation plan. The ordinary Go 1.25.14 release checker passed
(offline race suite, full vet, Linux amd64/arm64 builds), as did Bash syntax
checks. These findings concern publication destination integrity and a runbook
example; no library changes or additional release gates are needed.
## 1. Align destination validation with actual push resolution (high priority)
**Locations:** `scripts/release.sh:56–59`, `:91`, and `:116`;
regression coverage in `release_publish_test.go`.
The guard inspects `git remote get-url --push --all origin`, but both pushes use
the literal URL instead of the inspected remote. Git treats these differently
when `origin` has an explicit push URL and a matching `url.<other>.pushInsteadOf`
rule. The explicit remote push URL bypasses that rule for the guard; passing the
literal URL to `git push` applies the rule.
Reproduced with two disposable bare repositories A (authoritative) and B:
1. Set origin's fetch URL and explicit push URL to A.
2. Configure `url.<B>.pushInsteadOf` to match A.
3. Prepare main and a matching release note. Run a fixture copy of the actual
publisher with A substituted for the authoritative URL and a successful
checker stub, as in the existing publication fixtures.
Both guard queries return A. The publisher nevertheless pushes main and the
annotated tag to B and reports `Published`; A still has the old main and no
release tag. Recovery queries also inspect A rather than the push destination.
This violates the already-selected authoritative-destination and completion
contract; it is not a request for broader Git hardening.
**Required correction:** make guard, push, and recovery destination resolution
agree. Use a consistent validated target rather than assuming a literal URL
bypasses Git URL rewriting. Preserve explicit refspecs, non-force publication,
and suppression of unrelated tags/configured broad push behavior. Do not add
successful-push read-back, blanket Git configuration bans, or new human gates.
**Acceptance:** add a real local-Git regression for the configuration above.
Publication must either use the confirmed authoritative destination or refuse
before any publication; B must receive no refs. Preserve existing ordinary
success, multiple-destination refusal, and ambiguous-push recovery coverage.
## 2. Initialize the version in optional consumer verification (low priority)
**Location:** `docs/release.md:177–194`.
The optional `go get` example expands `$release_version`, but the successful
publication example passes a literal version to the script and never initializes
that shell variable. Its only assignment is in the failure-recovery section,
which successful releases do not need to execute. The optional example therefore
uses an unset variable (or a stale version from the caller's shell) instead of
the release just published.
**Required correction:** explicitly set the selected version in the optional
example, or consistently establish it in the normal preparation/publication
instructions and explain that prerequisite. Keep verification optional and
non-gating.
**Acceptance:** follow the successful path in a fresh shell without running
recovery instructions and confirm that the optional example constructs the
intended exact module/version argument. A local stub is sufficient; no production
module retrieval or new recurring test/gate is needed.