223 lines
14 KiB
Markdown
223 lines
14 KiB
Markdown
# 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.
|