AI導入の検討では、「今回は見送る」という判断が出ます。
しかし、理由を会議のチャットや担当者の記憶だけに置くと、数か月後に同じ調査をやり直したり、条件が変わっていないのに再び試したりします。見送りは失敗ではなく、今は安全に始められない条件を記録した状態です。
この記事では、GoogleスプレッドシートとGoogle Apps Script(GAS)で、AI導入候補の見送り理由、再検討条件、確認期限を台帳化します。AIが導入可否を決める仕組みではありません。候補の整理と期限切れの通知だけを補助し、再検討・承認・開始は人が行います。
作るもの
ADOPTION_DECISIONS シートに、次の列を作ります。
decision_id,work_id,work_name,decision,reason_code,impact_level,
owner_role,reconsider_condition,reconsider_due_at,source_ref,status,
last_reviewed_at,next_action
decision は次の3値に固定します。
TRIAL # 条件付きで小さく試す
HOLD # 条件がそろうまで見送る
NOT_NOW # 現時点では対象外。再検討条件を残す
status は台帳の運用状態です。HOLD や NOT_NOW の案件を、期限到来だけで TRIAL へ変えてはいけません。
OPEN -> DUE_FOR_REVIEW -> HUMAN_REVIEW -> RECONSIDERED
| |
+----> ARCHIVED +----> HOLD / NOT_NOW / TRIAL
見送り理由をコードにする
自由記述だけでは、後から似た案件を集計できません。まず、理由を少数のコードへ寄せます。
| reason_code | 例 | 再検討時に見る条件 |
|---|---|---|
| MISSING_SOURCE | 参照するFAQや正本がない | 正本の版と責任者が決まったか |
| MISSING_REVIEWER | 人間確認の役割が空いている | 確認者と代理が決まったか |
| HIGH_IMPACT | 契約・料金・個人情報に影響する | 対象範囲を限定し、責任者が承認したか |
| MISSING_INPUT | フォームの必須情報が足りない | 不足項目を受付で取得できるか |
| NO_RECOVERY | 失敗時の手動手順がない | 手動の戻し先と停止条件があるか |
見送り理由はAIへ渡すプロンプトではなく、次の確認者が判断を再開するための記録です。顧客本文や個人情報を台帳へコピーせず、source_ref には権限管理された原本の参照先だけを保存します。
シートを準備する
1行目へ見出しを入力し、サンプルとして1件だけ追加します。
decision_id | work_id | work_name | decision | reason_code | impact_level | owner_role | reconsider_condition | reconsider_due_at | source_ref | status | last_reviewed_at | next_action
D-001 | W-014 | 問い合わせ返信 | HOLD | MISSING_SOURCE | medium | support_manager | FAQ v3と確認者を登録できたら再検討 | 2026-10-20T09:00:00+09:00 | drive://ai-review/D-001 | OPEN | | 正本の担当者を確認
日付はシートのタイムゾーンを Asia/Tokyo にそろえます。期限は「そろそろ見る」ではなく、確認担当者が行動できる日時として持たせます。
GASで入力値を検査する
まず、見送り記録の必須項目と状態遷移を検査します。期限切れを自動で再開させないことが重要です。
const SHEET_NAME = 'ADOPTION_DECISIONS';
const REQUIRED_HEADERS = [
'decision_id', 'work_id', 'work_name', 'decision', 'reason_code',
'impact_level', 'owner_role', 'reconsider_condition',
'reconsider_due_at', 'source_ref', 'status', 'last_reviewed_at',
'next_action'
];
function validateDecisionLedger() {
const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
if (!sheet) throw new Error(SHEET_NAME + ' sheet is missing');
const values = sheet.getDataRange().getValues();
const headers = values.shift().map(String);
const index = Object.fromEntries(headers.map((name, i) => [name, i]));
const missing = REQUIRED_HEADERS.filter((name) => index[name] === undefined);
if (missing.length) throw new Error('Missing headers: ' + missing.join(', '));
const errors = [];
values.forEach((row, offset) => {
if (row.every((cell) => cell === '')) return;
const line = offset + 2;
const decision = String(row[index.decision] || '');
const status = String(row[index.status] || '');
const dueAt = row[index.reconsider_due_at];
if (!['TRIAL', 'HOLD', 'NOT_NOW'].includes(decision)) {
errors.push('row ' + line + ': invalid decision');
}
if (!['OPEN', 'DUE_FOR_REVIEW', 'HUMAN_REVIEW', 'RECONSIDERED', 'ARCHIVED'].includes(status)) {
errors.push('row ' + line + ': invalid status');
}
if (decision !== 'TRIAL' && !String(row[index.reconsider_condition] || '').trim()) {
errors.push('row ' + line + ': reconsider_condition is required');
}
if (!dueAt || Number.isNaN(new Date(dueAt).getTime())) {
errors.push('row ' + line + ': reconsider_due_at is required');
}
});
if (errors.length) throw new Error(errors.join('\n'));
return {ok: true, rows: values.length};
}
期限到来をレビュー待ちへ戻す
期限を過ぎた案件を DUE_FOR_REVIEW へ移す処理です。これは再検討の通知であり、導入許可ではありません。
function markDueForReview() {
const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
const values = sheet.getDataRange().getValues();
const headers = values.shift().map(String);
const index = Object.fromEntries(headers.map((name, i) => [name, i]));
const now = new Date();
let count = 0;
values.forEach((row, offset) => {
const decision = String(row[index.decision] || '');
const status = String(row[index.status] || '');
const dueAt = new Date(row[index.reconsider_due_at]);
const shouldReview = ['HOLD', 'NOT_NOW'].includes(decision)
&& status === 'OPEN'
&& dueAt.getTime() <= now.getTime();
if (shouldReview) {
sheet.getRange(offset + 2, index.status + 1).setValue('DUE_FOR_REVIEW');
sheet.getRange(offset + 2, index.next_action + 1)
.setValue('条件を確認して人間レビューへ戻す');
count += 1;
}
});
return count;
}
時間主導トリガーを毎朝実行しても、DUE_FOR_REVIEW から先の状態は変更しません。メール通知を追加する場合も、本文へ顧客情報を含めず、decision_id と確認先だけを送ります。
人間レビューのチェックリスト
期限が来たら、次の順番で人が確認します。
- 見送り理由はまだ有効か
- 再検討条件は実際にそろったか
- 対象業務・入力情報・参照正本に変更はないか
- 通常・境界・停止の例を1件ずつ確認したか
- 人間確認者と代理担当が今も対応可能か
- 失敗時に手動へ戻す場所があるか
- 今回の判断理由と次回見直し日を記録したか
条件が足りない場合は HOLD または NOT_NOW のまま期限を更新します。条件がそろっても、いきなり本番範囲を広げず、TRIAL として対象件数を限定してください。契約、返金、料金、個人情報訂正、強い苦情などはこの台帳から自動承認しません。
まとめ
見送りの台帳に必要なのは、「なぜ止めたか」だけではありません。
- 見送り理由をコード化する
- 再検討条件を一文で残す
- 期限到来をレビュー待ちへ戻す
- 人間が条件を確認して次の状態を決める
- 判断理由と次回見直し日を記録する
この構成なら、GASは期限の検知と一覧化までを担当し、導入可否や業務影響の判断は人に残せます。AI導入を進めることだけでなく、今は進めない理由を次の担当者へ渡すことも、運用を続けるための記憶になります。
