GoogleスプレッドシートでAI返信案を確認する時、チェックボックスを1つ置くだけで運用を始められます。しかし、GASが表示文字列のTRUEを見て「確認済み」と判定すると、文字列・数式・別の入力規則が混ざった行まで通ることがあります。
この記事では、チェック欄を承認の証明ではなく、形式を検査する入口として扱います。GASで実値の型、数式の有無、標準チェックボックスの入力規則を読み取り、条件外なら送信処理へ渡さず保留へ戻します。
AI API、メール送信、CRM更新、チェック欄への書き込みは実装しません。架空の値とテスト用シートだけを対象にします。
この記事で作る検査
対象は、問い合わせレビュー台帳の1セルです。合格条件を次の3つに固定します。
-
getValue()の結果がbooleanである - 数式が入っていない
- 標準のチェックボックス入力規則である
結果は次のいずれかです。
| 結果 | 意味 | 後続処理 |
|---|---|---|
REVIEW_MARKED |
標準形式でtrue | 確認者・本文版を別記録と照合 |
REVIEW_UNMARKED |
標準形式でfalse | 人間レビューへ戻す |
HOLD_FORMULA |
数式がある | 数式の意図を確認 |
HOLD_RULE |
入力規則が標準でない | 入力規則の変更を確認 |
HOLD_VALUE_TYPE |
実値がbooleanでない | 転記・空欄・文字列を確認 |
REVIEW_MARKEDでも、送信可能・承認済み・確認者本人である、とは判定しません。
1. 表示文字列と実値を分ける
getDisplayValue()は画面に表示された文字列を返します。一方、getValue()はセルの実値を返します。JavaScriptでは、空でない文字列はBoolean()でtrueになるため、次の変換は危険です。
Boolean('TRUE'); // true
Boolean('FALSE'); // true
Boolean(''); // false
表示が同じでも、標準チェックボックスのboolean、手入力した文字列、数式の計算結果は意味が違います。まず値をbooleanへ変換せず、型を検査します。
2. 外部接続のない判定関数を作る
Apps ScriptのV8ランタイムで、次の関数を作ります。シートやAIへ接続せず、引数の契約だけを判定します。
function inspectReviewMark(value, formula, isStandardCheckbox) {
if (typeof formula !== 'string' ||
typeof isStandardCheckbox !== 'boolean') {
throw new Error('CHECKBOX_METADATA_INVALID');
}
if (formula !== '') return { status: 'HOLD_FORMULA' };
if (!isStandardCheckbox) return { status: 'HOLD_RULE' };
if (typeof value !== 'boolean') return { status: 'HOLD_VALUE_TYPE' };
// 形式だけを返す。承認・送信可否は返さない。
return {
status: value === true ? 'REVIEW_MARKED' : 'REVIEW_UNMARKED',
};
}
不正なメタデータはfalseへ丸めません。通信・権限・取得処理の異常と、未チェックを混ぜないためです。判定の優先順位は、数式、入力規則、実値の順にしています。
3. テスト用セルのメタデータを読む
本番台帳ではなく、テスト用スプレッドシートにReviewSandboxシートを作ります。B2へ標準のチェックボックスを挿入し、A2には架空のINQ-001を置きます。
function readReviewMarkCell(cell) {
if (cell.getNumRows() !== 1 || cell.getNumColumns() !== 1) {
throw new Error('ONE_CELL_REQUIRED');
}
// 同じ実行環境で標準規則を作り、引数も含めて比較する。
const standard = SpreadsheetApp.newDataValidation()
.requireCheckbox()
.build();
const rule = cell.getDataValidation();
const isStandardCheckbox = rule !== null &&
rule.getCriteriaType() === SpreadsheetApp.DataValidationCriteria.CHECKBOX &&
JSON.stringify(rule.getCriteriaValues()) ===
JSON.stringify(standard.getCriteriaValues());
return inspectReviewMark(
cell.getValue(), cell.getFormula(), isStandardCheckbox
);
}
requireCheckbox()に引数を渡すと、yes/noなどのカスタム値を作れます。今回はカスタム値を無条件にbooleanへ読み替えません。標準規則と違えばHOLD_RULEにし、運用仕様を決めてから別の契約として実装します。
なお、値・数式・入力規則の読み取りは複数の呼び出しです。同時編集を止めるトランザクションではありません。送信直前に、案件ID・本文の版・宛先を別の確認記録と照合してください。
4. 架空の入力で境界を固定する
Googleサービスを呼ばないテストを先に実行します。
function testReviewMark() {
const cases = [
[true, '', true, 'REVIEW_MARKED'],
[false, '', true, 'REVIEW_UNMARKED'],
['TRUE', '', true, 'HOLD_VALUE_TYPE'],
['FALSE', '', true, 'HOLD_VALUE_TYPE'],
['', '', true, 'HOLD_VALUE_TYPE'],
[1, '', true, 'HOLD_VALUE_TYPE'],
[true, '=TRUE()', true, 'HOLD_FORMULA'],
[true, '', false, 'HOLD_RULE'],
];
cases.forEach(([value, formula, rule, expected], index) => {
const actual = inspectReviewMark(value, formula, rule).status;
if (actual !== expected) {
throw new Error('TEST_FAILED_' + index);
}
});
console.log('PASS_' + cases.length);
}
最低限、次のケースを確認します。
- チェックを付ける・外す:
REVIEW_MARKED/REVIEW_UNMARKED - 文字列の
TRUE・FALSE・空欄・数値:HOLD_VALUE_TYPE -
=TRUE():HOLD_FORMULA - 入力規則を外す、またはカスタム値に変える:
HOLD_RULE - 複数セルを渡す:
ONE_CELL_REQUIRED - シート読み取り例外:例外を未チェックへ置き換えない
本番データや顧客本文をテスト値にコピーしないでください。
5. チェック印と承認記録を分ける
形式検査に合格しても、次の事実は分かりません。
- 誰がチェックを付けたか
- どの案件ID・本文版・宛先を見たか
- FAQや料金、納期が確認後に変わっていないか
- その人に送信権限があるか
そのため、レビュー台帳では少なくとも次の列を分けます。
inquiry_id, reply_version, review_mark, reviewer, reviewed_at,
evidence_version, approval_state, hold_reason
review_markがREVIEW_MARKEDになっても、approval_stateを自動でAPPROVEDにしません。確認者・本文版・根拠版を照合した人が、別途、送信判断を記録します。
運用チェックリスト
-
表示文字列ではなく
getValue()の型を検査している -
文字列
FALSEや空欄を未チェックへ自動変換していない - 数式・入力規則変更・読み取り例外の戻し先がある
- 標準チェックボックスとカスタム値の契約を分けている
- 形式合格を承認・送信権限の証明にしていない
- 案件ID・本文版・確認者をチェック印と別に記録している
- AIや転記処理がチェック欄を書き換えない経路を確認している
- テスト用シートで正常系と失敗系を再現している
まとめ
チェックボックスは便利ですが、表示されたTRUEだけでは、人が対象の返信案を確認したことを表せません。GASでは、実値・数式・入力規則を検査し、形式外の行を保留へ戻すところまでを自動化します。
その先の承認は、案件ID、本文の版、根拠、確認者、送信権限を照合する別の業務ルールです。Miraigentでは、AIの下書きを増やす前に、確認できない時に誰へ戻るか、どの記録を正本にするかを一つの業務で整理します。
