diff --git a/.claude/skills/prepare-pr/SKILL.md b/.claude/skills/prepare-pr/SKILL.md new file mode 100644 index 00000000..93b66489 --- /dev/null +++ b/.claude/skills/prepare-pr/SKILL.md @@ -0,0 +1,178 @@ +--- +name: prepare-pr +description: > + `pnpm push` 完了後の PR 作成フローを標準化する試験運用スキル。 + jj commit description と diff から PR title / body の初稿を生成し、 + ユーザーの明示承認を経て `pnpm prepare-pr-body` → `pnpm create-pr` を実行する。 + トリガー条件: `/prepare-pr`、「PR を作成して」「PR 作成して」と明示された場合。 + 単なる「PR レビュー」「git 操作」では発動しない。 +--- + +# Prepare PR + +`pnpm push` 完了後の PR 作成フローを標準化するインタビュー型スキル (試験運用)。 + +ADR-028 (外部可視成果物の生成コマンドの実行ゲート) の運用フローを具体化し、 +Claude が draft を提示 → ユーザー承認 → harness 再確認の三段階で安全に PR を作成する。 + +## ステータス + +**試験運用** (2026-04-19〜)。 + +評価軸: +- 発火頻度 (月何件) +- 3-4 ステップ (status 確認 → draft → 承認 → 実行) を通せているか +- Claude が勝手に AskUserQuestion をスキップしないか +- body が切り詰めなく保存できているか + +半年後に正式採用 / 改良 / 廃止を判断する。 + +## 前提条件 + +本 skill を走らせる前に以下が成立していること: + +1. `.claude/settings.json` の `permissions.ask` に `pnpm create-pr*` 登録済 (PR-B / ADR-028) +2. `pnpm prepare-pr-body` / `pnpm prepare-pr-body:cleanup` スクリプト利用可 (PR-B / [scripts/prepare-pr-body.ps1](../../../scripts/prepare-pr-body.ps1)) +3. jj working copy は `pnpm push` 完了済 (bookmark が remote に反映されている) +4. master との差分が存在する + +前提が不成立の場合は skill を開始せず、ユーザーに不足工程を促す。 + +## 実行手順 + +### Step 1: 現状確認 + +以下のコマンドで状態を確認する: + +```bash +jj status +jj log -r 'master..@' --no-graph -T 'change_id.short() ++ " | " ++ description ++ "\n\n"' +jj log -r @ --no-graph -T 'local_bookmarks.map(|b| b.name()).join(",") ++ " -> " ++ remote_bookmarks.map(|r| r.name()).join(",")' +``` + +チェック項目: +- `master..@` 差分が空 → skill 終了 (commit がない) +- `@` に local bookmark なし → skill 終了 (`jj bookmark create` を促す) +- remote bookmark が空 → skill 終了 (`pnpm push` を促す) + +### Step 2: PR title 初稿生成 + +最新 commit の `description.first_line()` を取得: + +```bash +jj log -r @ --no-graph -T 'description.first_line()' +``` + +調整: +- 70 文字超: 短縮候補を提示 (要点を保ったまま短く) +- conventional commits prefix (`feat:` / `fix:` / `refactor:` / `docs:` / `chore:` / `perf:` / `ci:` / `test:`) を維持 +- プロジェクト固有の suffix (例: `(PR-D)`) は commit に既にあれば保持 + +### Step 3: PR body 初稿生成 + +`jj diff -r 'master..@' --stat` と `jj log -r master..@` を読み取り、以下のセクション構成で初稿を生成: + +```markdown +## Summary +- <変更点の bullet 3-6 個、技術的要点を簡潔に> + +## Context +<なぜこの変更か。参照 ADR / PR / issue / セッション> + +## Validation +- [ ] +- [ ] <手動 smoke test 内容> +- [ ] + +## References +- <関連 ADR> +- <参照 PR> +- <関連 memory> +``` + +生成時の注意: +- 実装の意図を復元する (diff だけでなく commit message も読む) +- プロジェクトの ADR 命名 (`ADR-XXX`) と PR 番号 (`PR #XX`) のリンクを明記 +- Validation は実測値を使う (ビルド結果・テスト件数・review 所要時間など) + +### Step 4: 明示承認 (AskUserQuestion 必須) + +Claude は title / body 初稿を user に提示し、**AskUserQuestion ツールで明示承認を取る**。 + +選択肢例: +- **OK / 実行**: そのまま `pnpm create-pr` を実行 +- **修正**: ユーザーが title / body の修正指示を入れる → Step 3 に戻る +- **中止**: PR 作成を行わない + +このステップは auto mode でも必ず停止する。AskUserQuestion を使わない (別の方法で確認したつもりになる) のは ADR-028 違反。 + +### Step 5: body を一時ファイルに書き込み + +承認された body を `pnpm prepare-pr-body` 経由で `.tmp-pr-body.md` に UTF-8 (BOM なし) で書き出す: + +```bash +cat <<'EOF' | pnpm prepare-pr-body + +EOF +``` + +stdin を使うのは `--body` 引数経由のシェル切り詰め問題を回避するため (PR #51 / memory `feedback_pnpm_create_pr_body.md`)。 + +### Step 6: `pnpm create-pr` を foreground 実行 + +```bash +pnpm create-pr --title '' --body-file .tmp-pr-body.md +``` + +`permissions.ask` プロンプトで harness 側が再確認する (二次防衛層)。ユーザーは deny して取り消しも可能。 + +### Step 7: 一時ファイルのクリーンアップ + +PR 作成が成功したら `.tmp-pr-body.md` を削除: + +```bash +pnpm prepare-pr-body:cleanup +``` + +PR 作成が失敗した場合は body を手元に残して原因調査できるようにクリーンアップを遅らせてよい。 + +## 設計原則 + +### user-supplied text を尊重 (ADR-022) + +Claude が生成した draft は「初稿」。ユーザーの修正指示 (「〜の記述を消して」「References に PR #XX を追加して」等) を優先し、skill 内で忠実に反映する。 + +承認後の title / body は automated actor (takt / cli-*) が書き換えない。 + +### ADR-028 の二層防衛を活かす + +| 層 | メカニズム | 本 skill での役割 | +|---|---|---| +| 一次 (Claude 側) | memory `feedback_bookmark_auto_naming.md` + 本 skill の AskUserQuestion | ユーザーが明示的に「OK」を出すまで進まない | +| 二次 (harness 側) | `.claude/settings.json` の `permissions.ask` | Claude が一次を誤って飛ばしても、ここで再確認が発火する | + +どちらか一方を無効化すると一層だけになる。両方必須。 + +### 自動化コンポーネントから独立 + +takt / claude -p / cli-* の自律ループはこの skill を呼ばない。interactive session で Claude が明示指示 (`/prepare-pr` 起動や「PR を作成して」依頼) を受けた時のみ発動する。 + +### body は必ず一時ファイル経由 + +`--body "..."` 引数形式は複数行 / シェル quote で切り詰めリスクがある (PR #51 で修正済だが、defense-in-depth として helper 経由を徹底)。 + +## 避けるべきアンチパターン + +- **AskUserQuestion をスキップ**: auto mode でも必須。飛ばせば ADR-028 一次防衛が崩壊する +- **`--body "..."` を直接使う**: `.tmp-pr-body.md` 経由を徹底する +- **skill から `jj bookmark create` / `pnpm push` を実行**: 事前工程で完了済の前提。skill の責務外。必要なら Claude が別途実行する +- **Claude が承認済 draft を勝手に「改善」**: ユーザーが承認した後の二重書き換えは ADR-022 違反 +- **PR 作成失敗時に無言で `cleanup`**: 失敗原因の body を失う。失敗時は body を手元に残す + +## 関連 + +- **ADR-028** (外部可視成果物の生成コマンドの実行ゲート): 本 skill の設計根拠 +- **ADR-022** (自動化コンポーネントの責務分離): user-supplied text の保護 +- **PR #57** (PR-B): `permissions.ask` + `pnpm prepare-pr-body` helper +- **memory `feedback_bookmark_auto_naming.md`**: 一次防衛層の源 +- **memory `feedback_pnpm_create_pr_body.md`**: `--body` の切り詰め対策 diff --git a/docs/todo.md b/docs/todo.md index 23ac6176..f0cbf7a8 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -159,61 +159,9 @@ --- -## セッション 247510ea 由来: 整備タスク群 (PR-D) - -> **最優先ブロック**。PR #54 / #55 のマージ後に確定した ADR / 仕組みの整備作業。残 1 タスク。 -> -> **背景コンテキスト**: -> - **発端セッション**: `247510ea-3f24-4b87-8f68-3c860e1b1b4e` (2026-04-18) -> - **先行成果**: -> - PR #54 (cli-merge-pipeline の revset 拡張 `@-..@--` + trunk filter) -> - PR #55 (cli-pr-monitor への同パターン水平展開) -> - PR-A (ADR 集約 / PR #56 merged): ADR-028 新設、ADR-021 原則 5 追加、ADR-024 本採用、ADR-019 可換性追記 -> - PR-B (Ask ルール + body helper / PR #57 merged): `permissions.ask` 4 パターン追加、`scripts/prepare-pr-body.ps1` 新設 -> - PR-C (jj-helpers 抽出 / 本 PR): `src/lib-jj-helpers/` 新設、3 クレート差し替え、重複テストを lib 側に集約 -> - **ユーザーフィードバック 3 点** (memory `feedback_bookmark_auto_naming.md` に記録済): -> 1. auto mode は試験導入。基本は自律実行だが、**最終出力の責任をユーザーが握るため `pnpm create-pr` / `pnpm merge-pr` は事前許可必須** -> 2. bookmark 名は Claude が自動採番して OK -> 3. `pnpm push` は foreground 実行 OK (permission prompt がゲート) -> - **設計的な確認事項** (ADR-028 / ADR-019 追記で明文化済): -> - `hooks` での `block` は許可後も効くので UX 崩壊 → 採用せず -> - 代わりに **settings.json の Ask ルール** で「毎回確認プロンプト」を出す (PR-B で実装済) -> - CodeRabbit 無料枠の制約 (1h 3 回、public リポジトリ限定) を許容し、rate limit 耐性の作り込みは **しない** (レビュアーロックイン回避のため) -> -> **PR 依存関係**: -> ``` -> PR-A (ADR 集約, merged) ──┬── PR-B (Ask ルール + body helper, merged) ── PR-D (prepare-pr skill) -> └── PR-C (jj-helpers 抽出, 本 PR) -> ``` - -### 7. [PR-D] `prepare-pr` skill (試験運用) - -- **やろうとしたこと**: auto mode で安全に PR を作成するためのインタビュー型 skill を試験運用として整備。commit log と diff から PR title / body の初稿を生成し、ユーザー承認後に `pnpm create-pr` を foreground 実行するフローを標準化 -- **現在地**: 未着手。PR-B merge 後に着手 (ADR-028 の運用フローと PR-B の body helper が前提) -- **実装内容**: - - [ ] **`.claude/skills/prepare-pr/SKILL.md` 新規** (試験運用ステータス) - - 起動条件: 「PR を作成して」等の明示依頼、または `/prepare-pr` 起動 - - ステップ: - 1. `jj status` + `jj log -r master..@` で差分サマリ取得 - 2. commit description から PR title 初稿生成 - 3. diff から PR body 初稿生成 (Summary / Changes / Test Plan / References セクション) - 4. Claude が提示 → **明示承認** (AskUserQuestion 強制) - 5. `pnpm prepare-pr-body` (PR-B 成果物) 経由で body 書き込み - 6. `pnpm create-pr --title ... --body-file ...` foreground 実行 (Ask プロンプトで再確認) - 7. `.tmp-pr-body.md` 削除 - - [ ] **検証**: skill 起動テスト、PR 作成完遂確認 -- **詰まっている箇所**: - - **skill の既存 frontend-design/pre-push-review との連携**: 既存スキルとの衝突可否を skill-sync-check で確認 -- **想定サイズ**: 小〜中 (skill 定義 1 本、~100-200 行) -- **依存**: **PR-A** (ADR-028), **PR-B** (M1 body helper, Ask ルール) -- **見積**: 1-2 時間 -- **参照**: ADR-028, PR-B 成果物 - ---- - ## その他の進行中タスク -### 8. 雑務: 過去の delete-pending bookmark cleanup +### 7. 雑務: 過去の delete-pending bookmark cleanup - **やろうとしたこと**: `jj git push --tracked` で `Refusing to push deleted bookmark fix/push-allow-new` の警告が出るため、`jj bookmark forget fix/push-allow-new` で消す - **現在地**: 未対応。push を block しないので緊急性なし