From d9a00c5f74cb143c723ed159858096e07d198ffd Mon Sep 17 00:00:00 2001 From: Ben Ranford <84072202+ben-ranford@users.noreply.github.com> Date: Sun, 13 Sep 2026 18:27:10 +1000 Subject: [PATCH 1/5] chore(release): prepare stable 1.1 release please Remove RC-only Release Please configuration while preserving the released rc.2 manifest and no-publication workflow path. The final squash commit must retain this one-shot footer so Release Please prepares the held 1.1.0 approval PR. Release-As: 1.1.0 --- README.md | 4 +++ docs/client-adoption.md | 6 ++--- release-please-config.json | 3 --- requirements/release_please_test.go | 42 ++++++++++++++++++++--------- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7903ceb..916527d 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,10 @@ module versions and tags; begin with the root module. See the [compatibility policy](docs/compatibility.md) and [security contract](docs/security.md) before integrating consequential agent actions. +The v1.1.0 changes in this development checkout are unreleased. Pin a published +tag before deploying consequential agent actions; use the development branch for +evaluation only. + ## Quick start In an empty directory, run `go mod init example.com/hello-stave`, then use the diff --git a/docs/client-adoption.md b/docs/client-adoption.md index ddd019a..ef7a325 100644 --- a/docs/client-adoption.md +++ b/docs/client-adoption.md @@ -5,11 +5,11 @@ theme, actions, and effects. Stave provides the semantic UI and runtime contracts that let those choices work consistently across human and automated interfaces. -The current root module release candidate is `v1.0.0-rc.2` . -It is not a GA promise; published Lopper parity and rollback evidence remains +The held root module release target is `v1.0.0-rc.2` , awaiting +its tag gate. It is not a GA promise; published Lopper parity and rollback evidence remains the promotion gate. Begin with the root module only. The nested SSH, Bubble Tea, and Lip Gloss modules are internal and are not yet supported consumer -dependencies. Pin this candidate after its release tag is published. +dependencies. Pin this target after its release tag is published. For a compiled first semantic tree, use the [root quick start](../README.md#quick-start). diff --git a/release-please-config.json b/release-please-config.json index 50a4644..ea51bc9 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -3,9 +3,6 @@ "packages": { ".": { "release-type": "go", - "versioning": "prerelease", - "prerelease": true, - "prerelease-type": "rc", "include-component-in-tag": false, "extra-files": [ "README.md", diff --git a/requirements/release_please_test.go b/requirements/release_please_test.go index 66f15d2..8e5720f 100644 --- a/requirements/release_please_test.go +++ b/requirements/release_please_test.go @@ -10,13 +10,10 @@ import ( "testing" ) -var releaseCandidateVersion = regexp.MustCompile(`^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)-rc\.([1-9][0-9]*)$`) +var releaseVersion = regexp.MustCompile(`^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-rc\.([1-9][0-9]*))?$`) type releasePleasePackageConfig struct { ReleaseType string `json:"release-type"` - Versioning string `json:"versioning"` - Prerelease bool `json:"prerelease"` - PrereleaseType string `json:"prerelease-type"` IncludeComponentInTag bool `json:"include-component-in-tag"` ExtraFiles []string `json:"extra-files"` ExcludePaths []string `json:"exclude-paths"` @@ -29,11 +26,31 @@ type releasePleaseConfig struct { func TestRootReleasePleaseConfiguration(t *testing.T) { root := rootReleasePleasePackage(t) assertRootReleasePleasePackage(t, root) + assertReleasePleaseUsesDefaultVersioning(t) assertReleasePleaseCandidateDocuments(t, root) assertReleasePleaseManifestAndChangelog(t) assertReleasePleaseWorkflow(t) } +func assertReleasePleaseUsesDefaultVersioning(t *testing.T) { + t.Helper() + rawConfig, err := os.ReadFile("../release-please-config.json") + if err != nil { + t.Fatal(err) + } + var config struct { + Packages map[string]map[string]json.RawMessage `json:"packages"` + } + if err := json.Unmarshal(rawConfig, &config); err != nil { + t.Fatal(err) + } + for _, setting := range []string{"versioning", "prerelease", "prerelease-type"} { + if _, exists := config.Packages["."][setting]; exists { + t.Fatalf("root release must use Release Please default versioning; remove %q", setting) + } + } +} + func rootReleasePleasePackage(t *testing.T) releasePleasePackageConfig { t.Helper() @@ -56,8 +73,8 @@ func rootReleasePleasePackage(t *testing.T) releasePleasePackageConfig { func assertRootReleasePleasePackage(t *testing.T, root releasePleasePackageConfig) { t.Helper() - if root.ReleaseType != "go" || root.Versioning != "prerelease" || !root.Prerelease || root.PrereleaseType != "rc" { - t.Fatalf("root release must remain a Go rc prerelease: %+v", root) + if root.ReleaseType != "go" { + t.Fatalf("root release must remain a Go package: %+v", root) } if root.IncludeComponentInTag { t.Fatal("root release tags must not include a component") @@ -96,8 +113,8 @@ func assertReleasePleaseManifestAndChangelog(t *testing.T) { if err := json.Unmarshal(rawManifest, &manifest); err != nil { t.Fatalf("decode %s: %v", manifestPath, err) } - if !releaseCandidateVersion.MatchString(manifest["."]) { - t.Fatalf("root manifest must contain a non-zero rc prerelease version, got %q", manifest["."]) + if !releaseVersion.MatchString(manifest["."]) { + t.Fatalf("root manifest must contain an rc baseline or stable SemVer version, got %q", manifest["."]) } changelogPath := filepath.Join("..", "CHANGELOG.md") changelog, err := os.ReadFile(changelogPath) @@ -124,24 +141,25 @@ func assertReleasePleaseWorkflow(t *testing.T) { } } -func TestReleaseCandidateVersionContract(t *testing.T) { +func TestReleaseVersionContract(t *testing.T) { for version, want := range map[string]bool{ "1.0.0-rc.1": true, "2.14.3-rc.42": true, "0.0.0-rc.1": true, + "1.1.0": true, + "2.14.3": true, "01.0.0-rc.1": false, "1.01.0-rc.1": false, "1.0.01-rc.1": false, "1.0.0-rc.0": false, "1.0.0-rc.01": false, - "1.0.0": false, "1.0.0-beta.1": false, "v1.0.0-rc.1": false, "1.0.0-rc.1+build.7": false, } { t.Run(version, func(t *testing.T) { - if got := releaseCandidateVersion.MatchString(version); got != want { - t.Fatalf("release candidate validation for %q = %t, want %t", version, got, want) + if got := releaseVersion.MatchString(version); got != want { + t.Fatalf("release version validation for %q = %t, want %t", version, got, want) } }) } From 2a3d727ec93cb488fc27b37de5160828fe103f14 Mon Sep 17 00:00:00 2001 From: Ben Ranford <84072202+ben-ranford@users.noreply.github.com> Date: Sun, 13 Sep 2026 23:46:23 +1000 Subject: [PATCH 2/5] test(release): accept stable manifest build metadata --- requirements/release_please_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/requirements/release_please_test.go b/requirements/release_please_test.go index 8e5720f..0d66387 100644 --- a/requirements/release_please_test.go +++ b/requirements/release_please_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -var releaseVersion = regexp.MustCompile(`^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-rc\.([1-9][0-9]*))?$`) +var releaseVersion = regexp.MustCompile(`^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-rc\.([1-9][0-9]*)|\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`) type releasePleasePackageConfig struct { ReleaseType string `json:"release-type"` @@ -146,6 +146,9 @@ func TestReleaseVersionContract(t *testing.T) { "1.0.0-rc.1": true, "2.14.3-rc.42": true, "0.0.0-rc.1": true, + "1.0.0+build.7": true, + "1.0.0+": false, + "1.0.0+build..7": false, "1.1.0": true, "2.14.3": true, "01.0.0-rc.1": false, From de6560214e117982000e5a2d738f9d1593106a47 Mon Sep 17 00:00:00 2001 From: Ben Ranford <84072202+ben-ranford@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:17:49 +1000 Subject: [PATCH 3/5] docs(release): keep development guidance version independent --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 916527d..45c87c4 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,8 @@ module versions and tags; begin with the root module. See the [compatibility policy](docs/compatibility.md) and [security contract](docs/security.md) before integrating consequential agent actions. -The v1.1.0 changes in this development checkout are unreleased. Pin a published -tag before deploying consequential agent actions; use the development branch for +Development checkouts may contain unreleased changes. Pin a published tag +before deploying consequential agent actions; use the development branch for evaluation only. ## Quick start From 8272a27dfe2fda249ce1abe9ed1243df66ff1804 Mon Sep 17 00:00:00 2001 From: Ben Ranford <84072202+ben-ranford@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:29:15 +1000 Subject: [PATCH 4/5] docs(release): preserve adoption guidance after version tagging --- README.md | 2 +- docs/client-adoption.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 45c87c4..c11a870 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Stave is created by [Ben Ranford](https://github.com/ben-ranford) and is ## Installation -Requires **Go 1.22 or later**. In your Go module, install the release candidate: +Requires **Go 1.22 or later**. In your Go module, install the documented version: diff --git a/docs/client-adoption.md b/docs/client-adoption.md index ef7a325..597ab37 100644 --- a/docs/client-adoption.md +++ b/docs/client-adoption.md @@ -5,11 +5,11 @@ theme, actions, and effects. Stave provides the semantic UI and runtime contracts that let those choices work consistently across human and automated interfaces. -The held root module release target is `v1.0.0-rc.2` , awaiting -its tag gate. It is not a GA promise; published Lopper parity and rollback evidence remains -the promotion gate. Begin with the root module only. The nested SSH, Bubble Tea, -and Lip Gloss modules are internal and are not yet supported consumer -dependencies. Pin this target after its release tag is published. +This guide tracks root module version `v1.0.0-rc.2` . +Begin with the root module only. The nested SSH, Bubble Tea, and Lip Gloss +modules are internal and are not yet supported consumer dependencies. Pin a +published release tag before deployment. For Lopper promotion, verify the +published parity and rollback evidence described in the [release runbook](releasing.md). For a compiled first semantic tree, use the [root quick start](../README.md#quick-start). From 6e9d75d4db636576d4f078e064790741410adeff Mon Sep 17 00:00:00 2001 From: Ben Ranford <84072202+ben-ranford@users.noreply.github.com> Date: Mon, 14 Sep 2026 02:41:56 +1000 Subject: [PATCH 5/5] docs(release): describe stable publication gates accurately --- README.md | 8 ++++---- docs/releasing.md | 21 ++++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c11a870..6893900 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,10 @@ go get github.com/ben-ranford/stave@v1.0.0-rc.2 ### Deliberate limits -Stave has not reached general availability. Promotion requires published, -immutable Lopper proving-client evidence for parity and rollback. The SSH, -Bubble Tea, and Lip Gloss adapters remain internal until they have independent -module versions and tags; begin with the root module. See the +A stable tag requires published, immutable Lopper proving-client evidence for +parity and rollback before GA promotion. The SSH, Bubble Tea, and Lip Gloss +adapters remain internal until they have independent module versions and tags; +begin with the root module. See the [compatibility policy](docs/compatibility.md) and [security contract](docs/security.md) before integrating consequential agent actions. diff --git a/docs/releasing.md b/docs/releasing.md index 70fa72d..9488d7a 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -4,7 +4,7 @@ The root Go module is the only published Stave package. The nested SSH, Bubble Tea, and Lip Gloss modules remain internal until they receive independent versions and tags. -## Publish the prepared release candidate +## Publish the prepared release tag Read the candidate from `.release-please-manifest.json`; publish it from the hardened final `main` commit, never from an older release-please pull request @@ -24,6 +24,7 @@ merge commit. 2. On the final `main` commit, wait for a fresh successful required-check run. Record its commit SHA and confirm it contains the intended candidate manifest, changelog, and release workflow. + Before deriving a stable tag, complete the GA promotion gate below. 3. Derive the release tag from the manifest and tag that exact SHA. Do not move or recreate the tag after it is pushed: @@ -41,9 +42,11 @@ merge commit. ``` 4. The tag triggers [the release workflow](../.github/workflows/release.yml). - It validates the tag, runs `make ci` and `make release-contract`, then - publishes a prerelease with `CHANGELOG.md`, `LICENSE`, and the performance - evidence artifact. Wait for that workflow and verify all published assets. + It validates the tag and runs `make ci`. A prerelease tag then runs + `make release-contract` and publishes a prerelease; a stable tag runs + `make release-ga-contract` and publishes a non-prerelease release. Both + release paths attach `CHANGELOG.md`, `LICENSE`, and the performance evidence + artifact. Wait for that workflow and verify all published assets. 5. Change repository visibility only after the scheduler-boundary proof in step 1 passes. Then run a controlled real public-fork pull request and prove it uses the hosted untrusted path before approving general outside @@ -55,11 +58,11 @@ merge commit. go list -m -json "github.com/ben-ranford/stave@${release_tag}" ``` -7. After the tag, prerelease, assets, and public Go resolution are verified, - replace `autorelease: pending` with `autorelease: tagged` on the original - release-please pull request. `skip-github-release: true` delegates - publication to the tag workflow, so release-please does not make that label - transition itself. +7. After the tag, its matching release channel, assets, and public Go + resolution are verified, replace `autorelease: pending` with + `autorelease: tagged` on the original release-please pull request. + `skip-github-release: true` delegates publication to the tag workflow, so + release-please does not make that label transition itself. Release Please updates the annotated candidate versions in `README.md` and `docs/client-adoption.md` for future release pull requests. Keep the