AIエージェント(Claude Code / Gemini 等)による実装で発生したエラー・不整合と、その根本原因・対策をまとめたページです。同じ失敗を繰り返さないためのナレッジベースとして活用してください。

分類

カテゴリ説明
計算ロジックフィルタ選択ミス、ゼロ除算、符号反転等
データ不整合DDLコード値 vs 実データの乖離、列ずれ等
スコープ・変数変数の参照スコープ外、未定義関数
テスト回帰新機能追加後にテストが壊れる
Git 運用コンフリクト解消ミス、並行開発の干渉
ドキュメント_config.json 未登録、ステータス更新漏れ
仕様書記述既存コード未確認で書いた仕様書に固有名詞・構造の誤り
数式設計GAS + Sheets 数式の組合せ・データ型自動変換・Unicode 等の落とし穴

全パターン一覧

#日付カテゴリ失敗内容関連案件根本原因対策
104-15計算ロジックfilterWithRecalcTotal で非加算指標の Total が壊れたMAS-024仕様書にフィルタ選択基準がなかった出力行ごとに「加算可能か」を明記。非加算指標は filterValues + Total独自計算
204-15計算ロジック売上ゼロ月で BEP が固定費と同額になったMAS-024ゼロ除算時のフォールバック(varRate=0)が誤りエッジケーステーブルで異常系の表示値を事前定義
304-15データ不整合固変区分の判定が FV_VAR で不一致MAS-024DDL定義のコード値と実データの日本語表記が異なっていた実行前タスクに「MCP で実データを確認」を追加
404-15スコープ・変数planCtx is not definedMAS-001計画パイプラインの if ブロック外に配置した変数のスコープを仕様書に明記
504-15Git 運用.claspignore の否定パターンで worktree が混入MAS-096.claude/ ディレクトリが除外対象に含まれていなかったclasp status で Tracked ファイルを検証
604-15Git 運用コンフリクト解消で追加日時列が消失MAS-001git checkout --theirs で古い版を採用したコンフリクト解消後に列構造の差分を確認
704-16スコープ・変数MAS-192 ファイル分割後に旧ヘルパー関数が未定義MAS-192分割時に旧ファイルを削除したが旧関数呼び出しが残存互換レイヤーを追加。分割時は grep で旧関数の参照を全件確認
804-16テスト回帰テスト T4-03 で BEP セクションが未登録科目として検出MAS-024新セクションの行ラベルがテストの SKIP_PATTERNS に未登録新セクション追加時はテストの SKIP_PATTERNS も同時更新
904-16テスト回帰テスト T4-21 で YoY 差異列追加による最終月列のずれMAS-020テストが headers.length - 1 で最終月を固定参照△列や空白列をスキップして実データ列を特定する
1004-16Git 運用TODO_future.md のサマリー・完了一覧が消失複数ワークスペースでの並行開発でコンフリクト解消時に上書きファイルの担当を分ける。TODO_future.md は片方だけが触る
1104-16ドキュメント_config.json に新規仕様書が未登録MAS-073 等仕様書作成時に _config.json への登録を忘れた汎用プロンプトの Phase 3 に登録ステップを必須化
1204-16データ不整合銀行CSV消込が実行されないMAS-145マッチ決済ID の形式が stlRowMap のキーと不一致の可能性消込実行前にID形式を検証するガードを追加

教訓サマリー

