AGENT SKILL

release-branch

Make the merge/PR/keep/discard decision for a feature branch, verify coverage gates, create the PR with gh, and clean up the worktree. Use when a feature is done and ready to ship, or when user says "release", "merge", or "open a PR".

License 许可
MIT
最近更新
2026-11-10
Stars
★ 290
Forks
24

01 前言 Front Matter

name
release-branch
model
haiku
description
Make the merge/PR/keep/discard decision for a feature branch, verify coverage gates, create the PR with gh, and clean up the worktree. Use when a feature is done and ready to ship, or when user says "release", "merge", or "open a PR".

02 资源文件 1

03 SKILL.md 正文

<!-- story: e38s07 --> <!-- story: e45s15 --> <!-- story: e45s32 --> <!-- story: e45s39 --> <!-- story: e82s02 --> <!-- story: e20s02 -->

Release Branch

HARD GATE — Do NOT merge or release if tests fail or if coverage gates are not met. If the branch is red, return to develop-tdd to fix regressions or add missing tests before proceeding.

Finalize a completed feature branch: verify coverage gates, integrate onto main, and clean up the worktree.

Additional modes

  • --hotfix: Cherry-pick to main + tag. Skip PR in solo.
  • --squash-state: Squash chore(state): commits before merge.

Integrate mode

Read specs/state.yaml key workflow_mode (team-pr | solo-git). Fall back to profiles/solo-git.md.

Mode When Ship path
solo-local workflow_mode: solo-git Auto: scripts/land-branch.sh if present, else fallback (Step 5)
team-pr workflow_mode: team-pr (default) gh pr create → gh pr merge --squash

If unsure, prefer solo-local. Also read state.yaml vcs.kind: Git follows the procedures below; Jujutsu uses workspaces/bookmarks and must not call Git-only landing scripts.

Process

Timing: bash scripts/bp-timing.sh start release-branch at invocation; bash scripts/bp-timing.sh end release-branch before handoff.

1. Final verification

<full test command> && <typecheck command> && <lint command>
git log main...HEAD --oneline | grep -vE "^[a-f0-9]+ (feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .+$" && echo "❌ Non-conventional commits found" || echo "✅ Commits verified"
# Block AI agent attribution (P1)
git log main...HEAD --format="%B" | grep -qiE 'co[- ]authored[- ]by' && echo "❌ Co-authored-by footer found — blocked" || echo "✅ No AI attribution"
  • [ ] All tests pass, no type errors, no lint violations, all commits follow Conventional Commits
  • [ ] NO Co-authored-by or Co-Authored-By in any commit body — P1 rule (CONVENTIONS.md § Git Attribution). land-branch.sh blocks the merge if found.

2. Coverage check

  • [ ] Overall coverage ≥ 80%; business logic coverage ≥ 95%

2a. Security gate

  • [ ] specs/security/REVIEW.md exists and is fresh (matches current branch diff)

2b. Audit-code & Traceability gates (HARD GATES — Issue #182)

  • [ ] Run bash scripts/lib/assert-epic-gate.sh release (asserts specs/AUDIT_LATEST.md passed; blocks release on failure).
  • [ ] No unresolved HIGH security findings with confidence ≥ 8 (or documented in specs/security/EXCEPTIONS.md).
  • [ ] Run gate-trace. FAIL blocks merge; CONCERNS requires explicit override in specs/state.yaml. WAIVED if no matrix available.

Adversarial refute framing (e45s32): The final pre-merge check is refute, not rubber-stamp. Before declaring ready, actively try to disprove traceability completeness — missing story tags, absent verify evidence, stale security review. Only proceed when refutation fails.

3. Diff review

4. Decision

Options: Release (solo-local) / Open PR / Keep branch / Discard

5. Integrate

Run commit-message first. Git solo-local uses land-branch.sh. Jujutsu team mode explicitly advances and pushes a bookmark; -m is mandatory for commit/describe operations:

# Git solo-local
bash scripts/land-branch.sh <task-slug> "feat(scope): description"
# Jujutsu team PR
jj describe -m "feat(scope): description"
jj bookmark set <task-slug> -r @
jj git push -b <task-slug>

Jujutsu solo-local landing is unsupported: run bp_require_vcs_operation "$PWD" land-branch and stop with its remediation instead of invoking the Git backend.

6. Create PR (team-pr only)

Create the pull request with a literal provenance marker in the body so agent-generated PRs are identifiable and do not rot silently:

<!-- bigpowers-provenance: agent-generated -->

Place the marker on its own line immediately after the ## Summary heading. Then merge via gh:

gh pr create --title "..." --body "$(cat <<'EOF'
## Summary
<!-- bigpowers-provenance: agent-generated -->

- ...

## Test plan
- [ ] ...

EOF
)"
gh pr merge --squash --delete-branch

semantic-release auto-detects the commit, bumps SemVer, tags the repo, generates release notes.

7a. Archive completed epic capsule

HARD GATE — When all epic stories are done (all done in execution-status.yaml), archive the capsule:

mv specs/epics/eNN-slug specs/epics/archive/

7b. CI verification & agent lock release (e39s02)

HARD GATE — Do NOT declare success until CI completes. Three-independent-facts (e45s15): commit landed, workflow green, registry visible — see REFERENCE.md.

bash scripts/wait-for-ci.sh --timeout 600 --interval 30
  • [ ] CI passes; release.ci_verified: true in state.yaml
  • On failure: handoff.next_skill = fix-bug

