マガジン

AIに直させたら別の所が壊れた:リグレッションを防ぐ修正の頼み方

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

チェックリストとコード差分の紙を見比べ、送料計算の修正範囲を確認する手元
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

結論から言うと、リグレッションを防ぐには「直す前に、今動いている部分をテストで固定する」「AIに触ってよい範囲を先に決める」「終わったら差分で範囲外に触れていないか見る」の3点が基本です。テストは、用意したケースでの挙動変化を検知する助けになりますが、テストにないケースまで守るものではありません。 この記事では、修正前から確認までの手順と、そのまま貼れる依頼文テンプレートを紹介します。例には、説明用に作った小さな送料計算のコードを使います。実在のプロジェクトではなく、記事内のテスト値も私が手計算したものです。実際に実行して確かめた結果ではないので、自分の環境で動かしてから使ってください。

この記事の目次
  1. 全体の流れ
  2. 直す前に「今の挙動」をテストで固定する
  3. 変更範囲を限定する依頼文テンプレート
  4. 差分で影響範囲を確かめる
  5. 最後のテスト実行と見落としやすい点

全体の流れ

  1. 作業用ブランチを切る
  2. 今の挙動をテストで固定する(直したい不具合以外)
  3. 直したい不具合を再現するテストを1本足す
  4. 範囲を限定した依頼文でAIに修正を頼む
  5. 差分で変更ファイルと行数を確認する
  6. テストを全件実行し、既存テストが書き換わっていないか確かめる

ブランチは、失敗したときに捨てられるようにするためです。Gitでは git switch -c で、新しいブランチの作成と切り替えを一度に行えます。

bash
git switch -c fix-shipping-border

直す前に「今の挙動」をテストで固定する

ここが肝です。固定するのは「正しい仕様」ではなく「いま出ている結果」です。このようなテストは、挙動が変わったことを検知する目的なので、バグが混じっていても構いません。ただし、直したい不具合そのものは固定しないでください。

説明用の例

次のコードは、小計が5000円「以上」なら送料無料にしたいのに、現状は「5000円を超えたら」になっているという想定の例です。

js
// price.js(説明用の例)
function calcTotal(items, couponCode) {
  const subtotal = items.reduce((s, i) => s + i.price * i.qty, 0);
  const discount = couponCode === 'SAVE10' ? Math.floor(subtotal * 0.1) : 0;
  const discounted = subtotal - discount;
  const shipping = discounted > 5000 ? 0 : 500;
  return { subtotal, discount, shipping, total: discounted + shipping };
}
module.exports = { calcTotal };
js
// price.test.js(説明用の例)
const test = require('node:test');
const assert = require('node:assert');
const { calcTotal } = require('./price');

// --- 現状の挙動を固定するテスト ---
test('クーポンの割引は小数点以下を切り捨てる', () => {
  const r = calcTotal([{ price: 1005, qty: 1 }], 'SAVE10');
  assert.deepStrictEqual(r, { subtotal: 1005, discount: 100, shipping: 500, total: 1405 });
});
test('送料は割引後の金額で判定する', () => {
  const r = calcTotal([{ price: 2700, qty: 2 }], 'SAVE10'); // 小計5400→割引後4860
  assert.strictEqual(r.shipping, 500);
});
test('4999円は送料あり、5001円は送料なし', () => {
  assert.strictEqual(calcTotal([{ price: 4999, qty: 1 }]).shipping, 500);
  assert.strictEqual(calcTotal([{ price: 5001, qty: 1 }]).shipping, 0);
});

// --- 直したい不具合(修正前は失敗する想定) ---
test('ちょうど5000円は送料無料', () => {
  assert.strictEqual(calcTotal([{ price: 5000, qty: 1 }]).shipping, 0);
});

2つ目のテストが「巻き添え防止」の役目を持ちます。AIが判定を割引前の小計に変えてしまうと、このテストが失敗して気づけます。実行は Node.js標準のテストランナー の node --test で行います。公式ドキュメントでは、テストに失敗があればプロセスの終了コードが1になると説明されています。検出されるファイル名のパターンなど、実行対象は利用中のNode.jsのバージョンや指定方法に左右されるため、プロジェクトの設定も確認してください。

bash
node --test

