发布分支
danielvm-git2026-10-27查看 1938复制 980
为功能分支做出合并/PR/保留/丢弃决策,验证覆盖率门禁,使用 gh 创建 PR,并清理工作树。当功能完成并准备发布时使用,或当用户说 \"release\"、\"merge\" 或 \"open a PR\" 时使用。
📘如何使用这个技能
- 1复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
- 2打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
- 3粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
- 4直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景
💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。
SKILL.md10963 chars
--- 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\"." --- <!-- 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 ```bash <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) - [ ] No unresolved HIGH findings with confidence ≥ 8 (or all documented in `specs/security/EXCEPTIONS.md` with sign-off rationale) If REVIEW.md is missing or stale → run `security-review` inline. Findings block the merge unless documented in EXCEPTIONS.md. ### 2b. Traceability gate Run `gate-trace` before merge. FAIL blocks merge; CONCERNS requires explicit override in `specs/state.yaml` (`traceability_override: CONCERNS accepted, reason: <explanation>`). 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 - [ ] All commits intentional, no secrets, CONVENTIONS.md compliance ### 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: ```bash # 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: ```markdown <!-- bigpowers-provenance: agent-generated --> ``` Place the marker on its own line immediately after the `## Summary` heading. Then merge via `gh`: ```bash 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: ```bash 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](REFERENCE.md#three-independent-facts-release). ```bash 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](REFERENCE.md#cycle-time). 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) ```bash 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 ```bash # 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 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 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 ```bash # 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" ```