8. Clean up & return

Git: prune worktree, delete branch, return to main. Jujutsu: jj workspace forget <workspace> only after integration; do not delete its bookmark implicitly. Cycle-time: see REFERENCE.md.

Report: "Branch released."

Verify

→ verify: command -v gh >/dev/null 2>&1 && test -f specs/state.yaml && test -d skills/verify-work


Release Branch — Reference

Navigation

Lines Section
1 Title
3–22 Navigation
23–31 PR body template (team-pr mode)
32–35 Summary
36–41 Verify
42–47 specs/ artifacts
48–58 Worktree cleanup details
59–81 Cycle-time recording
82–100 Why not story_start minus story_end?
101–121 CI verification
122–127 Solo-local fallback detail
128–134 Handoff
135–159 Reference block 1

Release Branch — Reference

PR body template (team-pr mode)

PR_TITLE="<type>(<scope>): <description>"
echo "$PR_TITLE" | grep -vE "^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .+$" && echo "❌ ERROR: PR Title must follow Conventional Commits"

gh pr create \
  --title "$PR_TITLE" \
  --body "$(cat <<'EOF'
## Summary
- [What this PR does]
- [Key decisions made]

## Verify
- [ ] All tests pass
- [ ] Coverage gates met (≥80% overall, ≥95% business logic)
- [ ] CONVENTIONS.md compliance verified
- [ ] PR Title follows Conventional Commits (for automated release)

## specs/ artifacts
- [List any specs/ files produced or updated]
EOF
)"

Worktree cleanup details

# From the main repo root
git worktree prune
git worktree remove ../<branch-name> 2>/dev/null || true
git branch -d <branch-name>

If git worktree remove fails due to uncommitted changes, ask: "There are uncommitted changes in the worktree. Force remove? (y/n)". If yes: git worktree remove -f ../<branch-name>.

Cycle-time recording

After landing the branch, record delivery metrics using the git-derived, additive script (replaces hand-arithmetic):

bash scripts/record-cycle-time.sh append \
  --story <story_id> --bcps <bcps> \
  --range "$(git merge-base main HEAD)..HEAD" \
  --file specs/metrics/cycle-times.yaml

This appends a row to the cycle-times ledger with two separated metrics:

  • effort_hours — ADDITIVE. Idle-stripped estimated effort from git commit history (git-hours model: 120-min session threshold, 120-min first-commit pad). Sums exactly to whole-repo effort. NO hand-arithmetic, NO wall-clock includes.
  • lead_time_minutes — calendar latency from first commit to merge. Median-aggregated across stories; NEVER summed.

The script also runs an additivity self-check: Σ(story effort) == whole-repo effort within rounding tolerance.

Why not story_start minus story_end?

The previous hand-arithmetic approach (survey-context writes story_start, release-branch writes story_end, agent hand-computes cycle_minutes) was retired because:

  1. It was agent-self-reported — trivially fabricated or mis-subtracted.
  2. Wall-clock included overnight/weekend/UAT gaps — calendar latency, not coding effort.
  3. The bcp_per_hour metric was computationally meaningless (velocity derived from a latency measurement).

The new approach derives effort from commit history (objective, reproducible) and lead time from first commit → merge (honest calendar latency). See docs/references/bcp.md for BCP sizing context and scripts/record-cycle-time.sh for the full algorithm.


CI verification

The CI polling logic has been extracted to scripts/wait-for-ci.sh. See the script's --help for usage. Step 7b of the main SKILL.md invokes it directly:

bash scripts/wait-for-ci.sh --timeout 600 --interval 30

Exit codes:

  • 0 — all workflows green. Set release.ci_verified: true in state.yaml.
  • 1 — at least one workflow failed. Prints failure URLs. Set handoff.next_skill = fix-bug.
  • 2 — timeout. CI did not complete. Retry or investigate.
  • 0 with warning — gh CLI not available, git-only fallback confirmed push landed but CI status unverified.

The script handles: auto-discovery of all workflows for the current branch/commit, polling until completion, success/failure/timeout exit codes, and git-only fallback when gh CLI is unavailable.


Solo-local fallback detail

The fallback sequence (Path B above) handles the "remote has moved" case with git pull --rebase. Use when scripts/land-branch.sh is absent.

Acceptance: When fallback runs, main is updated, feature branch is deleted locally, and output states "used fallback merge (land-branch.sh not found)".

Handoff

Gate: READY -> next: survey-context Writes: state.yaml handoff.next_skill = survey-context


Reference block 1

# Fallback: manual squash-merge when land-branch.sh is absent
FEATURE_BRANCH=<task-slug>
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo main)

# Ensure we're on the feature branch
if [ "$(git branch --show-current)" != "$FEATURE_BRANCH" ]; then
  git checkout "$FEATURE_BRANCH"
fi

# Checkout default branch and update
git checkout "$DEFAULT_BRANCH"
git pull --rebase origin "$DEFAULT_BRANCH" 2>/dev/null || git pull origin "$DEFAULT_BRANCH"

# Squash-merge the feature branch
git merge --no-ff "$FEATURE_BRANCH" -m "<conventional-commit-message>"

# Push
git push origin "$DEFAULT_BRANCH"

# Clean up local feature branch
git branch -d "$FEATURE_BRANCH"

04 同仓库更多 Skills