Todoアプリの改修を運営者向け画面からAIに頼めるか 確認質問と要件確定編
「Todoに優先度を付けたい。見やすくして」のような曖昧な依頼を、確認なしで実装へ渡さないための画面を作りました。質問への回答、要件の手動編集、人間による確定を記録し、未回答や未確定ならサーバー側で変更ジョブを止められるかを検証します。
最終目標は、チャットから下書きの変更提案まで
このシリーズでは、Gitやターミナルを操作しないTodoアプリの運用担当者が、専用Web画面のチャットだけで改修を依頼できる仕組みを段階的に作っています。 最終目標は、利用者がAIからの質問に答え、整理された要件を自分で編集して確定すると、隔離環境でコード変更とテストが実行され、合格した変更だけがGitHubのDraft PR(正式なレビューを依頼する前の下書き)になることです。 最後に10種類の改修を試し、既存のコーディングエージェントへ人間が手作業で依頼する方法と比べます。
自然文で改修を依頼
↓
不足事項への質問と回答 ← 第2回
↓
整理された要件の編集と確定 ← 第2回
↓
隔離環境でコード変更とテスト ← 第3回以降
↓
合格した変更だけ下書きの変更提案を作成 ← 第5回
↓
10種類の改修で手動依頼と比較 ← 第6回
第1回では、この流れの後半に必要な土台を先に試しました。 3社のAI APIを共通形式で呼び、生成されたコード変更案を隔離環境でテストしたところ、9件中3件が失敗して処理が停止しました。 GitHub上のコードと本番データには書き込まず、失敗した変更を外へ出す前に止められることまで確認しています。
しかし、第1回の画面には、「優先度は3段階」「既存Todoは中」「一覧で絞り込めるようにする」という事項が最初から表示されていました。 画面の利用者が決めたように見えますが、実験用の固定値です。
では、利用者はいつ質問を受け、どこで回答し、何を見て確定したのでしょうか。
答えは、まだ画面の中にありませんでした。 AIプロバイダを3社へ切り替えられても、確定までの操作が省略されていれば、非エンジニアが使える変更画面とは呼べません。
そこで、自然文の依頼とコード変更の間に、変更依頼記録(Change Request)を置きました。 変更依頼記録は、1件の改修について、会話、未回答の質問、整理された要件、人間の確認状態をまとめて保存します。 ここでいう整理された要件とは、会話文から変更の概要、現在の状態、変更後の状態、受入条件(何ができれば改修完了とみなすか)、テスト計画を分けたものです。 確定した要件を後段のコード変更処理へ渡す単位を、この記事では変更ジョブと呼びます。
「見やすくして」に残っていた四つの曖昧さ
画面に入れたのは、第1回と同じ依頼文です。
Todoに優先度を付けたい。見やすくして。
検証ログでは、この依頼を「シナリオS01」と呼びます。 S01は「Scenario 01」を略した管理用IDで、難易度や実行順を表す数字ではありません。
「優先度を付ける」は変更対象を示していますが、「見やすくする」の具体的な挙動は決まっていません。 変更依頼画面は、次の4件を未回答事項として返しました。
- 優先度は何段階にし、どの値を使うか
- 既存Todoの初期値を何にするか
- 一覧で優先度をどう見分けるか
- 既存の状態絞り込みとどう組み合わせるか

右側の整理された要件は、まだ変更後の状態、受入条件、テスト計画が空です。 画面は「回答待ち」を表示し、「この内容で確定」と「変更ジョブを開始」のボタンを無効にしています。
ここで、画面を介さずに変更ジョブ作成APIも直接呼びました。 画面のボタンが無効でも、APIへ直接リクエストを送れば回避できる実装では困るからです。
サーバーは、未回答質問を表すopenQuestionsが4件あることを再検査し、ジョブIDを発行しませんでした。
コード変更案を作るAIの呼び出し回数も0のままです。
回答のあとに残った「未確定」
質問には、次のように回答しました。
| 確認事項 | 人間の回答 |
|---|---|
| 優先度の値 | low、medium、highの3段階 |
| 既存Todoの初期値 | medium |
| 一覧での表示 | 色と文字を併用したバッジ |
| 絞り込み | 既存のstatusと同時に指定できる |
statusは、Todoが未完了か完了済みかを表す既存APIの項目名です。
固定の変換処理は、回答を共通データ形式change-request-v1へ反映し、変更後の状態、受入条件、テスト計画を作りました。
会話の文章だけを履歴へ残すのではなく、後段の処理が項目ごとに検査できる配列へ分けています。
{
"openQuestions": [],
"confirmedByHuman": false,
"acceptanceCriteria": [
"既存Todoはmediumとして表示される",
"許可していない優先度はAPIが400を返す",
"一覧は色と文字を併用したバッジで優先度を表示する",
"優先度の絞り込みはstatusと同時に指定できる"
],
"testPlan": [
"既存Todoをmediumへ移行するテスト",
"許可していない優先度を拒否するAPIテスト",
"画面からAPIまで通す優先度の表示と絞り込みテスト"
]
}
未回答事項は0件になりました。
しかし、confirmedByHumanはまだfalseです。
回答を受け取ったことと、実装へ進めてよいことは別の状態です。
「色と文字を使う」だけでは判別条件が曖昧だった
生成された受入条件には、「色と文字を併用したバッジで優先度を表示する」とありました。 しかし、これだけでは、色を見分けにくい利用者が文字だけで判別できるかは明確ではありません。 そこで、「優先度は色に頼らず文字でも判別できる」を画面から追記しました。

