diff --git a/.agents/skills/githits-release/SKILL.md b/.agents/skills/githits-release/SKILL.md index bcd234e..484def6 100644 --- a/.agents/skills/githits-release/SKILL.md +++ b/.agents/skills/githits-release/SKILL.md @@ -12,6 +12,22 @@ metadata: Use this skill for GitHits changelog maintenance, release work, version-bump PRs, release-readiness reviews, and release notes. +## Human Merge Gate + +- Release preparation ends with an open release PR. A request to audit, + prepare, create, cut, or release a version does not authorize merging, + enabling auto-merge, tagging, publishing, or waiting for publication. +- Merge a release PR only after receiving separate, explicit human approval + given after the release PR exists. The approval must explicitly authorize + merging and identify that PR by number, URL, or an otherwise unambiguous + reference to the already-open PR. +- Earlier requests for an end-to-end release do not satisfy the merge gate. + After opening the PR, report its URL and check status, then stop and ask for + merge approval. Do not enable auto-merge as a substitute for approval. +- After the separate approval, merge only the approved PR. The successful + `Main` workflow will trigger publication, which may then be monitored to + completion. + ## Release Checklist - Root `githits` and `@githits/mcp` have separate release flows. Bump both only when both surfaces changed. diff --git a/AGENTS.md b/AGENTS.md index 06cbfc0..0b8d0aa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -128,6 +128,7 @@ See `docs/guidelines/TESTING.md` for comprehensive patterns. - Root `githits` release versions must stay aligned with generated plugin/assistant manifests: `.plugin/plugin.json`, `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, `.cursor-plugin/plugin.json`, `.claude-plugin/marketplace.json`, and `gemini-extension.json`. The versionless Antigravity `plugin.json` and `mcp_config.json` must also be regenerated and checked. - `@githits/mcp` release versions live in `packages/mcp/package.json` and should change only for MCP package API, tool behavior, MCP instructions, schemas, MCP auth/error behavior, or remote-server-facing public type changes. - For coordinated CLI and MCP releases, keep the MCP minor aligned with the CLI minor for discoverability. The first MCP release for a CLI minor starts at `X.Y.0`; later MCP-package-visible changes in that CLI minor bump the MCP patch. +- A request to audit, prepare, create, cut, or release a version authorizes release preparation through opening the release PR only; it does not authorize merging, enabling auto-merge, tagging, or publishing. Merging requires separate, explicit human approval given after the release PR exists and identifying that PR. Earlier release requests do not count. Stop after opening the PR, report its URL and check status, and wait for that approval. - Successful `Main` runs on `main` trigger both root and MCP release workflows. The MCP workflow publishes only when the package version is not already published; manual dispatch is for recovery or dry runs. - Release preparation consumes all fragments into separate versioned sections for each released artifact and deletes the consumed files. diff --git a/changes/README.md b/changes/README.md index c2e3172..a5fb68e 100644 --- a/changes/README.md +++ b/changes/README.md @@ -36,3 +36,9 @@ partially. Group entries by category into each affected artifact's versioned unrelated to that release untouched. A fragment with `none` for every artifact documents repository or release-operation impact; it does not trigger a release and is consumed into the next `githits` release. + +Opening the release PR completes release preparation. A request to audit, +prepare, create, cut, or release a version does not authorize merging or +enabling auto-merge. Merge requires separate, explicit human approval given +after the release PR exists and identifying that PR; earlier release requests +do not count as merge approval. diff --git a/changes/release-merge-human-approval.changed.md b/changes/release-merge-human-approval.changed.md new file mode 100644 index 0000000..0412549 --- /dev/null +++ b/changes/release-merge-human-approval.changed.md @@ -0,0 +1,8 @@ +--- +"githits": none +"@githits/mcp": none +--- + +- **Human release merge gate** - Release preparation stops at an open PR; + merging requires separate explicit human approval after that PR exists, + preventing premature publication from an earlier release request. diff --git a/docs/guidelines/REVIEW_GUIDELINES.md b/docs/guidelines/REVIEW_GUIDELINES.md index cbf79e5..16fa2b1 100644 --- a/docs/guidelines/REVIEW_GUIDELINES.md +++ b/docs/guidelines/REVIEW_GUIDELINES.md @@ -35,6 +35,12 @@ Checklist for reviewing code changes in githits-cli. - [ ] Feature pull requests do not edit `CHANGELOG.md` - [ ] Historical changelog sections are unchanged unless a minimal edit corrects a blatant factual error +## Release PRs + +- [ ] A request to audit, prepare, create, cut, or release a version does not authorize merging or enabling auto-merge +- [ ] The release PR is merged only with separate, explicit human approval given after the release PR exists and identifying that PR +- [ ] Earlier release requests are not treated as merge approval, and the agent stops after opening the PR to report its URL and check status + ## Build & Lint - [ ] `bun run build` succeeds diff --git a/docs/implementation/release-process.md b/docs/implementation/release-process.md index bd1e8a1..24079de 100644 --- a/docs/implementation/release-process.md +++ b/docs/implementation/release-process.md @@ -84,6 +84,11 @@ that review. ## Release Preparation +Release preparation and release execution have separate authorization +boundaries. A request to audit, prepare, create, cut, or release a version +authorizes the work below through opening the release PR only; it does not +authorize merging, enabling auto-merge, tagging, or publishing. + For each artifact being released: 1. Inspect the complete package-specific tag-to-HEAD delta (`vX.Y.Z` for @@ -105,6 +110,13 @@ For each artifact being released: 6. Run the release skill checklist, package validation, tests, build, and the smoke or agent evaluations required by the changed surfaces. +After validation, commit and push the preparation and open the release PR. +Report its URL and check status, then stop. Merge only after receiving separate, +explicit human approval given after the release PR exists and identifying that +PR. Earlier release requests do not count as merge approval, and auto-merge +must not be enabled as a substitute. Once the separately approved PR merges, +the successful `Main` workflow triggers the root and MCP publication workflows. + The release-boundary tests validate fragment names, front matter, and body shape during development, and require release sections for the versions currently declared in both public package manifests. A version bump without a diff --git a/src/package-release-boundaries.test.ts b/src/package-release-boundaries.test.ts index 03c3a62..44da8ff 100644 --- a/src/package-release-boundaries.test.ts +++ b/src/package-release-boundaries.test.ts @@ -172,4 +172,25 @@ describe("package release boundaries", () => { expect(publishIndex).toBeGreaterThan(-1); expect(createTagIndex).toBeLessThan(publishIndex); }); + + it("requires separate human approval to merge a release PR", async () => { + const root = join(import.meta.dir, ".."); + const instructionPaths = [ + "AGENTS.md", + join(".agents", "skills", "githits-release", "SKILL.md"), + join("changes", "README.md"), + join("docs", "implementation", "release-process.md"), + join("docs", "guidelines", "REVIEW_GUIDELINES.md"), + ]; + + for (const instructionPath of instructionPaths) { + const instructions = ( + await readFile(join(root, instructionPath), "utf8") + ).replaceAll(/\s+/g, " "); + + expect(instructions).toContain("separate, explicit human approval"); + expect(instructions).toContain("after the release PR exists"); + expect(instructions).toContain("does not authorize merging"); + } + }); });