「AIを使えば早いですよ」と言った手前、バグの原因が分からないと言えなかった
「利用を開始しました」と表示されているのに、自転車の鍵は開かなかった。
土曜の10時12分、海沿いの公園にある貸し自転車ポート。先頭の利用者は受付で発行した1日券を使い、車体のQRコードを読み取った。スマートフォンでは利用が始まっている。それでも後輪の鍵は閉じたまま。もう一度試すと、今度は「利用中のため操作できません」と出た。
目の前には困っている利用者がいる。後ろには順番を待つ人もいる。スタッフは利用者へ謝りながら、保守を担当するフリーランスのエンジニアを見た。
「AIを使えば、保守はもっと早くできますよ」
数日前、運営スタッフにそう説明したのは自分だった。だから「まだ何が起きているか分かりません」とは言いにくかった。期待外れだと思われるのも、AIを使っているのに遅いと思われるのも怖い。「すぐ確認します」と答え、ノートPCを開いた。
ログには、通信に時間のかかった記録が一つあった。これが原因だと言い切ってしまえば、何かを説明できる。AIに修正させれば、数分後には差分を見せられるかもしれない。
エンジニアは、次の依頼を打ちかけた。
解錠APIがタイムアウトする不具合を直して。失敗したら再試行して。
AIも再試行処理の追加を候補に挙げた。変更は小さく見えた。原因が分からない気まずさから逃れるには、その案を受け入れるのが一番早く思えた。
その時、スタッフが小さく聞いた。
受付で出した1日券の人だけですか。会員の方は朝から使えています。
手が止まった。まだ、タイムアウトが原因だと確認できていない。再試行すれば、鍵が開かなかった利用を二重に開始する可能性もある。「急いでいるのだから直す」が、「急いでいるから、まず何が起きたかを短く残す」に変わった。
AIへバグ修正を頼む前に必要なのは、詳しい原因説明ではない。利用者が遭遇した問題を、修正前の状態で再び起こせる形にすることだ。開始条件、操作と実際の結果、期待する結果の3行があれば、AIは原因候補ではなく、直すべき問題へ戻りやすくなる。
原因を書く前に、起きたことを固定する
不具合の連絡を受けた直後は、原因を当てる言葉を書きたくなる。「APIが遅い」「状態管理が壊れた」「キャッシュが残った」と説明できると、仕事を前へ進めている感じがするからだ。
しかし、その説明が外れると、AIは違う問題を丁寧に直す。今回なら、通信の再試行は追加できても、1日券だけで起きる状態のずれは残る。
「解錠できない」だけでは、同じ場面へ戻れない
「解錠ボタンが動かない」という一文には、少なくとも次の違いが隠れている。
- ボタンを押せないのか、押したあと失敗するのか
- 会員、1日券、無料招待券のどれを使ったのか
- 画面だけが失敗したのか、物理的な鍵も閉じたままなのか
- 利用開始前の状態へ戻ったのか、料金が始まったのか
この違いがないままAIへ渡すと、コードで見つけやすい異常が「原因」に見える。先にコードを読むことが悪いのではない。コードで説明を作る前に、利用者が見た事実を固定する順番が必要になる。
GitHub DocsのIssue管理例は、バグ報告に、正確な再現手順、期待した結果と実際の結果、OSやアプリ版などの環境、画面やログといった追加情報を含める形を示している。Copilotへ任せるタスクについても、解く問題と完了条件が明確で、範囲が絞られているほど良い結果につながると説明している。
最初の原因候補を捨てなくていい
タイムアウトの記録は無駄ではない。ただし、事実と推測を同じ欄へ入れない。
事実: 1日券で利用開始表示のあとも後輪ロックが開かず、券は利用中になった
推測: 解錠APIの応答遅延、または1日券を未使用から利用中へ変える処理に原因があるかもしれない この二つを分けると、「タイムアウト説を否定されたら何も残らない」という怖さが小さくなる。推測はAIに調べてもらえる。事実は、どの推測を選んでも直すべき基準として残る🔍
再現手順は、3行から始める
長い障害報告を最初から完成させる必要はない。現場で待っている人がいるなら、まず三つの欄を一行ずつ埋める。
1行目: 始める前の条件
最初の行には、同じ状態を用意するために必要な条件を書く。
開始条件: iOS版2.8.1で、受付発行の未使用1日券を登録し、ポート17の車体を選ぶ 日時、OS、アプリ版、アカウントや契約の種類、対象データなどから、結果が変わるものだけを残す。端末名や担当者名を全部書くことが目的ではない。
今回、会員アカウントでは再現せず、受付発行の1日券では二回続けて再現した。この時点で、通信全体の遅さだけを直す依頼から、券種による処理の違いを調べる依頼へ範囲を絞れた。
2行目: 操作と、実際に起きた結果
次に、利用者が行った操作を順番にし、その直後に見えた結果を書く。
操作と実際: 車体QRを読む→「解錠」を押す→利用開始と表示されるが鍵は閉じたまま、1日券は利用中になる ボタン名、入力した値、画面遷移、物理的な結果を、起きた順に並べる。原因らしいログをここへ混ぜない。ログはあとで、この行を説明する証拠として添える。
Chrome DevToolsのRecorderには、ブラウザ上の操作を記録し、再生や共有をする機能がある。Webの不具合なら、手で書いた操作を記録へ置き換えることもできる。ただし、録画やログに氏名、メールアドレス、認証情報が入る場合は、そのままAIへ渡さない。値を伏せるか、再現用データへ置き換える。
3行目: 期待する結果と、失敗時に守るもの
最後に、直った時に利用者が受け取る結果を書く。
期待: 鍵が一度だけ開いて利用が始まり、開かなければ券を未使用へ戻して再操作できる 「エラーを出さない」では、画面だけ成功に見せる修正でも達成できる。今回必要なのは、物理的な鍵が開くこと、利用開始が一度だけ記録されること、失敗した券を使い切った扱いにしないことだ。
完了条件は、コードの処理ではなく、利用者が受け取る結果と失敗後に守る状態で書く。 これで、AIが提案した再試行を入れてよいかも判断できる。
三行に添える証拠は、一つずつ選ぶ
三行を書いたあとに、同じ結果を確かめる証拠を足す。最初からログを全部貼るのではなく、各行を補えるものを一つずつ選ぶ。
先に三行があれば、証拠を集める目的も見失いにくい。
開始条件の証拠: アプリ版と券の種類が分かる設定画面
操作と実際の証拠: 解錠直前から失敗表示までの操作記録、該当するリクエストID
期待の根拠: 1日券の利用手順、または運営担当者の確認 画面記録がなくても、発生時刻とリクエストIDがあれば、対象の通信を絞れることがある。反対に、長いログがあっても、どの操作に対応するか分からなければ、AIは目立つ警告から推測するしかない。
証拠を集める時は、利用者の氏名、メールアドレス、決済情報、認証用の値を除く。必要なのは本人の情報ではなく、同じ条件と結果へ戻る手掛かりだ。伏せた値が調査に必要だと分かった時は、本人の値を戻すのではなく、同じ条件の再現用データを作る。
集め始めると、すべてそろうまで報告できない気持ちにもなる。しかし、三行のどこが未確認かを書けば、途中でも渡せる。
未確認: Android版と、別のポートでも起きるかは未確認 確認済みと未確認を分けることで、知らない範囲を隠すための即答や、調べ終わるまでの沈黙を減らせる。
3行をAIへ渡し、修正範囲を絞る
エンジニアは、三行と伏せ字にしたリクエストIDをAIへ渡した。さらに、会員では再現せず、1日券で再現すること、関連しそうなファイルを調べ、コードを変える前に原因候補と確認方法を出すことを頼んだ。
実際の依頼は、次の形にした。
以下の不具合を調べてください。
開始条件: iOS版2.8.1、受付発行の未使用1日券、ポート17
操作と実際: QRを読む→解錠を押す→利用開始と出るが鍵は閉じたまま、券は利用中
期待: 鍵が一度だけ開き、失敗時は券を未使用へ戻す
会員では再現していません。まず関連する処理と原因候補を挙げ、
修正前にこの結果を再現する確認方法を示してください。
無関係な整理は行わず、コード変更前に一度報告してください。 「直して」だけでなく、最初に調査と再現を区切った。AIが勝手にコードを変えるからではない。原因候補と確認方法を見た時点で、現場の三行とつながっているかを人が判断できるようにするためだ。
まず再現し、修正前に失敗することを見る
AIは、1日券の発行経路だけ、外部の鍵サービスへ渡す利用者IDが空になる可能性を見つけた。サービス側は解錠を受け付けず、アプリ側は利用開始の保存だけを先に終えていた。通信時間の長いログは、失敗後の問い合わせに時間がかかっていた記録だった。
ここで、すぐ修正へ進めない。受付発行の1日券を使った時に、鍵サービスへの値が欠け、利用状態だけが進むテストを作る。修正前にそのテストが失敗し、現場の三行と同じ結果になることを見る。
GitHub Docsのバグ修正用エージェント例でも、可能なら問題を再現し、原因へ絞った小さな修正を行い、再発防止のテストを追加して十分に確認する流れが示されている。
再現できない時は、無理に成功したことにしない。発生した端末と時刻、確認できた操作、別の条件では起きなかったことを残し、次に集める情報を決める。たとえば「同じ1日券でもポート17以外では起きないか」「失敗時の鍵サービスの応答を一時的に記録できるか」を選ぶ。
本番でしか起きない問題へ、調査のためだけに危険な変更を入れる必要はない。影響が大きい場合は、AIへの修正依頼を止め、利用を一時停止する、代替手段を案内する、権限を持つ担当者へ引き継ぐ判断を先にする。再現できないという報告も、確認した条件が書かれていれば次の判断材料になる。
直す範囲と、今回は直さない範囲を伝える
原因が見つかると、周辺の整理も一緒にしたくなる。AIも、状態管理の共通化やエラー処理の全面整理を提案することがある。
しかし、利用者が待っている場面では、まず三行の問題を閉じる。
今回直す: 1日券でも必要なIDを渡し、解錠成功後だけ利用中にする
今回直さない: 券種全体の状態管理の共通化、画面文言の全面見直し
確認: 会員と1日券の解錠、失敗時の券状態、二重開始がないこと これは改善を諦めるための線引きではない。別の変更が混ざって、現場の問題が本当に直ったか分からなくなるのを防ぐ線引きだ。広い改善はIssueへ分け、今回の修正とは別に判断する。
AIへ渡す情報が具体的になるほど、修正を大きくする必要はなくなる。 原因を人が先に当てるのではなく、AIが調べたあとも同じ結果を確かめられる手掛かりを人が渡す。
早く答えるより、確認できる状態を返す
修正とテストが終わるまで、現場には15分ほどかかった。エンジニアは「直りました」だけでなく、次のように伝えた。
受付発行の1日券で、利用開始表示のあとも鍵が閉じたままになる問題を再現しました。券種ごとの値の渡し方を修正し、1日券と会員の両方で解錠できること、失敗時は券が未使用へ戻ることを確認しました。
待っていた利用者の自転車が開くと、スタッフの表情が緩んだ。最初の数分は、原因を即答できない自分を隠したくて、見つけたログへ飛びついていた。三行を書いたあとには、分からないことを抱えたままでも、次に何を確かめるかを説明できた🙂
速さは、最初の案をすぐコードにすることだけではない。間違った修正を戻し、別の問題を調べ直す時間を減らすことも速さに含まれる。
次に不具合をAIへ渡す時は、原因を言い切る前に次を埋める。
開始条件:
操作と実際:
期待: ログ、画面、コードは、その三行を説明するために後から足せる。情報が足りなければ、AIには修正ではなく、追加で観測する場所を提案してもらう。
AIの完了報告を3つの証拠で確認する方法では修正後の確認を、AIが書いたテストを利用者の結果へつなぐ方法ではテストの期待を扱っている。今回の三行は、その前に「何を直すのか」を失わないための入口になる。
AIに正解を急がせる前に、利用者が困った場面へ戻れる三行を残す。 それが、焦りを抱え込まず、小さく確かめられる修正へ進む最初の仕事になる。