最初に、不具合テスト以外の3本が通り、不具合テストだけが失敗する状態を確認します。ここで固定用のテストが落ちるなら、期待値の計算違いか、前提の読み違いです。AIが固定用テストを書いた場合も、期待値は「現状のコードを実行した結果」と一致している必要があります。AIは期待値を仕様から推測して書くことがあるので、実行して確かめてください。

確認できたら、テストをコミットしておきます。こうしておくと、後の差分にはAIの変更だけが出ます。

bash
git add price.test.js
git commit -m "test: 送料計算の現状挙動を固定"

変更範囲を限定する依頼文テンプレート

次のテンプレートの 【 】 を埋めて、AIに渡します。範囲、禁止事項、報告の形式を決めておくと、余計な変更が減ります。

text
【ファイル名】の不具合を直してください。

■ 不具合
【例:小計がちょうど5000円のとき送料が無料にならない。5000円以上で無料にしたい】

■ 直したい理由を確認するテスト
【テスト名】が現在失敗しています。これを通してください。

■ 変更してよい範囲
- 【ファイル名】の【関数名】の中だけ
- 新しい依存パッケージは追加しない

■ 変更してはいけないこと
- 既存のテストファイル(*.test.js)は編集・削除・スキップしない
- 関数名、引数、戻り値の形は変えない
- 関係のない整形、名前変更、リファクタリングをしない

■ 進め方
1. 原因だと考える箇所と理由を、コードを変える前に説明する
2. 最小の変更で直す
3. 変更した行と、その理由を一覧で報告する
4. 範囲外を変えないと直せない場合は、変更せず相談する

■ 現在のコード
【該当部分を貼る】

「相談する」の指定は重要です。範囲外の変更が必要なとき、AIが黙って広げるのを止められます。テストが邪魔に見えたときにテスト側を直してしまう動きも、禁止事項で抑えられます。

機密情報は貼らないでください。実コードに社内の値や個人情報がある場合は、ダミーの値に置き換えてから渡します。

差分で影響範囲を確かめる

AIが修正を返したら、反映した後で次の順に見ます。git diff の --name-only は変更ファイル名だけ、--stat はファイルごとの追加・削除行の概要を出します。

bash
git status
git diff --name-only
git diff --stat
git diff

テストをコミット済みなら、git diff には作業ツリーの未コミット変更が出ます。AIの変更だけが表示されるのは、そのほかの未コミット変更がない場合です。git diff は新規の未追跡ファイルを表示しないので、git status も併せて見てください。

説明用の例で期待する差分は、price.js の1行だけです。> が >= に変わるイメージです。

判断表

  • 変更ファイルが依頼した範囲だけ、判断:次へ進む
  • *.test.js が変更されている、判断:原則やり直し。期待値が本当に誤りなら、人が理由を確認して自分で直す
  • 範囲外の関数やファイルが変わっている、判断:戻して、範囲を再指定する
  • 変更行数が不具合の大きさに比べて多い、判断:整形や名前変更が混ざっていないか確認し、最小限に直させる
  • 新しいファイルや依存が増えている、判断:理由を聞き、不要なら削除

戻すときは、ブランチを切ってあるので、変更をコミットしないまま捨てるか、ブランチごと作り直せば済みます。

最後のテスト実行と見落としやすい点

差分に問題がなければ node --test を再実行し、全件が通ることを確認します。不具合テストが通り、固定した3本も通っていれば、少なくとも固定した範囲では挙動は変わっていません。

逆に言うと、固定していない挙動は守られていません。次のような点に注意してください。

  • 固定テストの数が少ないと、守れる範囲も狭いままです。今回の修正が触れそうな分岐(境界値、空の入力、クーポンなし)を、直す前に1本ずつ足します。
  • テストを足す作業はAIに任せてもよいですが、期待値を「現状の出力」に合わせたかを、人が実行して確かめます。
  • 通ったあとに「全体を見直してください」と頼まず、不具合ごとに依頼を分けます。範囲が広がると、差分の確認が難しくなります。

この流れは、最初の準備に数分かかります。それでも、壊れた箇所を後から探すより、早く済むことが多いはずです。次に頼むときは、依頼文の「変更してよい範囲」を1行だけ増やすところから始めてみてください。

出典・参考資料