ユーザーが指定した固定基点と HEAD の差分を2軸でレビューします:
- 規準 (Standards) — コードがこのリポジトリに文書化されたコーディング規約に準拠しているか?
- 仕様 (Spec) — コードが元の Issue / PRD / 仕様を忠実に実装しているか?
両方の軸は並列サブエージェントとして実行され、互いのコンテキストを汚染しません。その後、本スキルがそれらの結果を集約します。
Issue トラッカーが提供されているはずです。docs/agents/issue-tracker.md がない場合は /setup-matt-pocock-skills を実行してください。
プロセス
1. 固定基点を確定する
ユーザーが固定基点として指定したもの(コミットSHA、ブランチ名、タグ、main、HEAD~5 など)を使用します。指定がない場合は、ユーザーに確認してください。
diff コマンドを一度取得します:git diff <fixed-point>...HEAD(三点リーダーを使用し、マージベースとの比較を行います)。また、git log <fixed-point>..HEAD --oneline でコミットのリストも記録します。
先に進む前に、固定基点が解決可能であること(git rev-parse <fixed-point>)と、差分が空でないことを確認してください。無効な参照や空の差分は、ここで失敗させるべきであり、2つの並列サブエージェント内部で失敗させてはいけません。
2. 仕様ソースを特定する
元の仕様を以下の順序で探します:
- コミットメッセージ内の Issue 参照(
#123、Closes #45、GitLab の!67など)—docs/agents/issue-tracker.mdのワークフローを使って取得します。 - ユーザーが引数として渡したパス。
- ブランチ名や機能に一致する
docs/、specs/、.scratch/配下の PRD/仕様ファイル。 - 何も見つからない場合は、ユーザーに仕様の場所を確認します。ユーザーが「ない」と言った場合、仕様サブエージェントはスキップし、「利用可能な仕様なし」と報告します。
3. 規準ソースを特定する
コードの書き方を文書化したリポジトリ内のファイル(例:CODING_STANDARDS.md、CONTRIBUTING.md)を探します。
リポジトリが文書化している内容に加えて、規準軸は常に以下の不吉な匂いのベースライン(Fowler のコードの不吉な匂い、『リファクタリング』第3章)を考慮します。これはリポジトリが何も文書化していない場合でも適用されます。2つのルールがこれを束縛します:
- リポジトリが優先される。 文書化されたリポジトリの規約が常に優先されます。ベースラインでフラグが立てられるものでも、リポジトリの規約がそれを支持している場合は、その不吉な匂いは抑制します。
- 常に判断が必要。 各不吉な匂いはラベル付きのヒューリスティック(「可能性のある Feature Envy」)であり、絶対的な違反ではありません。そして、ここでの他の規約と同様に、ツールがすでに強制しているものはスキップします。
各不吉な匂いは、「それが何か」→「修正方法」を読み取り、差分と照合します:
- 怪しい名前 (Mysterious Name) — 名前がその機能や保持するものを明らかにしない関数、変数、型。→ 名前を変更する。正直な名前が思いつかないなら、設計が曖昧です。
- 重複コード (Duplicated Code) — 同じロジックの形状が、変更内の複数のハンクやファイルに出現する。→ 共通の形状を抽出し、両方から呼び出す。
- Feature Envy — 自身のデータよりも他のオブジェクトのデータに多くアクセスするメソッド。→ メソッドを、それが羨んでいるデータを持つオブジェクトに移動する。
- データのむら (Data Clumps) — 同じフィールドやパラメータのセットが頻繁に一緒に使われる(型として生まれたいと思っている)。→ それらを1つの型にまとめ、それを渡す。
- プリミティブへの執着 (Primitive Obsession) — ドメインの概念に独自の型を与えるべきところで、プリミティブや文字列が代用されている。→ その概念に独自の小さな型を与える。
- 繰り返されるスイッチ (Repeated Switches) — 同じ型に対する同じ
switch/ifの連鎖が、変更全体で繰り返し出現する。→ ポリモーフィズムに置き換えるか、両方の場所で共有する1つのマップを使用する。 - ショットガン手術 (Shotgun Surgery) — 1つの論理的な変更が、差分内の多くのファイルに散らばった編集を強いる。→ 一緒に変更されるものを1つのモジュールに集める。
- ** divergent change** — 1つのファイルやモジュールが、無関係な複数の理由で編集される。→ 各モジュールが1つの理由で変更されるように分割する。
- 投機的汎用性 (Speculative Generality) — 仕様にないニーズのために追加された抽象化、パラメータ、フック。→ 削除する。本当のニーズが現れるまでインライン化して戻す。
- メッセージ連鎖 (Message Chains) — 呼び出し元が依存すべきでない長い
a.b().c().d()のナビゲーション。→ 最初のオブジェクトの1つのメソッドの背後にウォークを隠す。 - 中間オブジェクト (Middle Man) — 主にさらに委譲するだけのクラスや関数。→ それを削除し、実際のターゲットを直接呼び出す。
- 拒絶された遺贈 (Refused Bequest) — 継承したもののほとんどを無視したりオーバーライドするサブクラスや実装者。→ 継承をやめ、コンポジションを使用する。
4. 両方のサブエージェントを並列に起動する
2つの Agent ツール呼び出しを含む1つのメッセージを送信します。両方に general-purpose サブエージェントを使用します。
規準サブエージェントのプロンプト — 以下を含めます:
- 完全な diff コマンドとコミットリスト。
- 手順3で見つけた規準ソースファイルのリスト。さらに、手順3の不吉な匂いのベースライン全体をそのまま貼り付けます — サブエージェントは他にアクセスできません。
- 指示:「報告 — 該当するファイル/ハンクごとに — (a) 文書化された規約に違反している箇所:規約を引用(ファイルとルール); そして (b) 見つけたベースラインの不吉な匂い:名前を付け、ハンクを引用。明確な違反と判断の余地のあるものを区別すること。文書化された規約の違反は明確な場合があるが、ベースラインの不吉な匂いは常に判断の余地があり、文書化されたリポジトリの規約はベースラインよりも優先される。ツールがすでに強制しているものはスキップ。400語以内。」
仕様サブエージェントのプロンプト — 以下を含めます:
- diff コマンドとコミットリスト。
- 仕様へのパスまたは取得した内容。
- 指示:「報告: (a) 仕様が要求しているが不足または不完全な要件; (b) 差分に含まれているが要求されていない振る舞い(スコープクリープ); (c) 実装されているように見えるが実装が間違っていると思われる要件。各所見について仕様の行を引用。400語以内。」
仕様がない場合は、仕様サブエージェントをスキップし、最終報告書にその旨を記載します。
5. 集約する
## 規準 と ## 仕様 の見出しの下に、2つのレポートをそのまま、または軽くクリーニングして提示します。所見をマージしたり再評価したりしないでください。2つの軸は意図的に分離されています(2軸の理由 を参照)。
最後に1行の要約を付けます:軸ごとの所見の総数と、各軸内での最悪の問題(もしあれば)。軸をまたいで単一の勝者を選ばないでください。それが、この分離が防ごうとしている再評価です。
2軸の理由
変更は、一方の軸を通過し、もう一方の軸で失敗することがあります:
- すべての規約に従っているが、間違ったものを実装しているコード → 規準 合格、仕様 不合格。
- Issue が要求したことを正確に行っているが、プロジェクトの規約を破っているコード → 仕様 合格、規準 不合格。
それらを個別に報告することで、一方の軸が他方を隠してしまうことを防ぎます。