この画面で人間が編集できるのは、変更の要約、期待状態、受入条件、テスト計画です。
編集内容を保存すると、以前に確認済みだったとしても確認状態をfalseへ戻します。
内容が変わったのに過去の承認だけが残る状態を避けるためです。
実際、4件の回答を反映したあとに変更ジョブ作成APIをもう一度呼びましたが、サーバーは「人間による変更要件の確認が完了していません」として停止しました。 未回答時と合わせて、サーバー側の開始条件が処理を止めた回数は2回になりました。
無効なボタンだけでは変更ジョブを止められない
「この内容で確定」を押すと、サーバーは次の条件を検査します。
- 必須項目がそろっている
openQuestionsが0件である- 受入条件とテスト計画が空ではない
- 人間が現在の内容を確認している
すべて満たしたあとに「変更ジョブを開始」を押すと、ジョブIDを1件発行しました。

第2回の変更ジョブは、queued_for_next_phase(次の工程待ち)で止まります。
コード変更案を作るAIの呼び出しは0回で、生成案を隔離環境へ適用してテストする実行器(runner)も起動していません。
ここで確認できたのは、確定済み要件だけを後段へ渡せることです。
ボタンの無効化は操作ミスを減らしますが、安全境界にはなりません。 変更ジョブ作成APIが確認状態を再検査し、拒否理由を操作履歴(audit trail)へ残すことで、画面以外の呼び出しにも同じ条件を適用できます。
「締切を入れたい」と「Todoをもっと便利にして」は同じように扱えるか
優先度追加だけで止まる画面なら、別の改修依頼には使えません。 期限日追加と要件不足も、同じ開始条件と停止条件へ通しました。 検証ログでは、優先度追加をS01、期限日追加をS02、要件不足をS06と記録しています。 番号がS02からS06へ飛ぶのは、全10件の検証計画から今回使う3件だけを抜き出したためです。 S03からS05は、タグ追加やCSV出力など後続回で扱う予定の依頼で、今回は実行していません。
| 改修依頼(管理用ID) | 最初の質問 | 未回答時 | 未確定時 | 確定後の変更ジョブ | コード変更AI |
|---|---|---|---|---|---|
| 優先度追加(S01) | 4件 | 停止 | 停止 | 1件 | 0回 |
| 期限日追加(S02) | 3件 | 停止 | 停止 | 1件 | 0回 |
| 要件不足(S06) | 2件 | 停止 | 未到達 | 0件 | 0回 |
期限日追加では、日付だけか時刻まで扱うか、判定に使うタイムゾーン、完了済みTodoの扱いを質問しました。 人間の回答は「日付のみ」「Asia/Tokyo」「完了済みは期限切れから除外する」です。 この3点を受入条件へ残したあとに確定し、ジョブIDを発行できました。
一方、要件不足の入力は「Todoをもっと便利にして」です。 誰がどの操作で困っているか、何ができれば完了かを質問し、回答しないまま変更ジョブ作成APIを呼びました。
結果は0件です。 優先度、期限、タグのどれかを固定の変換処理が選ぶこともありませんでした。
同じ停止結果をもう一度出せるか
npm run verify:change-requestsは、この記事用に用意した検証スクリプトです。
3件の固定した依頼と回答を変更依頼の管理処理へ入力し、未回答時と未確定時の変更ジョブ拒否、確定後のジョブ発行数、コード変更AIと実行器の未実行を検査します。
npm run verify:change-requests
S01: queued, jobs=1, providerCalls=0
S02: queued, jobs=1, providerCalls=0
S06: needs_clarification, jobs=0, providerCalls=0
queuedは次の工程待ち、needs_clarificationは質問への回答待ちを表します。
providerCalls=0は、コード変更AIを呼んでいないことを表します。
会話と変更依頼記録はサーバー側のJSONファイルへ保存するため、画面を再読み込みしても質問、回答、手動編集、停止履歴が残ります。 ただし、この保存方式はローカル実証用です。 複数利用者が同じ依頼を同時に更新する環境では、データベースと、古い内容による上書きを防ぐバージョン検査が必要になります。
あらかじめ用意した質問ではAIの質問品質を評価できない
第1回では、さくらのAI Engine、Cloudflare Workers AI、Google Gemini APIの実API応答を共通の要件形式requirement-plan-v1へ変換できることを確認しました。
今回は外部APIを呼ばず、3件の依頼に対する質問をあらかじめ用意した変換処理を使っています。
実装上の名前はdeterministic-scenario-adapterです。
この分離には理由があります。 質問内容が実行ごとに変わる状態では、変更ジョブの開始条件に不具合があるのか、質問が足りないのかを切り分けにくいからです。 入力と質問を固定すると、「未回答」「回答済みだが未確定」「確定済み」の各状態を同じ条件で再実行できます。
ただし、「あらかじめ用意した質問で止められた」は「実AIが必要な質問を作れる」を意味しません。 自由な改修依頼から質問を作る品質、回答を受けた再質問、矛盾する回答の扱いは未検証です。
変更ジョブの先には、まだコード変更がない
優先度追加と期限日追加では、未回答時と未確定時に変更ジョブの作成を拒否し、人間が要件を編集、確定したあとにだけジョブIDを発行できました。 要件不足の依頼は改善機能を勝手に選ばず、質問を残して止まっています。
したがって、第2回の判断も**Conditional Go(条件付きで継続)**です。 会話から確定要件までの管理とサーバー側の開始条件は機能しましたが、外部AI APIによる質問品質と、発行した変更ジョブから実際のコード変更を完了できるかは確認できていません。
第1回で失敗した3件のテストを、確定済みの変更依頼から起動した実行器が修復できるか。 専用画面が本当にコード変更の完了まで届くかどうかは、そこで決まります。