feat(skills): add cut-release skill#1527
Open
danielmeppiel wants to merge 4 commits into
Open
Conversation
Encode the v0.16.0 release process as a reusable APM primitive: sanitize the [Unreleased] CHANGELOG block into a dated version block (one 'so what' entry per merged PR), pick patch vs minor per a semver rubric, bump pyproject.toml + uv.lock, run the CI-mirror lint chain, commit, push, and open the release PR. Architecture (per genesis step 6 handoff packet, persisted in session plan.md): - Single-thread sequential pipeline with 3 B10 HUMAN CHECKPOINTS (version pick, sanitized changelog, lint-fail recovery). Not a PANEL -- one lens (release strategy), one rubric. Cites pattern-tradeoffs matrices #4, #6, #9, #1. - Depends on existing apm-strategy skill as the versioning lens (LOCAL SIBLING, auto-loads via CHANGELOG.md trigger). Depends on .apm/instructions/linting.instructions.md and .github/instructions/changelog.instructions.md as path-attached rules. No EXTERNAL MODULE. - 3 S7 deterministic tool bridges: - list-changes-since-tag.sh -- git log + gh pr view, emits JSON, classifies internal-vs-user-facing by path prefix. - bump-version.sh -- edits pyproject.toml version line, runs uv lock, emits unified diff. - verify-lint-mirror.sh -- mirrors the 4-step CI Lint job from .apm/instructions/linting.instructions.md verbatim. - 3 assets: - semver-rubric.md -- signal table, pre/post-1.0 framing, worked v0.16.0 example. - entry-sanitizer.md -- per-entry rubric, DROP list, section mapping, worked v0.16.0 example. - pr-body-template.md -- variable-substituted PR body. Boundary: STOPS at 'PR open'. Does NOT tag the release -- tagging stays a human-gated trigger for the release workflow. Refuses to bump to >= 1.0.0 without explicit operator confirmation. Self-dogfooded: the v0.16.0 cycle (PR #1526) was cut by following this exact procedure manually; the worked examples in semver-rubric.md and entry-sanitizer.md cite that cycle. Evals: 20 trigger evals (10 should-fire, 10 near-miss). Content evals deferred to real-task refinement on the next release cycle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new .apm/skills/cut-release/ skill bundle that encodes the manual release-cut workflow (assess bump, sanitize [Unreleased], bump pyproject.toml+uv.lock, run the CI-mirror lint chain, open the release PR) and stops short of tagging, which remains a human gate. The skill ships three deterministic shell helpers, three rubric/template assets, and a trigger-only eval manifest. It composes with the existing apm-strategy skill and the canonical lint/changelog instructions rather than redefining them.
Changes:
- New
SKILL.mddefining the seven-phase procedure, three B10 checkpoints, dependencies, and boundary. - Three S7 bridge scripts (
list-changes-since-tag.sh,bump-version.sh,verify-lint-mirror.sh) plus three assets (semver-rubric.md,entry-sanitizer.md,pr-body-template.md). - Trigger-only
evals/evals.jsonwith 10 should-fire + 10 should-not-fire items and a stop list.
Show a summary per file
| File | Description |
|---|---|
| .apm/skills/cut-release/SKILL.md | End-to-end procedure, checkpoints, anti-patterns, boundary. |
| .apm/skills/cut-release/scripts/list-changes-since-tag.sh | Enumerates merged PRs since last tag, emits JSON with user-facing hint. |
| .apm/skills/cut-release/scripts/bump-version.sh | In-place pyproject.toml version edit + uv lock refresh with diff output. |
| .apm/skills/cut-release/scripts/verify-lint-mirror.sh | Runs the four command-based CI lint steps verbatim. |
| .apm/skills/cut-release/assets/semver-rubric.md | Signal table + pre/post-1.0 framing + worked v0.16.0 calibration. |
| .apm/skills/cut-release/assets/entry-sanitizer.md | Per-entry rubric, DROP list, section mapping, consolidation rules. |
| .apm/skills/cut-release/assets/pr-body-template.md | Variable-substituted release PR body. |
| .apm/skills/cut-release/evals/evals.json | 20 trigger evals + stop list; content evals deferred. |
Copilot's findings
- Files reviewed: 8/8 changed files
- Comments generated: 3
Comment on lines
+1
to
+23
| Cut release {version}. | ||
|
|
||
| - Bump `pyproject.toml` to {version} (and `uv.lock`). | ||
| - Move `[Unreleased]` to `[{version}] - {date}` in `CHANGELOG.md`, with one short "so what?" entry per PR merged since {prev_version}. | ||
|
|
||
| ## Why {bump_kind} ({version}), not {alt_bump_kind} ({alt_version}) | ||
|
|
||
| {bump_rationale} | ||
|
|
||
| {breaking_summary_block} | ||
|
|
||
| ## Validation | ||
|
|
||
| Lint mirror green locally (ruff check + format, pylint R0801, auth-signals). See `.apm/instructions/linting.instructions.md` for the contract this mirrors. | ||
|
|
||
| ## Post-merge | ||
|
|
||
| Tag `{version}` to trigger the release workflow: | ||
|
|
||
| ``` | ||
| git tag {version} | ||
| git push origin {version} | ||
| ``` |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…emplate
Copilot review noted that the PR body template used a single {version}
placeholder for both unprefixed contexts (CHANGELOG.md heading and
pyproject.toml version) and the v-prefixed git tag. The release
workflow's stable-release regex (^v[0-9]+\.[0-9]+\.[0-9]+$ in
.github/workflows/build-release.yml) only matches v-prefixed tags, so
substituting the unprefixed form into 'git tag {version}' produced a
tag the workflow would treat as prerelease.
Introduce {tag} (v-prefixed) for the post-merge tag block and keep
{version} (unprefixed) for the CHANGELOG/pyproject lines, matching
the existing repo conventions. Update SKILL.md Phase 6 substitution
list to document both placeholders and the rationale.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Adds
.apm/skills/cut-release/-- a reusable skill that encodes the v0.16.0 release process (decide bump, sanitize[Unreleased], bumppyproject.toml+uv.lock, run CI-mirror lint, open the release PR). Stops at "PR open"; tagging stays a human gate.Why
The v0.16.0 cycle (#1526) was cut by walking the same steps manually for the third time:
git log v0.15.0..HEAD+gh pr viewfor each PR.[Unreleased]bullet into a one-line "so what" entry..apm/,tests/,.github/instructions/-- nothing user-visible).pyproject.toml, regenerateuv.lock, run the four-step CI lint mirror.That procedure is now a primitive. Activation: "cut a release", "ship v0.x", "what kind of release do we need", etc.
How (architecture)
Designed via the
genesisskill; the step-6 handoff packet is persisted in the sessionplan.md(architecture is the source of truth for future refactors, not the natural-language body).scripts/):list-changes-since-tag.sh--git log+gh pr view, emits JSON, classifies internal-vs-user-facing by path prefix.bump-version.sh-- editspyproject.tomlversion line, runsuv lock, emits unified diff.verify-lint-mirror.sh-- mirrors the four-step CI Lint job verbatim from.apm/instructions/linting.instructions.md.assets/):semver-rubric.md(signal table + pre/post-1.0 framing),entry-sanitizer.md(per-entry rubric + DROP list),pr-body-template.md(variable-substituted PR body).Composition
apm-strategy(existing).apm/instructions/linting.instructions.mdverify-lint-mirror.shis a thin invoker..github/instructions/changelog.instructions.mdNo EXTERNAL MODULE declared. No PHANTOM DEPENDENCY risk.
Boundary
The skill explicitly does NOT:
Self-dogfooded
The worked examples in
assets/semver-rubric.mdandassets/entry-sanitizer.mdcite the v0.16.0 cycle (#1526) as calibration. Next bug-fix release will be the first real run of the skill end-to-end -- if it diverges from what we'd do manually, the assets get tightened.Evals
evals/evals.json.How to test
Each prints usage and exits 0. The first dry-runnable end-to-end test is "cut a release" on the next worktree that has merged PRs since v0.16.0.