From b0c66aa6e7f1a873ea2b338f1b42ddac3c450dd5 Mon Sep 17 00:00:00 2001 From: Joseph Yaksich Date: Sat, 25 Jul 2026 16:04:03 +0000 Subject: [PATCH 1/2] docs: preserve complete release evidence Signed-off-by: Joseph Yaksich --- .github/pull_request_template.md | 12 ++++++++ CHANGELOG.md | 9 ++++++ CONTRIBUTING.md | 3 ++ docs/GOVERNANCE.md | 12 ++++++++ docs/release-checklist.md | 27 +++++++++++++++--- docs/release-lifecycle.md | 18 +++++++++--- docs/release-notes-template.md | 49 ++++++++++++++++++++++++++++++++ scripts/run-test-suite.mjs | 2 +- test/release-governance.mjs | 38 +++++++++++++++++++++++++ 9 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 docs/release-notes-template.md create mode 100644 test/release-governance.mjs diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 625c565..1ff086d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -23,6 +23,18 @@ Paste bullets for `CHANGELOG.md` Unreleased (or N/A): - [ ] `CHANGELOG.md` updated (or N/A) - [ ] `docs/VISION.md` updated if this is a product decision +## Numbered acceptance ledger + + + +1. … + +- [ ] Every requested item appears once and is implemented or explicitly named + as deferred with its reason. +- [ ] This ledger is ready to be copied into the GitHub Release notes unchanged. + ## Verification - [ ] `npm run typecheck` diff --git a/CHANGELOG.md b/CHANGELOG.md index d112c48..da3bfd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- GitHub Releases now require the complete numbered acceptance ledger from a + multi-item request, plus artifact and verification evidence. Generated + commit summaries can no longer replace the user-facing change list. +- The retained Apple Silicon release host now owns the complete macOS path: + clean build, signing, notarization, public-download installation, launch, + smoke verification, and Application Support preservation. + ## [0.0.10] - 2026-07-25 ### Fixed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b951341..caebdfc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,6 +13,7 @@ welcome through GitHub issues and pull requests. | [docs/GOVERNANCE.md](./docs/GOVERNANCE.md) | Authority, branches, quality bar | | [docs/release-lifecycle.md](./docs/release-lifecycle.md) | Idea → PR → deploy | | [docs/release-checklist.md](./docs/release-checklist.md) | Ship verification commands | +| [docs/release-notes-template.md](./docs/release-notes-template.md) | Complete public release record | | [CHANGELOG.md](./CHANGELOG.md) | User/operator-facing history | | [docs/VISION.md](./docs/VISION.md) | Product decisions and build record | @@ -49,6 +50,8 @@ assignment; contributors retain copyright in contributions they author. 5. Record durable decisions in `docs/VISION.md`. 6. Use the merge method selected by the maintainer; delete the head branch. 7. For a named ship: version bump + [release-checklist.md](./docs/release-checklist.md). +8. For a multi-item ship, preserve the numbered acceptance ledger in the PR + and GitHub Release; generated notes are not a replacement. ### Security diff --git a/docs/GOVERNANCE.md b/docs/GOVERNANCE.md index e56e3bf..06f12b4 100644 --- a/docs/GOVERNANCE.md +++ b/docs/GOVERNANCE.md @@ -54,6 +54,11 @@ contract as the slice hardens. 5. No secrets, operator hosts/paths, real provider keys, or `data/` SQLite dumps. 6. Significant product decisions recorded in `docs/VISION.md`. 7. User-visible changes noted under `CHANGELOG.md` → `## [Unreleased]`. +8. A multi-item user request retains a numbered acceptance ledger in the pull + request and GitHub Release. Do not collapse completed items into a generic + summary or rely on generated commit notes as the user-facing release record. +9. The retained Apple Silicon release host owns both artifact production and + public-download installed-app verification. ## Versioning @@ -61,6 +66,13 @@ contract as the slice hardens. - **Do not** reuse a published version tag for different bits. - A release requires a unique version, changelog, exact tag, verified public artifact, and platform-appropriate clean installation evidence. +- GitHub Release notes are a first-class product artifact. They must enumerate + every user-visible fix and feature accepted for that release, using the same + numbered ledger as the originating request when one exists. A short summary + can introduce that ledger but cannot replace it. +- macOS verification must use the exact publicly downloaded artifact, preserve + Application Support, and prove signature/ticket/Gatekeeper, launch, version, + loopback behavior, and retained state on the retained release host. Never hand-edit only a deployment target to fix the product. Fix in git, review, merge, and redeploy the exact source commit. diff --git a/docs/release-checklist.md b/docs/release-checklist.md index 4bf681e..20c0ea8 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -19,6 +19,10 @@ git switch -c Implement, update tests, `docs/VISION.md` if needed, and `CHANGELOG.md` Unreleased. +For a multi-item request, copy its numbering into the PR acceptance ledger and +keep one result/evidence line per item. That ledger must survive unchanged into +the GitHub Release notes; do not replace it with a shorter commit summary. + When this branch will be a named release: ```bash @@ -44,7 +48,7 @@ Run any feature-specific suites (e.g. `npm run test:native` when that script exi ```bash git push -u origin HEAD -gh pr create --fill # use template +gh pr create --fill # use template, including the acceptance ledger ``` ## 4. Merge @@ -66,11 +70,22 @@ git push origin "refs/tags/v${VERSION}" HEADLESS="dist/1Helm-${VERSION}-linux-node.tgz" DMG="dist/1Helm-${VERSION}-arm64.dmg" UPDATE_ZIP="dist/1Helm-${VERSION}-mac-arm64.zip" -gh release create "v${VERSION}" "$DMG" "$UPDATE_ZIP" "$HEADLESS" --title "1Helm ${VERSION}" --generate-notes --draft +RELEASE_NOTES="dist/1Helm-${VERSION}-release-notes.md" +# Author RELEASE_NOTES from docs/release-notes-template.md. It must contain the +# complete numbered acceptance ledger, artifact digests, and verification. +test -s "$RELEASE_NOTES" +rg -q '^1\. ' "$RELEASE_NOTES" # multi-item ships must retain a numbered ledger +gh release create "v${VERSION}" "$DMG" "$UPDATE_ZIP" "$HEADLESS" --title "1Helm ${VERSION}" --notes-file "$RELEASE_NOTES" --draft # review notes, then: gh release edit "v${VERSION}" --draft=false ``` +`--generate-notes` is not an acceptable replacement for the authored notes. +Generated commit/PR lists may be appended as secondary metadata, but the public +body must lead with the complete user-visible acceptance ledger. Before +publication, compare the notes item-by-item with the originating request and +the versioned `CHANGELOG.md` entry. + ## 6. Local verify ```bash @@ -88,7 +103,10 @@ Expect first-run / needs_setup on empty data dir. - Verify the native ZIP was created only after the app was notarized and stapled; extract it and repeat strict signature, ticket, and Gatekeeper checks. - Confirm the public Electron feed selects that ZIP for the prior Mac version and returns no update for the new version. -- On an independent Mac with preserved Application Support, use Profile to make the host download the update, wait for **Restart & install**, install it, and verify the new version, loopback health, resident state, and data-directory identity. +- On the same retained Apple Silicon release host used for the clean build, + install the **publicly downloaded** DMG/update with preserved Application + Support, then verify the new version, loopback health, resident state, and + data-directory identity. - Upload the exact `npm run package:linux` artifact and require GitHub's recorded `sha256:` digest before publication. - In a disposable systemd host running the prior release, invoke the same Captain host-update action, observe checking/downloading/installing/restarting, verify the new version and `/var/lib/1helm` identity, and exercise rollback with an intentionally unhealthy disposable fixture. @@ -106,9 +124,10 @@ Expect first-run / needs_setup on empty data dir. Version: Merged commit: Tag/Release: +Release notes: complete numbered acceptance ledger reviewed against request Local setup: needs_setup verified on clean CTRL_DATA_DIR Clean deploy: -Mac host update: +Mac host update: Linux update: CI: Actions green on main ``` diff --git a/docs/release-lifecycle.md b/docs/release-lifecycle.md index 4b8bcba..5d98584 100644 --- a/docs/release-lifecycle.md +++ b/docs/release-lifecycle.md @@ -21,7 +21,7 @@ Process contract from intent to verified deploy. Commands: [release-checklist.md version bump on the release branch │ v - tag · signed DMG + updater ZIP + Linux host artifact · deploy target(s) + full numbered notes · tag · signed DMG + updater ZIP + Linux host artifact │ v verify (local health + clean install + public artifact) @@ -61,7 +61,10 @@ Feature branches that introduce `test/native-world.mjs` (or similar) must run th ## 4. Pull request -Use the PR template: summary, type, changelog bullets, verification checklist. +Use the PR template: summary, type, changelog bullets, numbered acceptance +ledger, and verification checklist. For a multi-item request, preserve its +numbering and record one concrete outcome per item. The ledger is the source +for the GitHub Release; a commit title or generated summary is not a substitute. Draft PRs are allowed for long slices; mark ready only when the quality bar is met. @@ -77,7 +80,14 @@ Draft PRs are allowed for long slices; mark ready only when the quality bar is m 2. `npm version patch|minor|major --no-git-tag-version` (or edit `package.json`). 3. Commit the versioned source on the release branch before merge. 4. After merge, tag the exact verified `main` commit and push the tag. -5. Publish the verified DMG, native updater ZIP, Linux host artifact, and release notes through one GitHub Release. +5. Author release notes from the PR acceptance ledger using + [release-notes-template.md](./release-notes-template.md). Every accepted + user-visible item must appear once, with the same numbering as the request + when available. Include additional fixes, artifacts/digests, and verification + evidence in their own sections. +6. Publish the verified DMG, native updater ZIP, Linux host artifact, and those + complete release notes through one GitHub Release. Do not use GitHub's + generated notes as the sole or primary body. ## 7. Deploy @@ -103,7 +113,7 @@ workspace state. | Code landed | On `origin/main`, CI green | | Behavior fixed | Tests + manual/API check | | Install path still works | Clean `CTRL_DATA_DIR` boot through the wizard plus platform acceptance | -| Named release | Version, changelog, exact tag, verified public artifact, and clean installation | +| Named release | Version, changelog, full numbered notes, exact tag, verified public artifact, and clean installation | | Native host update | Published updater ZIP feed, installed-old-to-new Mac acceptance, and preserved Application Support | | Linux host update | Digest-qualified artifact, real systemd old-to-new update, health check, and preserved `/var/lib/1helm` | diff --git a/docs/release-notes-template.md b/docs/release-notes-template.md new file mode 100644 index 0000000..0376ec0 --- /dev/null +++ b/docs/release-notes-template.md @@ -0,0 +1,49 @@ +# 1Helm x.y.z + +Short outcome-first summary of this release. + +## What changed + +For a multi-item request, preserve the original numbered acceptance ledger and +write one user-visible outcome per requested item. Do not combine distinct requests into +generic bullets. If an item was deliberately deferred, keep its number and say +so plainly instead of silently omitting it. + +1. **Feature or fix name** — concrete user-visible outcome. +2. **Feature or fix name** — concrete user-visible outcome. + +## Additional changes + +- Include work added after the original numbered request. +- Include material licensing, migration, compatibility, or operational changes. + +## Downloads and integrity + +| Artifact | SHA-256 | +| --- | --- | +| `1Helm-x.y.z-arm64.dmg` | `` | +| Other published artifact, or `Not applicable` | `` | + +Source commit: `` + +## Verification + +- Name the exact automated suites and pass counts. +- Name public demo/site/API checks when applicable. +- For macOS, state Developer ID signature, Apple notarization, stapling, + Gatekeeper, public-download installation on the retained release host, app + launch/smoke behavior, and Application Support preservation. +- Name anything skipped or incomplete; do not call an incomplete release fully + verified. + +## Licensing + +State the license for this version and any release-boundary notice that users +need to understand. + +--- + +Before publication, compare this file line-by-line with the originating user +request/issue, PR acceptance ledger, `CHANGELOG.md`, published artifact list, +and final verification evidence. GitHub-generated notes are optional secondary +metadata and must never replace this authored record. diff --git a/scripts/run-test-suite.mjs b/scripts/run-test-suite.mjs index 95f8a47..51369ff 100644 --- a/scripts/run-test-suite.mjs +++ b/scripts/run-test-suite.mjs @@ -45,7 +45,7 @@ const suites = [ "test/routing.mjs", "test/routing-disabled-account.mjs", "test/desktop.mjs", "test/update-service.mjs", "test/channel-computers.mjs", "test/channel-computers-isolated-backends.mjs", "test/channel-computers-backend-migration.mjs", "test/cloudflare-worker.mjs", "test/connectors.mjs", "test/chatgpt-image.mjs", "test/autonomy-platform.mjs", - "test/feedback.mjs", "test/feedback-browser.mjs", "test/gmail.mjs", "test/photon.mjs", "test/site.mjs", "test/release-license.mjs", + "test/feedback.mjs", "test/feedback-browser.mjs", "test/gmail.mjs", "test/photon.mjs", "test/site.mjs", "test/release-license.mjs", "test/release-governance.mjs", "test/channel-surfaces.mjs", "test/workspace-interactions.mjs", "test/sweep-fleet-telemetry.mjs", "test/sweep-server-integration.mjs", "test/thread-followup-chat.mjs", "test/notifications.mjs", "test/terminal-reconnect-contract.mjs", "test/terminal-reconnect-browser.mjs", "test/web-research.mjs", "test/workflows.mjs"], ]; diff --git a/test/release-governance.mjs b/test/release-governance.mjs new file mode 100644 index 0000000..69c59a1 --- /dev/null +++ b/test/release-governance.mjs @@ -0,0 +1,38 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +const root = join(import.meta.dirname, ".."); +const read = (path) => readFileSync(join(root, path), "utf8"); + +test("multi-item releases retain the complete numbered acceptance ledger", () => { + const checklist = read("docs/release-checklist.md"); + const lifecycle = read("docs/release-lifecycle.md"); + const governance = read("docs/GOVERNANCE.md"); + const pullRequest = read(".github/pull_request_template.md"); + const notesTemplate = read("docs/release-notes-template.md"); + + for (const source of [checklist, lifecycle, governance, pullRequest, notesTemplate]) { + assert.match(source, /numbered acceptance ledger/i); + } + assert.match(checklist, /--notes-file "\$RELEASE_NOTES"/); + assert.doesNotMatch(checklist, /gh release create[^\n]+--generate-notes/); + assert.match(notesTemplate, /^1\. \*\*Feature or fix name\*\*/m); + assert.match(notesTemplate, /artifact/i); + assert.match(notesTemplate, /verification/i); +}); + +test("one retained Mac Studio owns the complete macOS release gate", () => { + const tracked = [ + read("docs/release-checklist.md"), + read("docs/release-lifecycle.md"), + read("docs/GOVERNANCE.md"), + read("docs/release-notes-template.md"), + read("CHANGELOG.md"), + ].join("\n"); + + assert.match(tracked, /same retained Apple Silicon release host/i); + assert.match(tracked, /publicly downloaded/i); + assert.match(tracked, /Application Support preservation/i); +}); From 90427b04e0817541041641bfa6d4fcd5291e0125 Mon Sep 17 00:00:00 2001 From: Joseph Yaksich Date: Sat, 25 Jul 2026 16:09:48 +0000 Subject: [PATCH 2/2] test: accept wrapped governance language Signed-off-by: Joseph Yaksich --- test/release-governance.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/release-governance.mjs b/test/release-governance.mjs index 69c59a1..15d6487 100644 --- a/test/release-governance.mjs +++ b/test/release-governance.mjs @@ -14,7 +14,7 @@ test("multi-item releases retain the complete numbered acceptance ledger", () => const notesTemplate = read("docs/release-notes-template.md"); for (const source of [checklist, lifecycle, governance, pullRequest, notesTemplate]) { - assert.match(source, /numbered acceptance ledger/i); + assert.match(source, /numbered acceptance\s+ledger/i); } assert.match(checklist, /--notes-file "\$RELEASE_NOTES"/); assert.doesNotMatch(checklist, /gh release create[^\n]+--generate-notes/);