Align release policy and operational documentation

This commit is contained in:
2026-09-28 01:13:09 +00:00
parent 299ebc21a9
commit 3d0093e1fd
7 changed files with 242 additions and 177 deletions

View File

@@ -64,7 +64,8 @@ git show cb5b435:docs/roadmap/remediation.md
``` ```
Release-candidate, publication, and verification work follows the operational Release-candidate, publication, and verification work follows the operational
[release procedure](release.md). [release procedure](release.md). Its single publication command validates the
committed candidate and publishes only the intended refs.
The completed string-and-integer schema-version implementation and remediation The completed string-and-integer schema-version implementation and remediation
records are preserved in Git history at `244104f`. The records are preserved in Git history at `244104f`. The
@@ -116,9 +117,9 @@ Use focused checks while iterating, with validation proportionate to the change
under the testing policy. Documentation-only work normally needs the local-link under the testing policy. Documentation-only work normally needs the local-link
check below and whitespace review; behavior-bearing examples and commands also check below and whitespace review; behavior-bearing examples and commands also
need execution. Use `go test -race ./...` for ownership or concurrency changes. need execution. Use `go test -race ./...` for ownership or concurrency changes.
The [release checker](release.md#4-publish-the-committed-candidate) performs one The [publication command](release.md#4-publish-the-committed-candidate) invokes
minimum-toolchain offline race-suite run, one full vet pass, and Linux the release checker once. It performs one minimum-toolchain offline race-suite
cross-builds using readonly module mode. run, one full vet pass, and Linux cross-builds using readonly module mode.
It already covers examples, links, and package boundaries; do not additionally It already covers examples, links, and package boundaries; do not additionally
run the everyday checker just to repeat those checks. CI never gates a release. run the everyday checker just to repeat those checks. CI never gates a release.
@@ -139,7 +140,8 @@ code changes. Use the component overview to find the corresponding implementatio
| Secrets, bootstrap, redaction, explanation | [References](../internal/engine/secret_reference_test.go), [bootstrap](../internal/engine/secrets_test.go), [rendering](../internal/engine/render_test.go), [explanation](../internal/engine/explain_test.go) | `go test ./internal/engine -run 'Secret\|Bootstrap\|Effective\|Explain\|Explanation\|History\|Sensitivity'` | | Secrets, bootstrap, redaction, explanation | [References](../internal/engine/secret_reference_test.go), [bootstrap](../internal/engine/secrets_test.go), [rendering](../internal/engine/render_test.go), [explanation](../internal/engine/explain_test.go) | `go test ./internal/engine -run 'Secret\|Bootstrap\|Effective\|Explain\|Explanation\|History\|Sensitivity'` |
| Consumer examples and migration fixtures | [Consumer tests](../examples/consumers/consumers_test.go), [API examples](../example_test.go) | `go test ./examples/consumers` and `go test . -run '^Example'` | | Consumer examples and migration fixtures | [Consumer tests](../examples/consumers/consumers_test.go), [API examples](../example_test.go) | `go test ./examples/consumers` and `go test . -run '^Example'` |
| Documentation links and dependency isolation | [Link checks](../documentation_test.go), [import boundary](../import_boundary_test.go), [public boundary](../public_boundary_test.go) | `go test . -run 'TestLocalDocumentationLinks\|TestDependencyImportBoundary\|TestPublicFacadeBoundary'` | | Documentation links and dependency isolation | [Link checks](../documentation_test.go), [import boundary](../import_boundary_test.go), [public boundary](../public_boundary_test.go) | `go test . -run 'TestLocalDocumentationLinks\|TestDependencyImportBoundary\|TestPublicFacadeBoundary'` |
| Check-command behavior | [Shell regression](../release_check_test.go) | `go test . -run '^TestCheckScripts'` | | Development and release checker behavior | [Shell regression](../release_check_test.go) | `go test . -run 'TestCheckScripts\|TestDevelopmentCheck'` |
| Guarded release publication and recovery | [Publication regression](../release_publish_test.go) | `go test . -run '^TestReleasePublication'` |
## Fuzz validation ## Fuzz validation

View File

@@ -6,9 +6,6 @@
**Upstream Source:** [Standard Repository Policies](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/release.md) **Upstream Source:** [Standard Repository Policies](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/release.md)
ConfigKit's [release procedure](../release.md) uses one publication command
with the selected local checker and explicit main-then-tag pushes.
## Purpose ## Purpose
This policy defines a proportionate workflow for validating and publishing an This policy defines a proportionate workflow for validating and publishing an
@@ -19,28 +16,21 @@ The repository-specific commands belong in `docs/release.md`. Historical release
summaries belong in `docs/releases/`. The procedure must agree with the adopted summaries belong in `docs/releases/`. The procedure must agree with the adopted
policy and link to it rather than introduce additional release requirements. policy and link to it rather than introduce additional release requirements.
## ConfigKit applicability ## ConfigKit Applicability
ConfigKit adopts a source-only Go module release model. The source tag and ConfigKit publishes a source-only Go module. Its declared deliverables are the
version-matched release note are the declared deliverables. Standalone binaries, immutable annotated source tag and version-matched checked-in release note.
container images, and separate binary/package-registry publication are not Standalone binaries, container images, hosted release objects, and separate
required. This does not waive source compilation, dependency maintenance, testing, or registry publication are not required. Additional channels require a deliberate
local target-build validation. Post-publication consumer retrieval is optional, update to the policy and procedure.
as described under Release Model.
The release procedure must define the module path, authoritative remote, The Go API, documented YAML and resolution semantics, and structured diagnostic
supported Go versions and operating-system/architecture targets, prerequisite contracts participate in compatibility review. A signature-preserving change
dependency acquisition, and the exact verification commands once established.
The default tests themselves remain deterministic and offline. Additional
publication channels require documented deliverables and verification before use.
The Go API, documented YAML/resolution semantics, and structured diagnostic
contracts all participate in compatibility review. A signature-preserving change
can still break consumers. Human diagnostic wording is stable only where a can still break consumers. Human diagnostic wording is stable only where a
contract expressly promises it. Minimum Go version and platform support changes contract expressly promises it. Minimum Go version and platform support
also require an explicit compatibility assessment. changes also require an explicit compatibility assessment.
### Platform support ### Platform Support
Linux is the release-validated platform. macOS has best-effort support: keeping Linux is the release-validated platform. macOS has best-effort support: keeping
it working remains desirable, but neither native macOS validation nor Darwin it working remains desirable, but neither native macOS validation nor Darwin
@@ -49,50 +39,59 @@ does not by itself block a release. Voluntary checks and fixes are welcome; ther
is no guarantee that each release has been validated on macOS. is no guarantee that each release has been validated on macOS.
The [release procedure](../release.md#release-identity-and-support) owns target The [release procedure](../release.md#release-identity-and-support) owns target
architectures and required Linux checks. This support change applies to upcoming architectures and required Linux checks. Historical release notes and their
releases; historical release notes and their validation records remain unchanged. validation records remain unchanged.
The v0.3.0 release note must explain the change in Compatibility, with version
selection following this policy's existing compatibility rules.
## Release Model ## Release Model And Completion
A source release identifies one exact committed source revision through an A source release identifies one exact committed source revision through an
immutable version tag and a version-matched, checked-in release note. ConfigKit's immutable version tag and a version-matched, checked-in release note. The
primary release branch is `main`; its tags are annotated. The primary release branch is `main` unless the adopted policy specifies otherwise.
[release procedure](../release.md) names the authoritative publication remote. The procedure must name the authoritative publication remote.
A successful push of the intended tag, with its source commit available on the A successful push of the intended tag, with its source commit available on the
authoritative primary branch, completes the release. ConfigKit publishes the authoritative primary branch, completes the release. The source commit may be
committed candidate to `main` before pushing only the intended tag. pushed before the tag or published together with it through an atomic push.
The procedure must choose and document the supported approach.
ConfigKit uses sequential explicit pushes: first the captured candidate to
authoritative `main`, then the annotated tag. Its
[release procedure](../release.md) names `origin` and checks that its fetch and
push destinations resolve to the authoritative URL.
Release commands must finish at successful publication. They must not wait for Release commands must finish at successful publication. They must not wait for
or poll CI, require successful CI status, inspect downloadable artifacts, or or poll CI, require successful CI status, inspect downloadable artifacts, or
check consumer installation or Go module availability as completion gates. check consumer installation or Go module availability as completion gates.
Optional remote tag read-back and fresh consumer retrieval do not delay release
completion.
A failed or ambiguous push requires resolving the authoritative remote state A failed or ambiguous push requires resolving the authoritative remote state
before declaring success or retrying; successful pushes do not require a before declaring success or retrying; successful pushes do not require a
separate remote read-back gate. separate remote read-back gate.
ConfigKit publishes source only. If additional deliverables are deliberately Remote tag read-back and fresh consumer retrieval are optional and non-gating
adopted, they must be traceable to the tagged source, identify the same version, after successful publication. A failed push receives one bounded check of the
and have documented publication responsibilities and verification. authoritative ref; do not poll or blindly retry.
Release automation may validate or publish a release only when its exact Repositories may publish source only. Additional binaries, images, packages,
responsibility is documented. Automation must not silently change the source checksums, or other declared deliverables may be published asynchronously from
candidate, move a published tag, replace a published deliverable, or repair a the tagged source. The procedure must identify those deliverables and the
release in place. responsibility of their automation. Published deliverables must be traceable
to that source and identify the same version.
ConfigKit currently declares no additional deliverables. Its source-tag push
is the completion point.
## Versioning And Compatibility ## Versioning And Compatibility
Stable releases use Semantic Versioning in the form `vMAJOR.MINOR.PATCH`, with Stable releases use Semantic Versioning in the form `vMAJOR.MINOR.PATCH`, with
no leading zeroes. The selected version must be unused locally and on the no leading zeroes. Prereleases require an explicit adopted policy defining
authoritative remote. A version known to have been published elsewhere must their format and use.
not be reused.
Unless an adopted policy explicitly supports and defines prereleases, ConfigKit does not support prereleases.
prerelease versions are not permitted.
The selected version must be unused locally and on the authoritative remote.
Do not require queries to every configured remote or publication service.
A version known to have already been published must not be reused, even if the
normal guards do not inspect that channel. Adding a distribution channel
requires a deliberate update to the policy and procedure where needed.
For releases at or after `v1.0.0`: For releases at or after `v1.0.0`:
@@ -105,89 +104,123 @@ configuration, data, integration, or compatibility contract when the release
note explains the impact and required consumer action. A patch release must note explains the impact and required consumer action. A patch release must
not intentionally break those contracts within its minor line. not intentionally break those contracts within its minor line.
A repository with additional compatibility promises must define them in its Additional compatibility promises and deliberate exceptions belong in the
adopted policy or canonical contract documentation. A release note may explain adopted policy or canonical contract documentation. Release notes explain
a compatibility change, but it must not redefine the current compatibility changes; they do not redefine current compatibility contracts.
contract.
## Release Documentation ## Release Documentation And Preparation
Every release made under this policy must include Every new release must include `docs/releases/<version>.md` in the tagged
`docs/releases/<version>.md` in the tagged source tree. The filename must use source tree. Use the complete version tag as the filename and begin with a
the complete version tag, and the document must begin with a title containing title containing the product name and that exact version.
the product name and that exact version.
ConfigKit requires the first line `# ConfigKit <version>`.
Include a short summary and any relevant compatibility impact or upgrade Include a short summary and any relevant compatibility impact or upgrade
instructions. Choose sections suited to the release and keep the note instructions. Choose sections suited to the release and keep the note
proportionate to the change. The annotated tag's message is the checked-in note. proportionate to the change.
Release notes are immutable historical summaries. They should link to current Keep exact current contracts in their canonical documents and update affected
canonical documentation for exact behavior. Every affected canonical document documentation with the behavior change. Link to those documents from the note
must be updated in the same candidate; a release note must not substitute for where useful. If annotated tags are used, derive their summary from the
current documentation or defer required documentation changes. checked-in note.
Each new release note must end with the release navigation defined by the ConfigKit uses the complete checked-in note as the annotated tag message.
[OSS policy](oss.md#discoverability). Preserve those links on a hosted download
page if one is used. The release procedure owns URL construction and channel
treatment. This is ordinary preparation, not a new network check or approval
gate; historical release notes are unchanged.
## Candidate Preparation And Validation Include the release footer defined by the [OSS policy](oss.md#discoverability)
in each new release document. The release procedure defines the concrete URLs
and publication mechanics. Prepare these links with the release note; they do
not add a network check or approval gate. If a hosted download page is used in
a future channel, preserve the footer there.
The publication command validates the final committed candidate once with Handle version selection, release-note content, and retirement of completed
ConfigKit's local release checker, using one maintained patch of the minimum roadmaps during preparation. Preserve planned and deferred work and repair
supported Go line on Linux. The checker runs one full offline race suite, one affected links when retiring roadmaps. Reuse ordinary change review for
full vet pass, and CGO-disabled Linux amd64/arm64 builds. The race suite unintended files, credentials, and private data. Scope release-content review
protects library behavior, ownership, to the tagged source.
and concurrent use; it includes examples, documentation links, consumer fixtures,
and package boundaries without separate runs. Full vet checks more than the
subset normally run by tests, so test-time vet is disabled. The two cross-builds
cover supported configurations that native race compilation does not. A second
toolchain is optional and non-gating.
All Go checks use readonly module mode and an offline dependency cache. ## Candidate Validation
Formatting and whitespace remain ordinary development checks. Review module
tidiness when dependencies change, rather than auditing it on every release.
Commit the release note and associated changes before release validation. The Provide one publication command that validates the final committed candidate,
publication command captures the exact candidate and rechecks it after the checks publication state, and publishes the intended refs. A validation-only
validator. A changed candidate requires a fresh invocation and validation. mode or command may be provided for diagnosis, but must not be a required step
Do not publish uncommitted or unvalidated content. Local check failures still before publication repeats the same checks.
block publication. Skipped test cases are reported, not separate human sign-off
requirements.
Compatibility review, release-note accuracy, removal of completed roadmaps, and ConfigKit uses `./scripts/release.sh vMAJOR.MINOR.PATCH`. The separate
review for unintended files, credentials, private data, and unrelated changes `scripts/release-check.sh` remains an optional diagnostic command; the
are ordinary preparation. The executing agent may perform them without routine publication command invokes it once and does not use a persistent candidate
human approval or separate manual evidence records. Ask the maintainer only for record.
genuine unresolved decisions or missing authority. A clean existing checkout is
sufficient; a dedicated clone is optional. Dependency and toolchain update Run the complete deterministic, offline default test suite once for the final
research belongs to maintenance or relevant changes, not every release. candidate, following the [testing policy](testing.md). For repositories that
publish builds, verify the required build targets. Select those targets for
the application's actual support commitments; native testing on each platform
and access to particular hardware are not default release prerequisites.
ConfigKit's one maintained Go 1.25 baseline runs the full suite with the race
detector and test-time vet disabled. This protects library behavior, ownership,
and concurrent use; the suite already includes examples, consumer fixtures,
documentation links, and package boundaries. One full vet pass adds static
checks beyond the test-time subset. CGO-disabled Linux amd64 and arm64 builds
cover supported configurations distinct from native race compilation. macOS
and newer-toolchain checks are optional.
Additional gates must address a concrete risk that the existing checks do not
adequately cover. Do not automatically require linting, race testing, module
hygiene audits, documentation audits, credential scans, example validation, or
expanded platform matrices solely because they are possible. Retain such
checks when their distinct protection justifies their cost. A one-time migration
check must not silently become a permanent release requirement.
The selected Go commands use readonly module mode with `GOPROXY=off`; acquire
the baseline toolchain and dependencies before validation. Formatting and
whitespace remain ordinary development checks in `scripts/check.sh`.
Review module tidiness when dependencies change, not as a release gate.
Release tests must not require real credentials, mutable application services,
paid APIs, provider probes, or inference calls. The procedure may describe dependency
preparation separately from offline validation.
Avoid duplicate validation across release phases. Successful checks for the
same final candidate need not be repeated solely to satisfy another phase;
any reuse must clearly apply to that exact candidate. Persistent validation
caches are not required. If the candidate changes, validate the new candidate.
Cheap publication-state checks may be repeated immediately before pushing
because local or remote state may have changed during validation.
Automate mechanical guards. Human review gates are strongly disfavored: add one
only through an explicit project-specific policy decision explaining the
concrete risk and why ordinary change review or automation is insufficient.
Do not add routine confirmations for checks the command can perform itself.
Compatibility review, release-note accuracy, completed-roadmap retirement, and
review for unintended files or credentials remain ordinary preparation. The
executing agent may perform them without routine human approval or separate
manual evidence records. Publication itself requires authorization.
## Publication Guards ## Publication Guards
Publication requires authorization before invoking the command. The command Automate the checks needed to publish the intended source under a fresh version:
must verify all of the following:
- the stable version has the required format and is unused locally and on the - the version has the adopted format and is unused locally and on the
authoritative remote; authoritative remote;
- the current branch is `main`, and the worktree and index are clean; - the worktree and index are clean on the primary release branch;
- the committed source and matching release note identify the exact validated - the source being published is the exact candidate that passed validation,
candidate; including its matching release note;
- the authoritative remote main can advance to that candidate without - the remote primary branch can be advanced to that candidate without
discarding history; discarding remote history, and is published before the tag; and
- the local automated gates succeeded for that commit; and - the tag identifies the validated candidate and only the intended refs are
- the annotated tag identifies that candidate and only the intended refs are
published. published.
Push the exact candidate to authoritative main, then create and verify the ConfigKit also checks that `origin` has exactly the authoritative fetch and
annotated tag before pushing only its ref. Do not use `git push --tags` or push destination, including configured push URLs. The command checks the
implicit follow-tags publication. A failed or ambiguous push receives one candidate and unused version again after validation, and checks local state
authoritative-state check before success, rejection, or unknown status is before creating the tag. Ignored local files do not block publication.
reported.
The repository-specific procedure must make these guards executable or give Fetch the authoritative branch and tag state as needed for these checks.
copyable commands for performing them. Do not force branch or tag updates to bypass a failed guard. Publish explicit
refs rather than all local tags. Do not require CI success, publication-service
availability checks, or a separate manual confirmation for each guard.
## Immutability And Correction ## Immutability And Correction
@@ -201,33 +234,33 @@ rerun the publication command. If a push fails or its outcome is ambiguous,
inspect the authoritative remote before retrying. Remove an unpublished local inspect the authoritative remote before retrying. Remove an unpublished local
tag only after confirming it was never published or used by a release channel. tag only after confirming it was never published or used by a release channel.
An unavailable remote leaves publication status unknown; do not overwrite a tag An unavailable remote leaves publication status unknown; do not overwrite a tag
to resolve uncertainty. A transient transport failure alone does not require to resolve uncertainty.
a new version.
If publication or post-publication verification reveals a defect, leave the Transient network, authentication, CI, or consumer-availability failures do not
published release intact. Correct the defect on the primary branch, choose a by themselves require a new version.
new patch version or other semantically appropriate new version, write a new
matching release note, and perform the complete release procedure again.
A distribution channel's supported yank, deprecation, or advisory mechanism A defect requiring changes to published source or contents requires a corrected
may warn consumers away from a defective release, but it must not replace that commit, a new semantically appropriate version, a matching release note, and
release's contents or reuse its version. the release procedure again. Leave the original release intact. A channel's
yank, deprecation, or advisory mechanism may warn consumers away from a defective
release without replacing its contents or reusing its version.
## Repository Release Procedure ## Repository Release Procedure
Maintain `docs/release.md` as the executable maintainer runbook. It identifies Maintain `docs/release.md` as a short, executable maintainer runbook. It must
prerequisites, version and note preparation, the single publication command, identify prerequisites, the primary branch and authoritative remote, version
declared deliverables and build targets, successful-tag-push completion, and and note preparation, one publication command with local checks and guards,
partial or unknown-state recovery. Keep optional diagnostics and consumer source-only deliverables, the successful-tag-push completion point, and
verification clearly optional. The procedure must agree with this policy. partial or unknown-state recovery.
Use copyable commands where practical. Keep optional diagnostics and consumer
verification clearly optional. The procedure must not turn preparation work,
ordinary change review, or post-publication investigation into additional
release gates.
## Policy Exceptions ## Policy Exceptions
Any exception to this policy must be explicitly documented in this section, The following historical exceptions do not change the current release workflow.
including the repository constraint requiring it, its rationale, scope, and
compensating controls. Customizing release mechanics must not silently weaken
the policy's integrity, validation, documentation, verification, or immutability
requirements.
For v0.1.1 only, the maintainer approved renaming the reserved `_configkit` key to For v0.1.1 only, the maintainer approved renaming the reserved `_configkit` key to
`configkit` as an error-correcting point release because there are no current `configkit` as an error-correcting point release because there are no current

View File

@@ -124,12 +124,21 @@ success. Otherwise it reports branch-only, conflicting, or unknown state and
retains any local tag. retains any local tag.
Inspect exact refs before any retry. Set `release_version` to the attempted Inspect exact refs before any retry. Set `release_version` to the attempted
version and compare main with the candidate printed or recorded from the run: version and compare main with the candidate from the command's report:
```sh ```sh
release_version=v0.5.0 release_version=v0.5.0
authoritative=https://gitea.maximumdirect.net/eric/ConfigKit.git authoritative=https://gitea.maximumdirect.net/eric/ConfigKit.git
git ls-remote --refs --exit-code "$authoritative" refs/heads/main if remote_main=$(git ls-remote --refs --exit-code "$authoritative" refs/heads/main); then
printf 'remote main: %s\n' "$remote_main"
else
result=$?
if [ "$result" -eq 2 ]; then
printf 'authoritative main confirmed absent\n' >&2
else
printf 'remote main state unknown; inspect before retrying\n' >&2
fi
fi
ref="refs/tags/$release_version" ref="refs/tags/$release_version"
if remote_tag=$(git ls-remote --refs --exit-code "$authoritative" "$ref"); then if remote_tag=$(git ls-remote --refs --exit-code "$authoritative" "$ref"); then
printf 'remote tag: %s\n' "$remote_tag" printf 'remote tag: %s\n' "$remote_tag"
@@ -141,7 +150,11 @@ else
printf 'remote tag state unknown; do not reuse the version\n' >&2 printf 'remote tag state unknown; do not reuse the version\n' >&2
fi fi
fi fi
git rev-parse --verify "refs/tags/$release_version" if local_tag=$(git rev-parse --verify "refs/tags/$release_version" 2>/dev/null); then
printf 'local tag object: %s\n' "$local_tag"
else
printf 'no local tag object\n'
fi
``` ```
A query failure is not proof that the tag is absent. Compare the remote tag A query failure is not proof that the tag is absent. Compare the remote tag
@@ -168,5 +181,17 @@ version into a new module without a local `replace` directive. These checks
are optional and non-gating. Do not poll CI or wait for module propagation. are optional and non-gating. Do not poll CI or wait for module propagation.
Private-host credentials must already be configured. For direct-origin Private-host credentials must already be configured. For direct-origin
verification, use a temporary consumer module and check the exact module path verification, use a temporary consumer module and check the exact module path
and version reported by `go list -m`. Report optional verification separately and version reported by `go list -m`:
from publication success.
```sh
consumer_dir=$(mktemp -d)
(
cd "$consumer_dir"
go mod init example.invalid/configkit-release-check
GOPRIVATE=gitea.maximumdirect.net GOPROXY=direct go get "gitea.maximumdirect.net/eric/ConfigKit@$release_version"
go list -m -f '{{.Path}} {{.Version}}' gitea.maximumdirect.net/eric/ConfigKit
)
```
The output should show the exact module path and selected version. Report this
optional check separately from publication success.

View File

@@ -1,6 +1,6 @@
# Release Workflow Implementation Plan # Release Workflow Implementation Plan
Status: ready for implementation; no stages completed by this planning pass. Status: implemented on 2026-09-28. All stages are complete.
Implement the [release roadmap](release.md) in the numbered order below. Each 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 stage is a bounded work unit for a gpt-5.6-terra coding agent; finish its tests
@@ -177,6 +177,12 @@ no longer require a manually recorded candidate before single-command publicatio
## Stage 3 — Complete documentation alignment and integrated validation ## 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 Reconcile `docs/policy/release.md` with the pinned upstream release policy. Adopt
shared paragraphs verbatim except for substantive local decisions. Remove the shared paragraphs verbatim except for substantive local decisions. Remove the
temporary deferral, all-remotes freshness rule, and stale prospective v0.3.0 note temporary deferral, all-remotes freshness rule, and stale prospective v0.3.0 note

View File

@@ -1,7 +1,7 @@
# Standard Policy Documentation Alignment # Standard Policy Documentation Alignment
Status: implemented on 2026-09-28. The [implementation record](implementation.md) Status: implemented on 2026-09-28. The completed implementation record and
contains the completed stages and validation evidence. validation evidence are preserved at `faf5ff8:docs/roadmap/implementation.md`.
ConfigKit's seven [adopted policies](../policy/meta.md) now identify the pinned ConfigKit's seven [adopted policies](../policy/meta.md) now identify the pinned
Standard Repository Policies revision Standard Repository Policies revision
@@ -11,10 +11,9 @@ applicable policies. [COPYRIGHT](../../COPYRIGHT) and the
[attribution notices](../oss/attribution.md) identify the separately licensed [attribution notices](../oss/attribution.md) identify the separately licensed
adapted policy and orientation material. adapted policy and orientation material.
The [release policy](../policy/release.md) retains ConfigKit's existing The [release policy](../policy/release.md) and
operational requirements. The [maintainer runbook](../release.md) remains their [maintainer runbook](../release.md) own current release requirements and
command owner. The separate [release-workflow roadmap](release.md) owns future operations. The separate [release-workflow roadmap](release.md) records the
publication automation and gate review; this policy alignment did not implement subsequent publication-automation work.
that workflow.
These completed records remain until normal release preparation retires them. These completed records remain until normal release preparation retires them.

View File

@@ -1,7 +1,7 @@
# Single-Command Release Workflow and Gate Review # Single-Command Release Workflow and Gate Review
Status: accepted target; execution order and acceptance checks are defined in the Status: implemented on 2026-09-28. The
[implementation plan](implementation.md). [implementation plan](implementation.md) records the completed work and checks.
## Intent and baseline ## Intent and baseline
@@ -15,14 +15,15 @@ The upstream reference is release policy v1.4 at
`d84a38ebab26f048cafbe59a2246700c35d29843`: `d84a38ebab26f048cafbe59a2246700c35d29843`:
[standard release policy](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/release.md). [standard release policy](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/release.md).
Today, `scripts/release-check.sh` performs local validation; the runbook separately 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, records a candidate commit and executes shell blocks for guards, branch push,
annotated tagging, and tag push. The checker runs module hygiene, formatting and 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 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. using a maintained Go 1.25 patch. Publication completes on successful tag push.
These remain the current requirements until deliberately revised. This roadmap The implementation plan records the subsequent gate selection and publication
does not itself waive existing gates. command. Current requirements belong to the
[release policy](../policy/release.md) and [runbook](../release.md).
## Target release contract ## Target release contract
@@ -40,7 +41,7 @@ authorization, not the standing local-commit policy.
The command validates the exact candidate once. An optional validation-only mode The command validates the exact candidate once. An optional validation-only mode
may support diagnosis but is not a prerequisite followed by duplicate validation. may support diagnosis but is not a prerequisite followed by duplicate validation.
Do not require both everyday and release checkers. An implementation need not Do not require both everyday and release checkers. An implementation need not
introduce a persistent validation cache merely to replace today's manual record. 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 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, valid version locally and on the authoritative remote, a matching release note,
@@ -54,12 +55,11 @@ consumer installation, or optional verification. Do not add a successful-push
remote read-back gate. If future artifact channels are adopted, delivery status remote read-back gate. If future artifact channels are adopted, delivery status
must remain separate; this task introduces none. must remain separate; this task introduces none.
## Gate review target ## Selected gate rationale
Keep the full deterministic offline suite as the core check. The selected gates Keep the full deterministic offline suite as the core check. The selected gates
below provide distinct protection without repeating validation. Their rationale below provide distinct protection without repeating validation. Their rationale
belongs in the adopted release policy, with commands in the runbook and tooling belongs in the adopted release policy, with commands in the runbook and tooling.
once implemented.
| Check | Selected end state and rationale | | Check | Selected end state and rationale |
| --- | --- | | --- | --- |

View File

@@ -12,13 +12,13 @@ fail() {
} }
check_candidate() { check_candidate() {
local current status local context=$1 current status
current=$(git branch --show-current) || fail "cannot read the current branch" current=$(git branch --show-current) || fail "$context: cannot read the current branch"
[[ "$current" == main ]] || fail "release requires the main branch" [[ "$current" == main ]] || fail "$context: release requires the main branch"
status=$(git status --porcelain=v1 --untracked-files=all) || fail "cannot inspect the worktree" status=$(git status --porcelain=v1 --untracked-files=all) || fail "$context: cannot inspect the worktree"
[[ -z "$status" ]] || fail "release requires a clean index and worktree" [[ -z "$status" ]] || fail "$context: release requires a clean index and worktree"
current=$(git rev-parse --verify HEAD) || fail "cannot identify the candidate" current=$(git rev-parse --verify HEAD) || fail "$context: cannot identify the candidate"
[[ "$current" == "$candidate" ]] || fail "candidate changed; commit and validate it again" [[ "$current" == "$candidate" ]] || fail "$context: candidate changed; commit and validate it again"
} }
check_unused_version() { check_unused_version() {
@@ -59,7 +59,7 @@ push_urls=$(git remote get-url --push --all origin 2>/dev/null) || fail "origin
fail "origin must have exactly the authoritative fetch and push destination" fail "origin must have exactly the authoritative fetch and push destination"
candidate=$(git rev-parse --verify HEAD) || fail "cannot identify the candidate" candidate=$(git rev-parse --verify HEAD) || fail "cannot identify the candidate"
check_candidate check_candidate "before validation"
check_unused_version check_unused_version
note_path="docs/releases/$version.md" note_path="docs/releases/$version.md"
@@ -85,7 +85,7 @@ git merge-base --is-ancestor "$fetched_main" "$candidate" ||
fail "candidate cannot advance authoritative main without discarding history" fail "candidate cannot advance authoritative main without discarding history"
./scripts/release-check.sh || fail "release validation failed; no refs were published" ./scripts/release-check.sh || fail "release validation failed; no refs were published"
check_candidate check_candidate "after validation"
check_unused_version check_unused_version
if git push --no-follow-tags "$remote_url" "$candidate:refs/heads/main"; then if git push --no-follow-tags "$remote_url" "$candidate:refs/heads/main"; then
@@ -93,37 +93,37 @@ if git push --no-follow-tags "$remote_url" "$candidate:refs/heads/main"; then
else else
if observed_main=$(read_remote_ref refs/heads/main); then if observed_main=$(read_remote_ref refs/heads/main); then
[[ "$observed_main" == "$candidate" ]] || [[ "$observed_main" == "$candidate" ]] ||
fail "main push did not publish; authoritative main differs from the candidate" fail "main push did not publish candidate $candidate; authoritative main differs"
else else
result=$? result=$?
((result == 2)) && fail "main push failed; authoritative main is absent" ((result == 2)) && fail "main push failed for $candidate; authoritative main is absent"
fail "main push outcome is unknown; inspect authoritative main before retrying" fail "main push outcome is unknown for $candidate; inspect authoritative main before retrying"
fi fi
fi fi
check_candidate check_candidate "main at $candidate; tag not yet published"
git tag -a -F "$note_file" --cleanup=verbatim "$version" "$candidate" || git tag -a -F "$note_file" --cleanup=verbatim "$version" "$candidate" ||
fail "could not create the local annotated tag" fail "main is at $candidate; could not create local tag $version"
tag_target=$(git rev-parse --verify "refs/tags/$version^{}") || tag_target=$(git rev-parse --verify "refs/tags/$version^{}") ||
fail "cannot verify the local tag target" fail "main is at $candidate; cannot verify local tag $version"
[[ "$tag_target" == "$candidate" ]] || fail "local tag does not identify the candidate" [[ "$tag_target" == "$candidate" ]] || fail "main is at $candidate; local tag $version targets another commit"
tag_type=$(git cat-file -t "refs/tags/$version") || tag_type=$(git cat-file -t "refs/tags/$version") ||
fail "cannot inspect the local tag" fail "main is at $candidate; cannot inspect local tag $version"
[[ "$tag_type" == tag ]] || fail "release tag must be annotated" [[ "$tag_type" == tag ]] || fail "main is at $candidate; local tag $version is not annotated"
tag_oid=$(git rev-parse --verify "refs/tags/$version") || tag_oid=$(git rev-parse --verify "refs/tags/$version") ||
fail "cannot identify the annotated tag" fail "main is at $candidate; cannot identify local tag $version"
if git push --no-follow-tags "$remote_url" "refs/tags/$version:refs/tags/$version"; then if git push --no-follow-tags "$remote_url" "refs/tags/$version:refs/tags/$version"; then
: :
else else
if observed_tag=$(read_remote_ref "refs/tags/$version"); then if observed_tag=$(read_remote_ref "refs/tags/$version"); then
[[ "$observed_tag" == "$tag_oid" ]] || [[ "$observed_tag" == "$tag_oid" ]] ||
fail "authoritative tag conflicts with the local tag; never replace it" fail "authoritative tag $version conflicts with the local tag at $candidate; never replace it"
else else
result=$? result=$?
((result == 2)) && ((result == 2)) &&
fail "tag push failed; main is published, but the local tag is unpublished" fail "tag push failed; main is at $candidate, but local tag $version is unpublished"
fail "tag push outcome is unknown; retain the local tag and inspect authoritative state" fail "tag $version push outcome is unknown for $candidate; retain the local tag and inspect authoritative state"
fi fi
fi fi