仕様書で防げたもの(#1, #2, #3, #4)

  • エッジケーステーブル: ゼロ除算、比率異常値、マスタ未設定のフォールバックを事前定義
  • フィルタ選択基準: 加算可能/非加算の区別を明記
  • 実データ検証: MCP で実データとDDLコードの乖離を事前チェック
  • 変数スコープ: if ブロック内/外の配置を明記

マッチングロジックで防げたもの(#13-#17)

#日付カテゴリ失敗内容関連案件根本原因対策
1304-16計算ロジック合算マッチが単一候補提案(Pass 3)に先取りされたMAS-162Pass 3 を Pass 2 より先に実行していた金額完全一致の合算を単一候補提案より先に実行(Pass 2 → Pass 3 の順)
1404-16計算ロジックSTL合計で合算を試みたが候補が多すぎて不一致MAS-162異なる取引先のSTLも含めて合計していた同一取引先でグルーピングしてから部分集合を探索
1504-16計算ロジック同一取引先4件中3件の合算が検出されないMAS-162全件合計のみ照合し部分集合を試行しなかった貪欲法(日付昇順に加算)+ 同一金額N件の2方式を追加
1604-16計算ロジック合算マッチで同じSTLが次の行でも再利用されたMAS-162合算成功時に candidates[ci].matched=true を設定していなかった合算マッチ成功時にSTLをロック(matched=true)
1704-16計算ロジックDate オブジェクトの文字列ソートで日付順が壊れたMAS-162String(dueDate) がタイムゾーン付き長文字列になったUtils.parseDateToYm() で YYYY-MM 形式に統一してからソート

テスト設計で防げたもの(#8, #9)

  • 新機能追加時は テストの固定値参照を見直す(列数、行ラベル等)
  • SKIP_PATTERNS や列位置の取得は 動的に 行う

Git 運用で防げたもの(#5, #6, #10)

  • 並行開発時は ファイルの担当を分ける
  • コンフリクト解消後は 差分の全体像を確認してからコミット
  • git checkout --theirs は安易に使わない

プロセスで防げたもの(#7, #11, #12)

  • ファイル分割時は grep で旧関数名の全参照を確認
  • 新規 .md 作成時は _config.json への登録を必須チェック
  • ID マッチング時は キーの形式(STL_ vs INV_)を検証

数式設計で防げたもの(#21-#24)

#日付カテゴリ失敗内容関連案件根本原因対策
2104-17数式設計数式構築時に sheet.getLastColumn() で最終列を取得したが、MAS-020 の YoY 差異列(O-Z)まで含まれて列範囲が想定外に膨張MAS-003 Step 2getLastColumn() は「値または書式が入っている最右列」を返す仕様。YoY 差異列が空でも書式があれば返される月列は C-N の 12 列固定にハードコード。動的取得する場合は「値の有無」まで検証(空セルは除外)
2204-17数式設計String.trim() で先頭のラベル装飾を除去したつもりが、全角スペース U+3000 が残って MATCH が失敗MAS-003 Step 2JavaScript の trim() は ASCII 空白(\s)のみ対象で、全角スペース U+3000 を除去しないラベル正規化では .replace(/[\s\u3000]+/g, '') で全角スペース明示除去。または正規化関数を Utils に集約
2304-17数式設計sheet.getRange('B2').setValue("2026-03") で YYYY-MM 形式の年月を書き込んだら、Sheets が「2026 引く 3 = 2023」の負数として自動パースMAS-003 Step 2Sheets は文字列を見て自動的に数式/日付/数値として解釈する。マイナス記号を減算演算子と誤認文字列強制は apostrophe 前置で setValue("'2026-03")、または setNumberFormat('@') でセル書式をテキストに固定してから書き込む
2404-17数式設計MATCH("✨ 売上総利益", ARRAYFORMULA(SUBSTITUTE(...))) でラベル検索する数式を組んだが、絵文字・改行・全角スペースの組合せで MATCH が壊れるMAS-003 Step 2数式側でのラベル正規化は脆弱: ARRAYFORMULA が大規模範囲に展開される、SUBSTITUTE で除去する文字を事前列挙しなければならない、Sheets の Unicode 正規化挙動が不透明数式側でラベル検索をせず、GAS 側で行番号を事前特定してリテラル埋め込み (INDEX('61_pl_monthly'!$C:$N, 9, 8))。findRowInColA_() 等のヘルパーで A 列スキャン + 正規化を JS 側で実施

共通の根本原因と対策

#21-#24 は全て MAS-003 Step 2 の KPI ダッシュボード数式実装時に、「Sheets の数式機能でラベル解決しようとした」 設計方針の脆弱性が連鎖的に顕在化したもの。

対策(MAS-003 Step 2 で実装に反映済み):

  • ラベル解決は GAS 側で完結: A 列スキャンで行番号を取得 → INDEX('sheet'!$C:$N, row, col) 形式のリテラル埋め込み数式を生成
  • 動的列範囲取得の禁止: 月列は C-N の 12 列固定。YoY 差異列 O-Z との混同を避ける
  • 文字列セル書き込み: 日付・年月風の文字列は apostrophe 前置 or setNumberFormat('@')
  • 文字列正規化の Unicode 対応: .replace(/[\s\u3000]+/g, '') パターンを徹底
  • ARRAYFORMULA + MATCH + SUBSTITUTE の組合せは原則禁止: GAS 側で計算してから埋め込む方式に統一

仕様書記述で防げたもの(#18-#20)

#日付カテゴリ失敗内容関連案件根本原因対策
1804-17仕様書記述仕様書が SHEET_DEFAULTS へ3要素配列を追加するよう指示したが、実際の型は { pattern, prefix, defaults } オブジェクト配列でシートキー登録用ではなかったMAS-003 Step 1名前「SHEET_DEFAULTS」から用途を推測し、Grep の部分ヒットだけで判断した。Read で構造を確認しなかった仕様書で既存データ構造に言及する際は必ず Read で型と要素形を確認してから記述
1904-17仕様書記述仕様書が「03_sys_params にシートキーが登録される」と記述したが、実際の登録先は 01_sys_configConstants.CONFIG_SHEETMAS-003 Step 1シート名を記憶で書いた。Utils.getSheetNameByKeyconfSheet.appendRow の参照先を Read しなかったシート名・定数名は Read で Constants.CONFIG_SHEET 等を参照先ごと追跡してから記述
2004-17仕様書記述仕様書が動作確認で「🔧 システム初期化 → MST_CONF_SHEETS 初期化」と記述したが、そのメニューは存在しない(実在は「🔧 開発・設定 → 全シートのスキーマとUIを最新化(DDL)」)MAS-003 Step 1メニュー名を造語した。onOpen()ui.createMenu を Read しなかった動作確認手順に固有名詞(メニュー・関数・シート名)を書く前に、該当コードを Read して実在する文字列だけ引用

共通の根本原因と対策

#18-#20 は全て同日の MAS-003 仕様書作成時に、1 回の「コード未読 → 名前から類推」で 3 件まとめて埋め込まれた

対策(汎用プロンプトの Phase 1-D に反映済み):

  • Grep は「どこにあるか」の発見まで。「どう書くか」の判断は必ず Read で行う
  • 仕様書に書く以下の要素は、全て Read で裏取り済みのものに限定:
    • データ構造の型・フィールド名
    • 変数名・関数名・シート名・メニュー名・定数名
    • 行番号・呼び出し経路
  • 「この定数は〜用だろう」「このシートは〜だろう」と推測した瞬間に手を止めて Read

並列実装の対称性漏れ(#25)

#日付カテゴリ失敗内容関連案件根本原因対策
2504-20並列実装銀行・クレカの類似2処理(501_cc_importer.js / 502_bank_importer.js)の片側だけに設定が漏れ、CC UNMATCHED 時の 確認FLG=FALSE セットが明示されていない状態だった。銀行側は明示的に FALSE セットしていたが、CC 側は暗黙のデフォルト値(空欄)に依存していたMAS-159 実装時(PR #221)に検出、同 PR で drive-by fixbank / cc のような並列実装を片方だけ見て編集し、もう一方の対称性チェックを怠った。書き込み系の分岐が「明示」と「暗黙デフォルト」で非対称になっていることを発見できなかった並列実装の編集時は必ず両方のコードを並べて対称性チェック。書き込み系は全分岐で明示的に値を set する(暗黙の初期値・空欄に頼らない)。Grep で setValue / appendRow 等の書込みポイントを bank / cc 両側で洗い出し、同じ列に対する書込みパターンが対称か確認

GAS マニフェスト・外部 API 仕様変動(#26-#30)

#日付カテゴリ失敗内容関連案件根本原因対策
2604-20GAS マニフェスト設定の見落としmas/appsscript.jsonoauthScopes を部分宣言したことで、GAS のスコープ自動検出が完全オフになり、既存機能(SpreadsheetApp / DriveApp / MailApp / Utils.auditLog 等)が一斉に "Specified permissions are not sufficient" で動作不能にMAS-206 実装時(PR #245)に検出、fix コミット 023e773 で oauthScopes を削除して復旧GAS の oauthScopes は「明示宣言 = 自動検出完全オフ」という排他仕様。部分宣言すると自動検出されていた spreadsheets / drive / mail / ui 等が全て消失する。Admin SDK 等の Advanced Service 用スコープを「1 個足す」つもりで oauthScopes フィールド自体を追加してしまったのが原因Advanced Service で済むスコープは enabledAdvancedServices 側に宣言(GAS が自動付与)。どうしても oauthScopes に手動宣言が必要な場合は、既存コードで使用中の全スコープを GAS エディタ「プロジェクト設定 → OAuth スコープ」から抽出し、完全列挙した上で新規スコープを追加する。dev で主要機能(サイドバー / バックアップ / RPA)の一通り動作確認してから prod push
2704-20外部 API 仕様変動への過度な依存AdminReports.Activities.list(..., { eventName: 'acl_change' }) でエラー "Event acl_change not found in manifest"。acl_change は旧仕様の名称で、現行では change_user_access / change_document_access_scope 等の粒度別名に分化していたMAS-206 実装時(PR #245)に検出、fix コミット 439dcde で eventName フィルタ削除し post-processing 方式に変更Google Admin SDK 等、Google 社が更新する API のイベント名・フィールド名は時期で変わる。古いブログやチュートリアルに載っている名前がそのまま通用する保証はなく、eventName のようなサーバー側フィルタに依存すると API 仕様変更のたびに壊れる現行の公式ドキュメントで必ず確認(2025 年以前の記事は信用しない)。可能な場合は名前指定を避け、API に広めに問い合わせて post-processing(自前のフィルタリング)で絞る方式が堅牢。例: eventName 無指定で全 Drive アクティビティを取得 → target_user / target_domain パラメータを持つイベントのみ抽出。エラーメッセージ "not found in manifest" 等は名前変更サインとして認識。仕様書に API 名を明記する際は**「YYYY-MM 時点」のタイムスタンプを併記**
2804-27GAS 末尾 _ 関数の private 扱いMAS-232 Stage 2 で SPA サイドバーが「google.script.run.getInitialStateForSpa_ is not a function」で起動不能。GAS 仕様で関数名末尾の _ は private 扱いとなり、google.script.run / doGet / doPost 等のクライアント呼び出しから到達できない。同名で末尾 _ なし関数も存在しないため undefined 扱いとなったMAS-232 Stage 2 dev 投入時に検出(main 側 PR #372 / commit da1e549getInitialStateForSpa_getInitialStateForSpa にリネームして復旧)。仕様書 dev_mas-232_sidebar_spa.md v1.1 で UI 層分離設計時に末尾 _ を付けて記述したまま実装に流れたGAS の命名規約(末尾 _ = private)と SPA 設計の「google.script.run 経由でクライアントから呼び出される public エンドポイント」が衝突。private helper(_setSpaView_ / _consumeSpaView_ 等)と public エンドポイント(getInitialStateForSpa 等)の命名規約を spec 起草時に区別できていなかったクライアント呼び出しを伴う GAS 関数は末尾 _ を付けないを規約化。具体的には: ①google.script.run.foo() から呼ばれる関数 / ②doGet(e) / doPost(e) / ③onOpen(e) / onEdit(e) 等のトリガー / ④MENU_DEFINITION.funcName で参照される関数 — これらは全て末尾 _ 禁止。逆に完全な private helper(同一ファイル内からのみ呼ばれる内部関数)には末尾 _ を付ける_setSpaView_ / _consumeSpaView_ / _calcInternal_ 等)。仕様書起草時は関数を「クライアント到達 / GAS 内部のみ」の 2 区分で明示し、命名を分ける。追加チェック: spec 内の関数名 grep で末尾 _ 関数のうち google.script.run 文脈で参照されているものがないかを Read で確認
2904-27google.script.run V8→Java シリアライズの silent nullMAS-057 Phase 3 SPA で getInitialBootstrapData() 等が withSuccessHandlernull を返す。withFailureHandler は呼ばれず・throw もなく・GAS エディタ直接実行では JSON.stringify も成功するため検知困難。HAR で op.exec[0, null, "<Java HashMap.toString>"] — 第二要素が null・第三要素に Java toString が入るMAS-057 Phase 3 実装時 (PR #379) に実機検出。原因は Constants.INCOME_TAX_BRACKETS.brackets[6].upTo = Infinity を bootstrap レスポンスに含めていたことInfinity / -Infinity / NaN は V8→Java ブリッジでシリアライズ失敗するが、エラーが UI まで伝播しない (Java 側で例外が握り潰される)。GAS エディタから直接実行すると JSON.stringify は成功する (V8 内では問題ない) ため、再現性が「Web App 経由のみ」に限定され検知が極めて困難対策 (3 段階): ①bootstrap で既知の InfinityNumber.MAX_SAFE_INTEGER (9007199254740991) に scrub する防衛コードを書く / ②Repository 経由で取得する数値も Number.isFinite() で防御的にチェック / ③受信側 (クライアント) で state === null の場合に「サーバー側で Infinity / NaN / 関数 / 循環参照を含めていないか」のエラー表示。切分テクニック: (a) 静的 probe 関数 (Date と string のみ返す) で通信経路を確認 / (b) 関数内で JSON.stringify(result).lengthconsole.log / (c) それでも null なら必ず Infinity / NaN / 関数 / 循環参照を疑う / (d) 最終手段は HAR エクスポートで op.exec[0, ...] の中身を確認
3004-27Vertex AI preview モデルは個別有効化必須MAS-057 Phase 3 で gemini-3-pro-preview / gemini-3.1-pro-preview を呼ぶと bizlp-gas-accounting-dev の Vertex AI で HTTP 404 (Publisher Model not found)MAS-057 Phase 3 実装時 (PR #379) に実機検出。gemini-2.5-pro は動作するが、3.x 系 preview モデルは事前有効化が必要だったVertex AI の Generative AI Studio / Model Garden で publisher model を個別に Enable する必要がある + 48 時間の課金履歴経過が条件になっているケースあり (preview モデルは GA より厳格)。仕様書では「Vertex Gemini 経由で呼べる」と一括で書いてしまったが、preview と GA で制約が異なるモデル切替を 03_sys_params で動的化 (F57_INSIGHT_AI_MODEL + F57_GEMINI_MODEL_OVERRIDE_PRO/FLASH) し、preview モデル試験時は CUSTOM オプションで切替可能な設計とする (UI 上 model_id 直接入力)。default は GA リリース済モデル (gemini-2.5-pro 等) を採用。preview モデル使用時は仕様書に「Model Garden で個別 Enable + 48h 経過必要」を明記する。仕様書記載の API 名は 「YYYY-MM 時点」のタイムスタンプを併記 (#27 と同じ規則を踏襲)

並列実装・並行開発の同期失敗(#25, #31)

#日付カテゴリ失敗内容関連案件根本原因対策
3104-27案件 ID 採番衝突 (TODO_future.md 同期遅延)MAS-057 Phase 3 実装後の振り返りで派生した「配当ミックス最適化」案件を main 側プロンプトが「MAS-060 として起票」と指定したが、MAS-060 は既に「組織構成シミュレーター」(2026-04-25 起票) として確定使用済 → 番号衝突。sub 側で MAS-066 に振り直して起票 (PR #382)2026-04-27 main 側が MAS-057 Phase 3 PR #379 を実装する間に sub 側で MAS-060〜MAS-065 が起票されていたが、main 側が git pull 前に MAS-060 を新規予約してしまった。sub 側が git pull origin main 後の TODO_future.md grep で衝突を検出して振り直し複数ワークスペース (main / sub) での並行開発時の TODO_future.md 同期遅延。main 側が origin/main を fetch せずに新規案件 ID を予約すると、sub 側で確定済の番号と衝突する。CLAUDE.md の「複数ワークスペースでの並行開発ルール」§ファイル担当マトリクスでは TODO_future.md は sub 専属だが、新規案件 ID 予約は両側で発生しうる (起票プロンプト発行は main 側が行うことも多い)新規案件起票プロンプト発行前に必ず以下を実施: ①git fetch origin main && git diff HEAD origin/main -- docs/_internal/TODO_future.md で main の最新 ID 予約状況を確認 / ②`grep -nE '| F-[0-9]+ \

React / SPA 実装の落とし穴(#32-#33)

#日付カテゴリ失敗内容関連案件根本原因対策
3204-28React TDZ エラー (useMemo factory + const arrow ヘルパー後置)MAS-058 Step 5 (PR #400) RequiredRevenuePanel.tsx 実装中、初回 render で Cannot access 'isError' before initialization エラー発生。useMemo factory 内で参照する isError ヘルパーを const arrow function で後ろに宣言していたため Temporal Dead Zone (TDZ) 違反MAS-058 Step 5 SPA 実装中 (PR #400) に検出JavaScript の const / let 宣言は TDZ (宣言行に到達するまで参照不可) を持つ。function 宣言は hoisting されるが、const arrow は hoisting されない。React の useMemo(() => helper(...), [...]) の factory は render フェーズ中に同期実行されるため、factory 内で const 宣言したヘルパーへの参照が「宣言より前」になると TDZ エラー対策: ①ヘルパー関数は useMemo 呼出よりに宣言する (推奨)、②function 宣言を使う (hoisted・順序不問)、③ヘルパーを useCallback でラップして依存配列管理する場合も宣言順を意識。追加チェック: コンポーネント内の const/let 宣言ヘルパーが、そので参照されていないかを ESLint no-use-before-define ルールで検出可能 (TypeScript strict 設定推奨)
3304-28新規 GAS ドメインエンジン追加時の SPA 副作用 import 漏れMAS-066 PR (#402) で mas/400_domain/449_dividend_mix_optimizer.js を新設し webapp_client/scripts/sync-engines.mjs の同期対象に追加したが、webapp_client/src/cockpit-main.tsx への副作用 import を忘れていたため、cockpit 上で配当を変更しても計算結果に反映されないバグが発生MAS-066 実装中 (PR #402) に検出。fix(MAS-066) commit 41305eacockpit-main.tsximport './engines/449_dividend_mix_optimizer.js' を追加して修正window 露出方式 (注意事項 #14 (b) 採用) では mas/400_domain/{xxx}_*.jssync-engines.mjs でコピー → webapp_client/src/engines/ に配置 → ビルド時に if (typeof window !== 'undefined') window.XxxEngine = XxxEngine; が末尾に自動付与される。ただし cockpit-main.tsx で副作用 import (import './engines/xxx_*.js') しないと bundle に含まれず window.XxxEngine が undefined になる。Vite の tree-shaking が「副作用なし」と判断して除外する典型パターン。sync-engines.mjs 自体はファイルコピーのみで bundle 登録までは面倒見ない新規ドメインエンジン追加時の必須チェックリスト: ①mas/400_domain/{xxx}_*.js を新設・IIFE + var XxxEngine = (function(){ ... })() パターンで実装 / ②webapp_client/scripts/sync-engines.mjsENGINES_TO_SYNC 配列に追加 / ③**webapp_client/src/cockpit-main.tsx (or sidebar-main.tsx 等のエントリポイント) に副作用 import を追加** ← 必須・抜け漏れ多発ポイント / ④npm run build 実行 / ⑤cockpit/sidebar の動作確認時に console.log(window.XxxEngine) で undefined でないことを確認 / ⑥単体テスト (F66-01 等) は GAS 側のみで PASS しても SPA 側で動かないケースがあるためブラウザでの実機確認まで含めて完了判定sync-engines.mjs の出力ログに「次の手順: cockpit-main.tsx に副作用 import を追加してください」を強調表示する改修を将来検討

計画 B/S と実績 B/S の構造的乖離(#34)

#日付カテゴリ失敗内容関連案件根本原因対策
3405-01計画 B/S が実績 B/S と大きく乖離 (cash plug 過小)PR #460 で 73_bs_plan の現預金が実績 71_bs と乖離 (2026-02 で約 -605K)。計画 B/S で資金見通しが過度に悲観的になり、経営判断ミスリードリスク。兆候: (a) 計画側現預金が実績より大幅マイナス・(b) 未払系負債が異常に少ない・(c) 月次で乖離幅が拡大MAS-300 (BUG_tracking) として記録。PR #460 で3 段階のロジック改善 (d748ed53aaa04ec21c3dc1f04ef5) を経て案 A 改 2 に確定「計画 = 全 INV 即決済前提」の単純化により、計画側で未払系負債が積み上がらず現預金がマイナス側に振れる構造的バグ。実績側 (PHASE 2) では 決済日_実績 ベースで期ずれが正しく解消されるが、計画側 (PHASE 1) では同じ仕組みが欠落。月次で乖離幅が拡大するのは「未消込 INV の累積」が cash plug として効かないため (実績では未払金として B/S に積まれるが、計画では即時決済扱いで負債側に出てこない)mas/600_report/601_datamart_ingest.jsdmIngestPlanData_ で INV の 決済日_実績 列を期ずれ解消月の判定起点とする: (a) 決済日_実績 記入済 → 実績 PHASE 2 と同月で期ずれ解消 (sStr = settleActStr) / (b) 決済日_実績 空 + 決済日_計画 ≤ 当月 → 未消込のまま残す (sStr = '9999-12') / (c) それ以外 → 決済日_計画 をそのまま使用。残乖離 ±30K は地代家賃の前払 INV 表示差 (71 では「未払費用 -30K」・73 計画では「前払費用 +30K」となるが cash plug 効果は同値で許容)。追加チェック: 計画 B/S と実績 B/S の差分は当月決算で ±50K 以内 (地代家賃前払等の表示差を除く) を許容範囲とし、超過時は警告表示 (MAS-085 整合性チェックパターンを応用)。設計原則: 計画 B/S 生成時は実績側の決済日 (決済日_実績) を SSoT として優先し、計画日 (決済日_計画) は補助情報として扱う

GAS API: フィルター適用中の連続 setValue が silent-fail(#35)

#日付カテゴリ失敗内容関連案件根本原因対策
3505-01フィルター適用中の連続 setValue で後続列が silent-failPR #465 で applyBankSettlement のフィルター silent-fail 修正。33_wrk_bank に「決済ステータス = 未処理」フィルターを設定した状態で消込実行すると、消込後に 33タブを見ても 決済日_実績 列が空のままAction B (自動仕訳生成) が起動条件 (33タブの「消込済 かつ 自動仕訳JNL_ID あり」判定) を満たさず止まる二次被害あり。兆候: スクリプト実行は成功 (例外なし・ログも正常) するが、特定列だけ値が入らない (「消込済」は書かれるが他は空)。フィルター解除後に再実行すると正常動作するため再現条件が掴みにくいMAS-302 (BUG_tracking) として記録。PR #465 commit c069b63 で修正1 つ目の setValue でフィルター対象列 (例: 「決済ステータス」列を「未処理」→「消込済」に変更) が変わると、Google Sheets が即フィルター再評価を実行して対象行が hide される。hide 後の行に対する後続の setValue は API としては成功扱いだが実際には書き込まれない silent-fail が発生する。Sheets API の Range が hide 状態の行にバインドされた直後の操作で発生するレースコンディション同一行への複数セル更新は range.setValues([rowVals]) で 1 つの API call にまとめて原子化する。例: range1.setValue(A); range2.setValue(B); range3.setValue(C); range4.setValue(D) (4 call・各 call の間にフィルター再評価が挟まる) → sheet.getRange(row, col, 1, 4).setValues([[A, B, C, D]]) (1 call・原子的書込・フィルター再評価が挟まる隙なし)。派生注意: setBackground 等の書式系は filter 状態に左右されないため分離可能。setValues 化が困難な場合は、フィルター対象列を最後に更新するワークアラウンドも可だが、フィルター列追加時の保守コストが上がるため非推奨。チェック: フィルター適用シート (flagTabs 対象) への複数 setValue 呼出は code review で setValues 化を必須とする (33_wrk_bank / 23_bud_subscription 等)

単一マッチ前提のロジックが拡張機能 (合算 / 部分一致) に未追従(#36)

#日付カテゴリ失敗内容関連案件根本原因対策
3605-01単一ケース前提のロジックが多重ケース拡張時に silently 機能しないPR #465 の Pass 2.5 ソフト合算追加後、applyBankSettlement の差額記録ロジックが stlIds.length === 1 の単一マッチ条件のみ対応しており、Pass 2.5 (合算 ±少額差) ヒット時の差額が会計上ロスト。71_bs 2026-04 現預金乖離 98,837 円のうち 1,000 円分が本パターン起因 (武生年金: 銀行 149,950 vs STL 合計 150,950)。兆候: (a) 既存単一機能テストは PASS する (b) 拡張機能 (合算等) で「動いているように見えるが副次データ (差額・摘要・科目) が抜ける」 (c) 数ヶ月後に B/S 集計時の cash plug 不整合で発覚MAS-303 (BUG_tracking) として記録。MAS-338 (dev_mas-338_settlement_diff_handling.md) として spec 化済拡張機能 (Pass 2.5 ソフト合算) を追加した PR #465 では「合算マッチ機能 + 銀行明細との金額判定」までを実装スコープとし、消込後の副次処理 (差額記録 / 科目推定 / 監査ログ) の合算対応は別 PR スコープに切り分けたため、「単一マッチ前提のロジック (if (stlIds.length === 1))」がそのまま生き残り、新機能の差額が落ちる片肺状態に。「単一前提ロジック」の存在を PR #465 のレビュー時に検出できなかったのは、合算機能のテストが「合算マッチが成功すること」までしかカバーしていなかったため(1) 拡張機能追加時のチェックリスト: 既存ロジックの「if (count === 1) / [0] / 単一前提の if 分岐」を grep で全件抽出し、拡張機能でも対応必要かを review checklist に明文化。(2) findComboGroup_ 等の拡張ヘルパー追加時は、その下流で「合算結果を消費する全箇所」を call graph で追跡し、stlIds.length を見ている箇所を網羅 (差額記録 / 監査ログ / UI 表示)。(3) テストカバレッジ: 単一マッチ + 合算マッチ + ソフト合算の 3 ケース全てで「副次データ (差額・科目・ログ) が正しく書かれているか」を検証する E2E テストを必須化 (F338-01 〜)。(4) 設計原則: 拡張機能 (合算 / 部分一致 / 差額あり) は「既存機能の置換」ではなく「上位 superset」として設計し、stlIds.length === 1 の単一前提分岐は速やかに >= 1する (差額按分ヘルパー chooseDiffTargetStl_ を介して同一インターフェースで処理)。チェック対象 spec: MAS-338 (本パターンの解消・実装着手判断待ち)

Walking Skeleton / ADR-0028/0029 準拠漏れ(#37-#39)

#日付カテゴリ失敗内容関連案件根本原因対策
3705-13監査ログ書込の silent-fail 検知不能UC スライス実装後、Utils.auditLog の呼び出しはあるが 98_audit_log シートに行が追記されない。スクリプト実行は例外なし・ログも正常に見えるため数スプリント後まで気づかない。兆候: (a) Utils.auditLog 呼び出しコードは存在する (b) 98_audit_log シートの行数が実行回数と一致しない (c) 監査要件の証跡が空ADR-0028/0029 Walking Skeleton 必須要素③の欠落Walking Skeleton の「③監査ログ (Log)」をテストせずに skeleton ステータスへ移行したため、呼び出し引数の型不一致 (例: undefined を渡す) が silent-fail として見逃されるWalking Skeleton の test_{slice_id}_audit_logged_() テストを必須化: 98_audit_log シートの行数を実行前後で比較し、PASS エントリが追記されることを assert する。skeleton ステータス移行条件に本テストの PASS を含める。Utils.auditLog は第 1 引数 sliceId(文字列)・第 2 引数 status'PASS' または 'FAIL')・第 3 引数 detail(任意文字列)の型チェックを関数先頭で行い、型不一致時は console.error ではなく throw させる
3805-13Feature Flag キーが PropertiesService 9KB / 30 文字制限を超過UC スライスで Feature Flag キーを FF_UC{N}_S{NN}_{verb} 形式で命名したが、キー文字列が 30 文字を超過し PropertiesService.setProperty が例外をスローする。兆候: (a) Feature Flag の設定時にのみ例外が出る (b) キー名が FF_UC10_S12_enable_all_the_things 等の 30 文字超ADR-0029 C1 で Feature Flag キー命名規則を定めたが、FF_UC{N}_S{NN}_{verb} の最大長チェックを仕様書に明記していなかったFF_ (3) + UC (2) + N (1-2) + _ (1) + S (1) + NN (2) + _ (1) + verb の最大長は 30 - 10 = 20 文字。動詞が長い場合 (例: enable_monthly_closing_report) は 30 文字を超過する命名規則を FF_UC{N}_S{NN}_{verb} かつ 総長 30 文字以内 に厳格化: verb は最大 18 文字 (N=1桁・NN=2桁時) 〜 最小 16 文字 (N=2桁時)。仕様書作成時に scripts/B4_inject_walking_skeleton.js がキー長チェックを自動実行しキー超過を警告する。test_{slice_id}_error_handling_() テスト内で実際にキーを PropertiesService にセット・ゲットして例外が出ないことを確認する
3905-136 分制限を貫通する UC スライス粒度UC スライスの実装後、実データで実行すると 6 分制限(360 秒)を超過してタイムアウトが発生する。兆候: (a) 少量データのテストは PASS する (b) 本番スプシで実行すると「最大実行時間を超えました」エラー (c) _RUNTIME_METRICS シートに実行時間の記録がない(タイムアウトで measureRuntime_ の finally ブロックが未到達)Walking Skeleton の仕様書レビュー時に「6 分制限チェック(推定実行時間)」の記載が不十分だったため、スライス粒度が大きすぎることを実装前に検知できなかったUC スライスが「1 UC スライス = 1 つのビジネスシナリオ全体」になっており、行数が多いシートへの全行処理が含まれている。仕様書の「推定実行時間: _____ 秒」が空欄のまま CONDITIONAL GO 判定を通過した仕様書の Walking Skeleton チェックリストの「推定実行時間」空欄は GO 判定不可: scripts/B5_review_specs_by_gemini.js のレビュープロンプト §G-3 で 6 分見積もり未記載を Critical 指摘対象とする。6 分超過リスクがある場合は chunk 分割(Properties 進捗保存 + Time-driven Trigger)の実装方針を仕様書に明記すること。test_{slice_id}_input_() テストで Utils.measureRuntime_ の計測値が 60 秒未満であることを Walking Skeleton 完了条件に含める(余裕率 6 倍: 少量テストデータ × 6 ≦ 360 秒)

ドキュメント大規模改訂時の構造的落とし穴(#40-#42)

#日付カテゴリ失敗内容関連案件根本原因対策
4005-20ドキュメントindex.md / SUMMARY.md の中身 swap (PR #874) 後、既存リンク [index.md §1.9](../index.md) が意味的に壊れた状態で merge され、PR #873 (Glossary SSoT) で発覚。Step 4 audit (PR #876) でも追加で dev_mas-090 L336[5.5 預り金・源泉税](../index.md) 等が swap の影響を受けている可能性が判明 (legacy-dev 故触らず保留)PR #874 / PR #876 / PR #873ファイル間の content swap は anchor 参照を破壊するが、swap 実施 PR で「grep -rnE 'filename\.md(#[a-zA-Z0-9-]+)?'」での参照全件抽出を行わなかった。build 成功 ≠ anchor 解決成功 (anchor は missing でも build は通る)content swap / 大規模 section 移動 PR の必須チェック: ①swap 対象ファイル名を grep -rnE 'filename\.md(#[^)\s]*)?' docs/ で全 link を抽出 → ②各 link が swap 後も解決可能か手動 or スクリプトで検証 → ③Cloudflare Pages preview で実際の navigation を merge 前に確認。docs-build.mjs の build 成功は anchor 解決を保証しないため、別途 link-check が必要 (将来 CI 化を検討)
4105-20ドキュメントadr-lint_rules.md が Phase 2b で 637 行に到達し Anthropic Skill 500 行制約超過 → Phase 2c で案 X5 (rules/<id>.md 個別ファイル分離) へ緊急移行 (PR #866)ADR-0054 / PR #865 / PR #866Progressive Disclosure 設計時に「閾値到達後の分割パス」を ADR §6 撤退条件で定義済だったが、Phase 2b で残 12 rule Detail を一度に追加して閾値超過。Phase 単位で 400 行 (WARN) 段階での移行判断を行わなかったADR §6 撤退条件で 400 行 (WARN) 段階での移行判断を必須化。CI で 400/500 行二段階閾値を強制 (PR #867 で scripts/adr-lint-doc-consistency.mjs 実装済、main doc 134 lines (limit 400 WARN / 500 FAIL) 出力で監視)。Phase 2 系の大量追加 PR では事前に行数を見積もり、400 行超過見込みなら Phase 分割直前に X5 (個別ファイル分離) を先行実施してから本体追加
4205-20Git 運用pre_bash_guard.shgit push --force-with-lease を自動実行から block するため、PR rebase 後の push が自動 PR フローで詰まる (PR #873 で発生)。兆候: rebase は成功・build/lint も pass しているのに自動 push が「permission denied / hook blocked」相当で失敗scripts/hooks/pre_bash_guard.sh / CLAUDE.md "Prohibited"不可逆操作 (force push) を技術的にブロックする設計は意図通り正しい (.claude/settings.jsonpermissions.deny + PreToolUse Hook)。ただし PR rebase 後の正当な force-with-lease push もブロックされるため、自動フローでは詰まるPR rebase + force-with-lease push のオペレーション手順を明文化: ①ローカルで git rebase main → ②検証 (docs-build.mjs / docs-nav-lint.mjs / adr-lint-doc-consistency.mjs) → ③! git push --force-with-lease origin <branch> をユーザに依頼 (! prefix で hook を経由しない sandbox 外実行) → ④gh pr view N --json mergeable,headRefOid で remote 反映を確認。docs/_internal/05_how-to/git_workflow.md の rebase 章に本パターンを記載 (将来)

Deploy: 無効な manifest 値 → clasp 3.x silent skip → 古い bundle が動き続ける(#43)★ 最重大級

#日付カテゴリ失敗内容関連案件根本原因対策
4305-22Deploy 運用OCR Bench で mas/appsscript.jsonwebapp.accessANYONE_WITH_GOOGLE_ACCOUNT に設定。clasp 3.x はこの値を Invalid manifest と判定し clasp push 全体を silent skipdeploy.sh だけが走り「✅ Deploy complete」と表示されるが、実際は古い bundle が GAS に残ったまま約 1 日間動作。ローカルで bbox padding / 印字手書き判定 / 罫線除去 / dilation / Claude validator / Self-Consistency / GT 全項目 / pdfjs scale 4.0 / pdf-lib CropBox を実装・「デプロイ完了」しても、ユーザのブラウザではすべて ddd3fa5 時点のコードが動く。「pdfjs blank」「PNG 出力」「click 不可」等の症状を 1 日かけて多方向から「修正」したが、すべて wrong target — 真の原因は push 自体が一度も走っていない だったため改善せずOCR Bench Sprint (PR #891 → #892 → #901)(1) ANYONE_WITH_GOOGLE_ACCOUNT存在しない値 (有効値: UNKNOWN_ACCESS / DOMAIN / ANYONE / ANYONE_ANONYMOUS / MYSELF)。Anthropic/Google ドキュメントの口語表現「anyone with Google account」を勝手に enum と同一視した思い込み / (2) clasp 3.x は manifest validation でこの値を reject するが、エラー出力は npm run deploy:dev 2>&1 | tail -3 で末尾 3 行に切り詰めると見えない / (3) deploy:dev = push:dev && deploy.sh&&push:dev の最後の cmd (clasp push) が exit 0 で帰れば通過。clasp は "Skipping push." と表示しつつ exit 0 で抜けるため、deploy.sh が無批判に走り「✅ Deploy complete」を出す / (4) deploy.sh の clasp deploy --deploymentId X は GAS 側に既にある最新ファイル群で新 deployment 版を作るだけで、ローカルファイルと GAS ファイルの一致は保証しないA. 検証 (恒久対策): ①scripts/pre-push-check.sh 末尾で mas/appsscript.json の access 値を有効値リスト (UNKNOWN_ACCESS|DOMAIN|ANYONE|ANYONE_ANONYMOUS|MYSELF) と grep 比較し外れたら exit 1 / ②deploy:devpush:dev 末尾を clasp push --force に変更 (change detection で skip するのを防止) ※本 PR で実施済 / ③deploy.sh の冒頭で deployed bundle の sentinel string を fetch して検証: mas/templates/ocr_bench_shell.html に build 時 unique timestamp や git SHA を埋め込み (例: <meta name="build-sha" content="aacfa5d">)、deploy 直後に curl /exec?... でその string を取り、ローカルファイルの該当箇所と一致しなければ exit 1。B. 観察 (短期対策): ①deploy 実行時は tail -3 ではなく tail -30 以上Skipping push. / errors / warning を必ず確認 / ②ユーザから「修正が反映されていない」報告を受けたら コード変更でなく deploy 状況を最初に疑う (HAR ダウンロードして bundle 内に新シンボル grep 等)。C. 設計思想: mas/appsscript.json のような外部 schema に依存する設定値は enum を勝手に書かず、必ず公式リファレンスを 1 次資料で確認。ChatGPT 等他 AI から提示された値も鵜呑みにしない

Deploy: worker src PR の merge = 即本番デプロイ → in-flight 審査 run を kill(#44)

#日付カテゴリ失敗内容関連案件根本原因対策
4406-04Deploy 運用PR #1431 (Gate 1 プロンプト改善・src/nodes/socratic.ts 含む) を merge → deploy-worker.yml が 12:05-06 (UTC) に自動デプロイ → その時刻に実行中だった審査 run (drp-layered-docs-architecture 再投入) の queue consumer invocation が kill され、再配信も isInflightRedelivery ガード (running + updatedAt 20 分鮮度) で ack-skip → 永久無進捗 → EC-3 watchdog が idle 1200s で error 終端 (12:26、telemetrywatchdog-timeout 行記録)。審査 ~10 分ぶんの LLM 課金と gate 進捗が喪失PR #1431 / DRP-376 残課題① / deploy-worker.yml(1) decision-pipeline は merge = 本番デプロイ の配線 (deploy-worker.ymldrp/src|public|wrangler.toml の main push で発火) だが、デプロイと実行中審査 run の排他機構がないCloudflare Workers のデプロイは in-flight の Queues consumer invocation を graceful drain しない / (2) merge 操作者 (Claude) からは実行中 run を一覧する手段がない (list-sessions エンドポイント無し・telemetry は run 終端時書込のため in-flight が見えない) / (3) フル run ~10-16 分の長尺と kill 後再開不能 (gate 単位 chunk 化未実装 = DRP-376 残課題①) の合せ技で被害が最大化A. 運用 (即日): worker src (drp/src|public|wrangler.toml) を触る PR の merge 前に「審査 run 実行中でないか」をユーザーに必ず確認 (CLAUDE.md Workflow 節に追記済)。確認できるまで merge 保留 / B. 検知: watchdog は設計どおり機能 (沈黙せず 20 分で error 終端 + telemetry 記録)。kill 直後の症状は「running のまま進捗停止」→ 20 分待てば watchdog-timeout で表面化 / C. 復旧: draft は KV に残存するため chat UI から再 run (新 worker 上で最初から) / D. 構造解消 (将来): queue-consumer-gate-chunking ADR (gate 単位 chunk 実行・kill 後再開可能) が審査 pass 済み・PR 起票待ち。採択されればデプロイ kill の被害は「実行中 chunk 1 個」に縮小