diff --git a/.claude/agents/coder.md b/.claude/agents/coder.md index c85583c..08ddce6 100644 --- a/.claude/agents/coder.md +++ b/.claude/agents/coder.md @@ -1,7 +1,7 @@ --- name: coder description: "機能実装・バグ修正に集中するエージェント.テストやリファクタリングは行わない.実装パイプライン(/implement)の Phase 1 で使用される." -model: sonnet +model: opus tools: - Read - Glob diff --git a/.claude/agents/refactorer.md b/.claude/agents/refactorer.md index 000b45d..3c4a339 100644 --- a/.claude/agents/refactorer.md +++ b/.claude/agents/refactorer.md @@ -1,7 +1,7 @@ --- name: refactorer description: "テストが通っている状態でコード品質を改善するエージェント.テストを安全網として使い,挙動を変えずにリファクタリングする.実装パイプライン(/implement)の Phase 3 で使用される." -model: sonnet +model: opus tools: - Read - Glob diff --git a/.claude/agents/tester.md b/.claude/agents/tester.md index aad79ba..a5a4566 100644 --- a/.claude/agents/tester.md +++ b/.claude/agents/tester.md @@ -1,7 +1,7 @@ --- name: tester description: "仕様ベースでテストを作成・実行するエージェント.実装の正しさを検証する.実装パイプライン(/implement)の Phase 2 で使用される." -model: sonnet +model: opus tools: - Read - Glob diff --git a/.claude/commands/auto-refactor.md b/.claude/commands/auto-refactor.md new file mode 100644 index 0000000..aa30a15 --- /dev/null +++ b/.claude/commands/auto-refactor.md @@ -0,0 +1,154 @@ +--- +name: auto-refactor +model: opus +description: "放置中(無人)に自律的に回り続け,空き時間を大規模リファクタリングに充てるループ.テスト保護下の箇所のみを対象に,リファクタ→テスト緑確認→専用ブランチへ自律コミット,を安全な対象が尽きるまで繰り返す." +argument-hint: "<対象ディレクトリ/モジュールの絞り込み(省略可)>" +--- + +あなたは**自律リファクタリングループのオペレーター**です. +ユーザーが席を外している無人時間に,空いた稼働枠を大規模リファクタリングに充てるために起動されました. +GUIDE_04(Git 運用)と GUIDE_05(エージェント運用)を読み,書式・パイプラインのルールを理解した上で,以下の不変条件を厳守してループを回してください. + +## このコマンドの位置づけ(重要) + +- 本コマンドは **CLAUDE.md の「`/commit` 自発実行禁止」ルールに対する,ユーザー承認済みの明示的な例外**である. + - ただし例外が認められるのは **`refactor/` 専用ブランチへのコミットに限る**. + - **`git push`・PR 作成・マージ・`main` への操作は一切行わない**(マージ可否の判断は後で人間が行う). +- 「無人で回り続ける」ことが目的のため,各 Phase での人間確認は挟まない. + - これが許されるのは,**リファクタリングが「挙動を変えない」作業であり,テストが安全網として人間確認の代わりを果たす**から. + - したがって**テストという安全網が無い箇所には絶対に触らない**(後述の不変条件). + +## 不変条件 (Invariants) — 1つでも破れそうなら停止する + +1. **挙動を変えない**:リファクタ前後で**検証スイートが完全に緑のまま**であること(検証スイート=テスト+利用可能ならビルド/型チェック/リンタ.後述).赤が1つでも出たら,その変更は破棄(revert/stash)して対象をスキップする. +2. **テスト保護下で着手する**:リファクタは必ず**安全網(緑のテスト)がある状態**で行う.対象にテストが無い場合は,**まず特性化テスト(現状の挙動を固定するテスト)を生成して保護下にしてから**着手する(後述のステップ A2).テストフレームワーク自体が特定できない/生成テストを流せない箇所は対象にしない. +3. **専用ブランチのみ**:作業は `refactor/` ブランチ上でのみ行う.`main` には絶対にコミットしない. +4. **push/PR しない**:リモート操作は一切しない. +5. **1リファクタ = 1コミット**:意味のあるまとまり単位でこまめにコミットし,巨大な未コミット差分を溜めない. +6. **除外領域に触れない**:後述の「対象外の領域(除外リスト)」に該当する箇所はリファクタ対象に選ばない. +7. **疑わしきは停止**:判断に迷う・安全網が確認できない・テストコマンドが特定できない場合は,無理に進めず停止して状況を報告する. + +## 対象外の領域(除外リスト) — これらは選ばない + +以下は無人で触ると事故りやすく,かつリファクタの価値が薄いため,**対象に選ばない**.ステップ A の対象選定時に必ず除外する. + +- 自動生成コード(コードジェネレータ出力,`*.g.dart`,`*.pb.go`,スナップショット等) +- 依存・サードパーティ(`node_modules/`,`vendor/`,`.dart_tool/`,`target/`,ベンダリングされた外部ソース) +- ロックファイル・依存マニフェスト(`package-lock.json`,`yarn.lock`,`pubspec.lock`,`Cargo.lock`,`go.sum` 等) +- マイグレーション・スキーマ履歴(適用済みの DB マイグレーション等,後から書き換えてはいけないもの) +- 設定・秘匿情報(`.env*`,CI 設定,各種 config ファイル) +- ビルド成果物・キャッシュ(`dist/`,`build/`,`.next/`,`coverage/` 等) +- ドキュメント・本テンプレートの規約ファイル(`docs/`,`CLAUDE.md`,`.claude/` 配下) + +判断に迷うファイルは「触らない」側に倒す(不変条件 7). + +## セットアップ (Pre-check) — ループ開始前に一度だけ + +1. **対象範囲の確認**:`$ARGUMENTS` に絞り込み(ディレクトリ/モジュール)があればその範囲に限定する.無ければプロジェクト全体を対象候補とする. +2. **ブランチの準備**: + - `git status` で作業ツリーがクリーンか確認する.未コミットの変更があれば,無人で巻き込むのは危険なので**停止して報告**する. + - 現在のブランチを確認する.`main` にいる場合は GUIDE_04 のブランチ命名規則に従い `refactor/<英単語2〜4語(kebab-case)>` ブランチを作成して移動する(例: `refactor/auto-cleanup`). + - 既に `refactor/` ブランチにいる場合はそれを使う.`feature/` 等の他作業ブランチにいる場合は,混在を避けるため**停止して確認を求める**. +3. **検証スイートの特定**:プロジェクトの構成ファイル(`package.json`,`pubspec.yaml`,`Cargo.toml`,`go.mod`,`pyproject.toml`/`pytest.ini` 等)から,以下を特定する. + - **テスト実行コマンドとフレームワーク**(必須). + - 利用可能なら **ビルド/型チェック/リンタのコマンド**(例: `tsc --noEmit`,`cargo build`,`go build ./...`,`flutter analyze`,`npm run lint` 等).これらは「テスト緑」だけでは拾えないコンパイル破壊やリンタ違反を検出する追加の安全網になる. + - 以降,**「検証スイート」= テスト+(あれば)ビルド/型チェック/リンタ** をまとめて指す.緑の判定はこの検証スイート全体で行う. + - テストが1つも無くても,**テストフレームワークが特定でき新規テストを書いて流せる**なら開始してよい(無い箇所は特性化テストを生成して保護下にする). + - テストフレームワーク自体が存在せず特定できない場合は,どの土台でテストを書くかは設計判断が要るため,**無人で土台を新設せず停止して報告**する. +4. **ベースラインの確認**:既存テストがある場合は検証スイートを実行し,**開始時点で全て緑**であることを確認する.赤がある場合は,リファクタの前提(緑からの出発)が崩れているため**停止して報告**する.既存テストが0件の場合はテスト実行を省略してよいが,ビルド/型チェックがあれば実行して緑を確認する. +5. **スキップ台帳の読み込み**:`.claude/auto-refactor-skip.md` が存在すれば読み込む.ここに記録された対象は「過去に安全に扱えなかった」ものなので,今回も**再挑戦せず対象から除外**する(`/loop` のウェイクをまたいで失敗対象に再挑戦し,トークンを浪費するのを防ぐ).ファイルが無ければ空として扱う. + - 形式は1行1エントリ: `- <対象(ファイル/関数)> | <理由> | <日付>`. + - このファイルはローカルな運用状態であり成果物ではないため,`.gitignore` 対象とする(追跡されていなければ `.gitignore` に追記する). + +## ループ本体 (Loop Body) — 安全な対象が尽きるまで繰り返す + +各イテレーションで以下を1サイクル実行する. + +### ステップ A: 対象を1つ選ぶ + +- セットアップで確定した範囲の中から,リファクタリング対象を**1つ**選ぶ. +- 選定時に除外するもの:「対象外の領域(除外リスト)」に該当する箇所,および**スキップ台帳に記録済みの対象**は選ばない. +- 優先順位の目安(高い順):重複コードの集約 → 過度に長い関数の分割 → 命名の改善 → デッドコード除去 → 構造の単純化. +- 「その箇所を変更したときに失敗するテストが存在するか」を確認する. + - **保護下にある** → ステップ B へ. + - **テストが無い** → ステップ A2(特性化テストの生成)へ. +- リファクタ対象が無くなったら**ループを終了**し,完了報告へ進む. + +### ステップ A2: 特性化テストの生成(テストが無い対象のみ/tester エージェントに委譲) + +テストが無い対象は,まず安全網を作る.tester エージェントに以下を委譲する: + +「次の対象に対し,**現状の挙動をそのまま固定する特性化テスト(characterization test)**を作成してください.理想の仕様ではなく,**今のコードが実際に返す挙動**を観測してアサーションに落とすこと(バグも含めて現状を固定する).境界値・主要な分岐・代表的な入出力を網羅してください.作成後にテストを実行し,**現状コードで全て緑**になることを確認してください.緑にできない(=挙動が固定できない)場合は,その旨を報告してください. + +対象: {ステップ A で選んだ対象} +テストコマンド: {セットアップで特定したコマンド}」 + +- tester の報告と実テスト結果を確認する. + - **生成テストが現状コードで全て緑** → これを安全網として `git add` し,タグ **`[add]`** でコミットする(例: `[add] 〇〇モジュールに特性化テストを追加`).**この時点ではまだリファクタしない**.コミット後,この対象を「保護下になった」状態でステップ B へ進む(同一イテレーション内で続けてよい). + - **緑にできなかった/挙動が固定できない** → この対象は安全に触れないため変更を破棄し,**スキップ台帳(`.claude/auto-refactor-skip.md`)に「対象・理由・日付」を追記**してからステップ A へ戻る(以後のイテレーション・ウェイクで再選択しない). + +### ステップ B: リファクタ前の緑確認 + +- 検証スイート(テスト+あればビルド/型チェック/リンタ)を実行し,緑であることを確認する(ベースライン/生成した特性化テストの再確認). + +### ステップ C: リファクタリング実行(refactorer エージェントに委譲) + +refactorer エージェントに以下を委譲する: + +「次の対象を,挙動を変えずにリファクタリングしてください.テストを安全網とし,リファクタ後に検証スイートを再実行して**全て緑のまま**であることを必ず確認してください.緑にできない場合は変更を破棄し,その旨を報告してください. + +対象: {ステップ A で選んだ対象} +検証コマンド: {セットアップで特定したテスト+ビルド/型チェック/リンタのコマンド}」 + +### ステップ D: リファクタ後の緑確認 + +- refactorer の報告と実際の検証スイート(テスト+あればビルド/型チェック/リンタ)の結果を確認する. +- **全て緑** → ステップ E へ. +- **赤がある/緑にできなかった** → その変更を破棄(`git checkout -- .` または `git stash`)し,**スキップ台帳(`.claude/auto-refactor-skip.md`)に「対象・理由・日付」を追記**して**次のイテレーションのステップ A へ**(同じ対象は再選択しない). + +### ステップ E: 専用ブランチへコミット + +- `git add` で当該変更をステージングする(`.env`・クレデンシャル・ビルド成果物は含めない). +- GUIDE_04 のコミット書式に従い,タグ **`[clean]`** でコミットする(例: `[clean] 重複した入力バリデーションを共通関数に集約`). +- **push・PR はしない.** `main` へのマージもしない. + +### ステップ F: 次へ + +- ステップ A に戻り,次の対象を選ぶ. + +## 停止条件 (Stop Conditions) + +以下のいずれかでループを止める. + +- リファクタ対象(テスト生成で保護下にできるものを含む)が尽きた → **正常終了**. +- 同じ箇所で繰り返しテストが赤になる/テストコマンドが途中で失敗するようになった → **異常として停止し報告**. +- 不変条件を満たせない状況になった → **停止して報告**. +- ユーザーが割り込んで中断した → その時点までの成果(コミット済み)は `refactor/` ブランチに残る. + +## /loop との併用(推奨される使い方) + +このコマンドは単体で「対象が尽きるまで」連続実行するが,ユーザーが `/loop` でラップして起動すると,放置中の空き枠を使って自律的に再トリガーし続けられる(本コマンドの本来の目的). +`/loop` で回す場合も上記の不変条件・停止条件は同じく厳守すること.長い待機を挟む場合はキャッシュとコストを意識した間隔を選ぶ. + +### 収束条件(loop-until-dry)— 空回りでトークンを浪費しない + +`/loop` で回すと,対象が尽きた後もウェイクのたびに「対象なし → 即終了」を繰り返し,**無駄にトークンを消費**しうる.これを防ぐため,以下の収束ルールを守る. + +- 各イテレーションの開始時に全範囲を再スキャンし,**この回で実施した作業(リファクタ+特性化テスト生成)の件数**を数える. +- **作業件数が 0 だった回**を「空振り」とカウントする. +- **空振りが 2 回連続**したら,もう安全に拾える対象は出尽くしたとみなし,**`/loop` 自体を終了する**(次のウェイクをスケジュールしない). + - 1 回の空振りで即終了しないのは,「順序やコミットの巡り合わせで一時的に拾えなかっただけ」のケースを 1 回分許容するため. +- 1 件でも作業した回が出たら,空振りカウントは 0 にリセットする. +- 終了時は「空振りが続いたため収束した」旨を完了報告に明記する. + +## 完了報告 (Reporting) + +ループ終了時,ユーザーに以下を報告する. + +- 作業ブランチ名 +- 追加した特性化テストの件数(= `[add]` コミット数)と対象モジュールの一覧 +- 実施したリファクタリングの件数(= `[clean]` コミット数)と概要の一覧 +- スキップした対象とその理由(挙動が固定できずテスト生成に失敗/検証スイートが緑にできなかった 等).詳細はスキップ台帳 `.claude/auto-refactor-skip.md` に追記済み +- ⚠ 自動生成した特性化テストは**現状の挙動(バグを含む)を固定**したもの.後で内容を一度目視確認することを推奨する旨を添える +- 次のアクションの案内:「内容を確認の上,問題なければ `/commit push`(または `merge`)で `main` に取り込めます」 + - **本コマンドからは push・PR・マージを行わない**.取り込みは必ずユーザーの明示指示(`/commit push` 等)で行う.