概要

項目内容
案件IDMAS-122
カテゴリデータ整合性
PhaseP1
優先度★★★
対象ファイル200_data/201_data_validator.js / 900_test/901_test_runner.js / templates/operations_sidebar.html / 新規 800_ops/813_recalc_ord_balance.js
前提案件MAS-297(発注残高二重減算)恒久対策

目的

MAS-297(発注残高二重減算)の恒久対策として、31_wrk_order32_wrk_invoice の消化状況を自動検証する仕組みを新設する。

  • 発注残高(自動計算) と「税込金額_発注 − 有効 INV税込金額_計画 合計」の乖離を自動検知
  • ORD が存在しない孤立 INV を早期に発見
  • 有効フラグ=FALSE 化された INV が発注残高に正しく反映されていない状態を検知
  • 発注残高が破損したケースに備え、有効 INV から逆算した値で強制再同期する運用手段(「発注残高を再計算する」メニュー)を提供する
  • 既存の runDataValidation フロー(201_data_validator.js)に検証項目を追加し、不整合 ORD 行を WARN_RED 色でハイライトする

現在のコード

ORD↔INV 整合性チェック専用ロジックは未実装。現状は以下の部分的チェックのみ存在する(200_data/201_data_validator.js):

  • validateInvoice_: 親発注 ID が ordSet に存在するかの存在確認のみ実施(ordSet有効フラグ=TRUE の ORD ID セット)
  • validateOrder_: 発注残高(自動計算) がマイナスの場合に WARNING を出すのみ

再利用する既存関数:

モジュール関数/オブジェクト用途
200_data/202_repository.jsOrderRepository.findAll(){ headers, dtos: OrderDTO[] } を返す
200_data/202_repository.jsOrderRepository.save(dtos)全件上書き(writeDtosToSheet_ で clear→setValues)
200_data/202_repository.jsInvoiceRepository.findAll(){ headers, dtos: InvoiceDTO[] } を返す
000_infra/003_contracts.jsOrderDTO / InvoiceDTO型定義
000_infra/004_utils.jsUtils.parseAmt(val)数値パース(全角数字・カンマ対応、失敗時 0)
000_infra/002_constants.jsConstants.COLORS.WARN_RED_BG / Constants.COLORS.WARN_RED_FC警告色 #f4cccc / #cc0000

補足: readSheetAsDtos_有効フラグ でのフィルタを行わないため、業務ロジック側で判定が必要。

修正方針

Step 1: 整合性検証ロジックの開発

200_data/201_data_validator.js に ORD↔INV 整合性チェック関数 validateOrderInvoiceConsistency_(ordResult, invResult) を追加する。

  • 入力: OrderRepository.findAll()InvoiceRepository.findAll() の戻り値。

  • 有効フラグ判定(readSheetAsDtos_ はフィルタしないため必須):

    function isActiveDto_(dto) {
      var flag = dto['有効フラグ'];
      return flag !== false && String(flag).toUpperCase() !== 'FALSE';
    }
    
  • InvoiceDTO親発注ID(ORD) をキーとする Map にグルーピング(有効 INV のみ):

    var invByOrd = new Map();  // key: ORD_ID, value: InvoiceDTO[]
    var orphanInvs = [];       // 親 ORD 不在の INV
    var ordIdSet = new Set(ordResult.dtos.filter(isActiveDto_).map(function(d){ return d['発注ID(ORD)']; }));
    invResult.dtos.forEach(function(inv) {
      if (!isActiveDto_(inv)) return;
      var ordId = String(inv['親発注ID(ORD)'] || '').trim();
      if (!ordId) return;
      if (!ordIdSet.has(ordId)) { orphanInvs.push(inv); return; }
      if (!invByOrd.has(ordId)) invByOrd.set(ordId, []);
      invByOrd.get(ordId).push(inv);
    });
    
  • Phase 1 で確認した検証項目 (a)〜(d) を独立した小関数として実装する:

    検証項目関数判定式(概略)
    (a) 親ORDなしINVの検知checkOrphanInv_(orphanInvs)orphanInvs.length > 032_wrk_invoice の該当 INV を WARN_RED
    (b) 超過紐付け(ORD総額 < 紐づくINV合計)checkOverLinked_(ordDto, invList)Utils.parseAmt(ordDto['税込金額_発注']) + 0.01 < sum(Utils.parseAmt(inv['税込金額_計画']))
    (c) 残高乖離(発注残高 ≠ 税込金額_発注 − 有効INV合計)checkBalanceDrift_(ordDto, invList)Math.abs(Utils.parseAmt(ordDto['発注残高(自動計算)']) - (Utils.parseAmt(ordDto['税込金額_発注']) - sum(Utils.parseAmt(inv['税込金額_計画'])))) > 0.01
    (d) FALSE化INVの未反映(c) の副次効果で検出有効フラグ=FALSE INV を除外して再計算した値と 発注残高(自動計算) が乖離 → (c) で検知される
  • 許容誤差: 浮動小数点誤差を避けるため Math.abs(diff) > 0.01 を使う(完全一致判定は使わない)。

  • 金額フィールド: 必ず Utils.parseAmt() 経由で数値化する(文字列・全角数字・空文字に備える)。

  • プロパティ名: OrderDTO.税込金額_発注 / InvoiceDTO.税込金額_計画 / OrderDTO.発注残高(自動計算) を厳守(税込金額 と略称しない)。

  • 結果: 不整合 ORD の行番号・INV の行番号を返し、呼び出し元(runDataValidation)が bg / notes 配列へ Constants.COLORS.WARN_RED_BG / Constants.COLORS.WARN_RED_FC を書き込む。

Step 2: テスト・バリデーターへの組込

(2-1) 200_data/201_data_validator.js への組込

  • runDataValidation のループ内、WRK_ORDRWRK_INVC の両方を処理し終えた後に validateOrderInvoiceConsistency_ を呼び出すフックを追加する。
  • 既存の validateOrder_ / validateInvoice_ は残し、追加の検証として組み込む(既存シグネチャ・戻り値は変えない)。
  • 検出した不整合 ORD 行・孤立 INV 行は bg / notes 配列に Constants.COLORS.WARN_RED_BG を設定し、セルメモに [VAL] 発注残高乖離: 期待値=XXX 実績=YYY などの理由を書き込む(既存 setErr_ パターン準拠)。
  • 結果ダイアログのシート別件数カウントに本検証の件数を合算する(totalErrorsresults['31_wrk_order'] に加算)。

(2-2) 900_test/901_test_runner.js への組込

  • 新規テスト関数 testT12_OrdInvConsistency_() を末尾に追加する(T11 が末尾のため次番号 T12)。
  • テストパターン:
    • T12-01: 正常ケース(OrderRepository.findAll()InvoiceRepository.findAll() の結果を直接 validateOrderInvoiceConsistency_ に渡し、既存の正常データで検出件数 = 0 を確認)
    • T12-02: 孤立 INV の検出(invResult.dtos に架空の 親発注ID(ORD)='ORD_TEST_INVALID' をメモリ内で追加し検出件数 ≥ 1 を確認)
    • T12-03: 超過紐付けの検出(メモリ内で 税込金額_発注 を意図的に小さくして再実行し検出件数 ≥ 1 を確認)
    • T12-04: 残高乖離の検出(メモリ内で 発注残高(自動計算) を意図的にずらして再実行し検出件数 ≥ 1 を確認)
    • シートへの書き込みは行わない(メモリ操作のみで純粋にロジックを検証)。
  • runAllTests()try { testT12_OrdInvConsistency_(); } catch (e) { addResult_('T12-ERR', ...); } を追加する。

Step 3: 発注残高の強制再計算ツールの開発

(3-1) 新規ファイル 800_ops/813_recalc_ord_balance.js を作成

  • 番号 813 の採用理由: ls 800_ops/ で既存最大は 808。ただし 809〜812 は他仕様書(MAS-119 / MAS-120 / MAS-121 / MAS-135)が既に予約しているため、衝突回避のため 813 を採用する。

  • 関数名: recalcOrderBalance()

  • 処理フロー:

    1. SpreadsheetApp.getUi().alert() で実行前確認ダイアログを表示(Human-in-the-Loop)。件数サマリと「OrderRepository.save() は全件上書きです。事前にスプレッドシートのバージョン履歴からバックアップ可能であることを確認してください」を明示する。
    2. LockService.getScriptLock() + lock.tryLock(30000) による多重実行防止(失敗時は ui.alert('他の処理が実行中です。しばらくしてから再試行してください。') で早期終了)。
    3. OrderRepository.findAll()InvoiceRepository.findAll() で全 DTO 取得。
    4. 有効な InvoiceDTO の 税込金額_計画親発注ID(ORD) 別に合算(Utils.parseAmt 経由)。
    5. 全 ORD について 発注残高(自動計算) = Utils.parseAmt(税込金額_発注) - 請求合計 を計算し DTO を更新(有効/無効問わず全件更新し、無効 ORD は残高計算対象 INV も有効フラグ判定でフィルタされるため自然に整合)。
    6. OrderRepository.save(dtos)31_wrk_order を全件書き戻す。
    7. Utils.auditLog('MIGRATE', '31_wrk_order', '', '', 'recalcOrderBalance', '', { updated: count }, '発注残高再計算') で監査ログ記録。
    8. Utils.logInfo + SpreadsheetApp.getUi().alert の両方で結果サマリ(更新件数・変更件数)を通知。
    9. try / catch / finally { lock.releaseLock(); } で排他制御解放を保証。
  • 冪等性: 処理自体は「有効 INV 合計からの逆算」のみで副作用は 発注残高(自動計算) 列の更新のみ。何度実行しても結果は同じ。

(3-2) メニュー追加

  • templates/operations_sidebar.html🔧 マイグレーション セクション(L89-L95)に「発注残高を再計算する」ボタンを追加する:

    <button class="btn" onclick="run('recalcOrderBalance', this)">発注残高を再計算する</button>
    
  • メニュー名の根拠: templates/operations_sidebar.html L89 の <h3>🔧 マイグレーション</h3> を Read で確認済み(実在する文字列)。101_sys_config.jsonOpen🚀 BizLP トップメニュー(サイドバーを開くエントリ)のみを定義しており、操作ボタンは全てサイドバー HTML に集約されている。

影響範囲

新規ファイル

  • 800_ops/813_recalc_ord_balance.js(1 ファイル新規)

既存ファイルへの追記

  • 200_data/201_data_validator.js: validateOrderInvoiceConsistency_ 等の新規関数を末尾に追加、runDataValidation に組み込みフックを追加(既存関数シグネチャは変えない)
  • 900_test/901_test_runner.js: testT12_OrdInvConsistency_ を末尾に追加、runAllTests() に呼び出しを追加
  • templates/operations_sidebar.html: 🔧 マイグレーション セクションに 1 ボタン追加

既存動作への影響

  • runDataValidation の実行時間は ORD 件数 × 紐づき INV 件数に比例して若干増加(オンメモリの Map 操作のため実運用で問題になる規模ではない)
  • recalcOrderBalance手動実行のみ(自動トリガーなし)。誤実行防止のため確認ダイアログ必須
  • 他の RPA / Action A / Action B ロジックへの影響なし

注意事項

  1. 列番号のハードコード禁止: 全てヘッダー名ベース(indexOf / DTO プロパティアクセス)で参照する。31_wrk_order / 32_wrk_invoice の列順変更に追従できるようにする。
  2. Utils.parseAmt() 必須利用: 税込金額_発注 / 税込金額_計画 / 発注残高(自動計算) は必ず Utils.parseAmt() を経由して数値化する。空文字・全角数字・カンマ区切り文字列に備える。
  3. 有効フラグ判定の統一: dto['有効フラグ'] === false || String(dto['有効フラグ']).toUpperCase() === 'FALSE' の書式を統一使用する(既存 isActiveRow_ / readSheetAsDtos_ との整合)。readSheetAsDtos_ は有効フラグでフィルタしないため、業務ロジック側で明示的にチェック。
  4. OrderRepository.save() は全件上書き: writeDtosToSheet_clearContent()setValues() するため、事前に DTO を取得してから同じ DTO 配列を上書き保存しないとデータ消失の危険がある。recalcOrderBalance では必ず findAll() で全件取得後に更新・保存する。事前にスプレッドシートのバージョン履歴でバックアップ可能であることを確認ダイアログで周知する。
  5. メニュー名は Read で確認した実在する文字列のみ使用: templates/operations_sidebar.html<h3>🔧 マイグレーション</h3> セクション(L89)に追記する。造語・推測禁止。
  6. プロパティ名の正確性: OrderDTO.税込金額_発注税込金額 ではない)、InvoiceDTO.税込金額_計画税込金額 ではない)、OrderDTO.発注残高(自動計算) を正確に使用する。
  7. 許容誤差: 浮動小数点誤差を避けるため完全一致ではなく Math.abs(diff) > 0.01 を使う。
  8. LockService 必須: recalcOrderBalanceLockService.getScriptLock() + tryLock(30000) + try/finally releaseLock() で多重実行防止する(他 Action と同時実行で整合性破綻するため)。
  9. 監査ログ記録: Utils.auditLog('MIGRATE', ...)98_audit_log に記録する(807_migration_i10.js と同様のパターン)。
  10. テストはメモリ操作のみ: testT12_OrdInvConsistency_ はシートに書き込みを行わず、findAll() 結果をディープコピーして検証対象に渡すこと(副作用を持たないテスト)。

エッジケース

条件挙動実装上の対応
税込金額_計画 がマイナス(返金 INV)請求合計がマイナスになり残高が増えるUtils.parseAmt() で数値化し符号そのまま加算。乖離判定は同様に Math.abs(diff) > 0.01
有効フラグfalse(boolean) / 'FALSE'(string) / 空白無効行として全処理スキップ`dto['有効フラグ'] === false
1 つの ORD に INV が 0 件INV リストが空配列`invByOrd.get(ordId)
浮動小数点誤差(差異 0.00001 円など)完全一致では誤検出Math.abs(diff) > 0.01 の許容誤差で乖離判定
親 ORD が存在しない孤立 INV検証 (a) で検出対象 INV の 請求ID(INV) をリストアップして Utils.logInfo 出力 + 該当行を WARN_RED でハイライト
発注残高(自動計算) が空白または非数値Utils.parseAmt が 0 を返す0 として扱い 税込金額_発注 - INV合計 との乖離チェックを実施。再計算ツールで正しい値に上書きする
税込金額_発注 が空白または非数値Utils.parseAmt が 0 を返す0 として扱い、INV合計がある場合は超過紐付け (b) で検出される
親発注ID(ORD) が空文字・空白のみ孤立 INV 判定の対象外`String(inv['親発注ID(ORD)']
FALSE 化された INV が発注残高に未反映検証 (c) で検知有効 INV のみで逆算するため、FALSE 化 INV が計上された残高は乖離として検出される(検証項目 (d))
ORD が FALSE 化されたが紐づく INV は TRUE のまま孤立 INV として検出ordIdSet は有効 ORD のみで構成されるため、自動的に検証 (a) で検知される
同一 発注ID(ORD) が 2 行以上存在(データ破損)invByOrd の最初の ORD に対して検証が走るvalidateOrder_ 側の既存重複 ID チェック(もしあれば)に任せ、本検証では先勝ちで判定
再計算ツール実行中に他ユーザーが編集LockService.tryLock(30000) で多重実行防止30 秒以内にロック取得できない場合はダイアログ通知して中断
recalcOrderBalance 実行時に OrderRepository.save() が失敗部分更新でデータ消失の可能性try/catch/finally { releaseLock(); } で確実にロック解放、エラーダイアログ+Utils.logError で原因提示

実データ検証

実装着手前に MCP で以下を確認する:

  • 31_wrk_order発注残高(自動計算) 列の実際のデータ形式(Number 型 / 文字列 / 空欄)と空欄率を把握する
  • 32_wrk_invoice親発注ID(ORD) 列の入力状況(空欄件数・ORD_xxx 形式外の異常値の有無)を把握する
  • 32_wrk_invoice有効フラグ=FALSE の INV 件数を確認し、それらが発注残高に影響している ORD の有無を特定する
  • 既存の MAS-297 で報告された二重減算パターンがまだ残っているかを、本検証ロジックで試験的に検出できるか確認する

関連ドキュメント

人間が検討すべき事項

TODO_future.md から転記:

  • 再計算ツールの実行タイミング: Action A 前後での自動呼び出し / 手動メニュー実行のみ / 月次バッチ自動実行のいずれを採用するか。本仕様書ではまず 手動メニュー実行のみ とし、運用後の頻度を見て自動化を検討する。
  • 超過紐付けの判定閾値: 完全一致(±0 円)で検出するか、税込端数を許容するか。本仕様書では Math.abs(diff) > 0.01 を採用(浮動小数点誤差のみ許容、業務ズレは即検知)。

追加の検討事項:

  • 再計算ツールのプレビュー表示: 現在は確認ダイアログ → 一括保存の 2 段階フローだが、将来的には「変更予定行の一覧を別タブに書き出し → 人間がレビュー → 承認 → 確定」の 3 段階フロー(Human-in-the-Loop 強化版)への拡張余地がある。検討の際は 99_wrk_ord_balance_diff 等の一時シート方式を参考にできる。
  • 検証項目の閾値カスタマイズ: Math.abs(diff) > 0.01 の閾値を 03_sys_params 経由で外出ししたい場合の設計。現状は定数でハードコードする(YAGNI 原則)が、運用上頻繁に誤検知が発生する場合は Constants.getParam('ORD_BALANCE_TOLERANCE', 0.01) 化を検討。
  • 自動再計算の承認プロセス: 月次バッチ化する場合、自動実行後に差分サマリを Slack / メール通知する仕組みが別途必要になる(MAS-104 支払依頼ワークフローの通知基盤との共通化余地あり)。
  • 検証 (d) の粒度: 「FALSE 化 INV が残高に未反映」を独立項目として検出するか、(c) の副次効果に含めるか。本仕様書では (c) に包含 する設計(実装簡潔・検出抜けなし)とする。

実装プロンプト(Claude Code 用)

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-122「ORD↔INV 消化状況の整合性チェック」を実装してください。

## 実行前タスク
- `000_infra/003_contracts.js` を Read: OrderDTO の `発注残高(自動計算)`・`税込金額_発注`、
  InvoiceDTO の `親発注ID(ORD)`・`税込金額_計画`・`有効フラグ` のプロパティ名を確認。
- `200_data/202_repository.js` を Read: `OrderRepository.findAll()` / `save(dtos)` の
  引数・戻り値・副作用(全件上書き)を確認。`readSheetAsDtos_` は有効フラグを
  フィルタしないことも確認。
- `000_infra/004_utils.js` を Read: `Utils.parseAmt()` / `Utils.auditLog()` /
  `Utils.logInfo()` の使い方を確認。
- `000_infra/002_constants.js` を Read: `Constants.COLORS.WARN_RED_BG` /
  `Constants.COLORS.WARN_RED_FC` の値を確認。
- `200_data/201_data_validator.js` を Read: 既存の公開関数は `runDataValidation`、
  シート別バリデーションは `validateOrder_` / `validateInvoice_`。
  `setErr_` / `applyValidationResults_` / `buildHeaderIndex_` のパターンに従うこと。
- `900_test/901_test_runner.js` を Read: 末尾テストは `testT11_Utils_`。
  新規は T12 として追加し `runAllTests()` 末尾に `try/catch` 付きで登録する。
- `templates/operations_sidebar.html` を Read: `🔧 マイグレーション` セクション
  (L89 `<h3>🔧 マイグレーション</h3>` 直下)にボタンを 1 行追加する。
- `ls 800_ops/` で既存最大番号(808)を確認。新規ファイルは `813_recalc_ord_balance.js`
  を使用する(809〜812 は MAS-119/MAS-120/MAS-121/MAS-135 が予約済みのため衝突回避)。

## 修正対象ファイル
- `200_data/201_data_validator.js`(整合性チェック関数の追加+`runDataValidation` に組込)
- `900_test/901_test_runner.js`(T12 テストケースの追加+`runAllTests()` への登録)
- `800_ops/813_recalc_ord_balance.js`(新規作成。`recalcOrderBalance()` 関数)
- `templates/operations_sidebar.html`(🔧 マイグレーション セクションに 1 ボタン追加)

## 実装内容
修正方針 Step 1〜3 の手順に従い実装する。
Step 1: `validateOrderInvoiceConsistency_(ordResult, invResult)` を
`200_data/201_data_validator.js` に追加し、(a)〜(d) の 4 検証項目を実装する。
Step 2: `runDataValidation` の `WRK_ORDR` / `WRK_INVC` 処理後のタイミングで
上記関数を呼び、不整合 ORD 行・孤立 INV 行に `Constants.COLORS.WARN_RED_BG` を
設定する。テストランナーに T12 を追加。
Step 3: `800_ops/813_recalc_ord_balance.js` を新規作成し、
`LockService.tryLock(30000)` + 確認ダイアログ + `OrderRepository.findAll/save` +
`Utils.auditLog('MIGRATE', ...)` を実装。`templates/operations_sidebar.html` に
「発注残高を再計算する」ボタンを追加する。

## 制約
- 列番号のハードコード禁止。ヘッダー名ベースで参照する(DTO プロパティ名)。
- `OrderRepository.save()` は全件上書きのため、意図しないデータ消失に注意する。
  必ず `findAll()` → DTO 更新 → `save()` の順で実行すること。
- 有効フラグ判定は `=== false || String(x).toUpperCase() === 'FALSE'` を統一使用する。
- `readSheetAsDtos_` はフィルタしないため、業務ロジック側で有効フラグをチェック。
- メニュー名・関数名は Read で確認した実在する文字列のみ使用する。造語禁止。
- プロパティ名は `税込金額_発注`(OrderDTO)・`税込金額_計画`(InvoiceDTO)・
  `発注残高(自動計算)`(OrderDTO)・`親発注ID(ORD)`(InvoiceDTO)を正確に使用する。
- 許容誤差は `Math.abs(diff) > 0.01` で判定する(浮動小数点誤差回避)。
- `recalcOrderBalance` は必ず `try/catch/finally { lock.releaseLock(); }` で
  排他制御を解放する。

## エッジケース
- `税込金額_計画` がマイナス(返金 INV): 符号そのまま加算、`Math.abs(diff) > 0.01`
- `有効フラグ` が false/FALSE/空白: 全処理スキップ(統一判定)
- 1 ORD に INV 0 件: `invByOrd.get(ordId) || []` + `reduce((a,b)=>a+b, 0)` で NaN 防止
- 浮動小数点誤差 (0.00001 円等): `Math.abs(diff) > 0.01` で無視
- 親 ORD 不在の孤立 INV: 検証 (a) で検出、INV 行を WARN_RED
- `発注残高(自動計算)` 空白/非数値: `Utils.parseAmt` が 0 を返す、再計算ツールで上書き
- `親発注ID(ORD)` が空: 単独起票と見なし検証対象外
- ORD=FALSE / INV=TRUE の不整合: 検証 (a) で自動検知(`ordIdSet` は有効ORDのみ)
- `recalcOrderBalance` 実行中の編集競合: `LockService.tryLock(30000)` で防止
- `save()` 失敗時: `try/catch/finally` で `releaseLock()` 保証

## 動作確認
1. `npm run push:dev` でデプロイ
2. GAS エディタから `runDataValidation` を手動実行し、検証 (a)〜(d) の結果を
   セルハイライトと `Utils.logInfo` 出力で確認
3. 意図的に不整合なテストデータ(`32_wrk_invoice` で存在しない `親発注ID(ORD)` 設定、
   `有効フラグ=FALSE` 化等)を用意し、WARN_RED ハイライトが正しく行われることを確認
4. サイドバー「🧪 テスト」→「全テスト実行」で T12 含む全ケースを実行し
   `90_test_results` で PASS を確認
5. サイドバー「🔧 マイグレーション」→「発注残高を再計算する」を実行し、
   `31_wrk_order` の `発注残高(自動計算)` 列が正しく更新されることを確認
6. 再実行して値が変わらないこと(冪等性)を確認
7. `98_audit_log` に `MIGRATE` ログが記録されていることを確認

### 拡張思考の使用状況
| フェーズ | 拡張思考 | 備考 |
|---------|---------|------|
| Phase 1(調査) | あり | ファイル読み込み・固有名詞確定 |
| Phase 2(実装) | なし | 調査結果の書き下しに徹する |

推奨実行モデル

ステップ推奨モデル理由
Step 1(整合性検証ロジック開発)Sonnet複数ファイル横断の既存パターン適用・中程度の判断が必要(DTO・Repository・Utils の連携)
Step 2(テスト・バリデーター組込)SonnetrunDataValidation / runAllTests への注入位置の特定、既存の色分けメモパターンへの追従が必要
Step 3(再計算ツール・メニュー追加)SonnetLockService + auditLog + 確認ダイアログの既存マイグレーション(807_migration_i10.js 等)パターン適用、サイドバー HTML への追記

本案件は仕様書で判断要素をすべて確定しているが、既存コードベース横断での注入位置特定・既存パターン踏襲の判断が必要なため、全ステップで Sonnet を推奨する。

変更履歴

日時変更内容
2026-04-19初版作成。ORD↔INV 整合性チェック仕様書。検証 (a)〜(d) の 4 項目と 800_ops/813_recalc_ord_balance.js 強制再計算ツールを規定

仕様書作成プロンプト

展開して表示
<instruction>
【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】

1. **拡張思考の使い分け**:
   - Phase 1(設計)では拡張思考をフル活用し、ファイル名形式・エッジケース一覧・
     Step 分割粒度・固有名詞(関数名/シート名/列名/行番号)を完全に確定させる。
   - Phase 2(清書)の各 Step 内では拡張思考を最小限に抑え、Phase 1 で確定済みの
     内容の書き下しに徹する。出力途中で再考しない。

2. **テキスト報告の禁止**:
   - 「〜を作成します」等の text のみで tool_use なしに turn を終了しない。
   - 説明は 1 文以内。直ちに tool を呼ぶ。

3. **4-5 分割の Write/Edit 実行**:
   - 仕様書作成は以下の Step に分けて実行する:
     - 2-1 骨格 Write(~20行)
     - 2-2 概要〜注意事項 Edit/Bash(~300行)
     - 2-3a エッジケース〜人間検討事項 Edit/Bash(~200行)
     - 2-3b 実装プロンプト〜変更履歴 Edit/Bash(~250行)
     - 2-4 `<details>` にプロンプト全文記録 Edit/Bash(最重量・必ず独立 Step)
   - 1 回の Write/Edit は約 300 行以内を目安にする。

4. **各 Step で何を書くかを具体指示**:
   - 設計判断を Phase 2 実行時に持ち込まないよう、各 Step の内容を
     Phase 1 で完全に確定してから清書に進む。再考は Phase 1 で完結させる。

======================================================================
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者兼仕様書ライターです。
CLIエージェント「Claude Code」として、案件 S-50「ORD↔INV 消化状況の整合性チェック」の開発仕様書を作成してください。

**Grep は「どこにあるか」の発見まで。「どう書くか」の判断は必ず Read で行う。推測・造語禁止。**

---

## Phase 1: 実行前タスク(テキスト報告禁止。即座にツール実行)

以下を全てツールで調査し、Phase 2 に必要な固有名詞・構造・番号を確定させること。

1. **案件要件の読み込み**(Read/Grep: `docs/_internal/TODO_future.md`)
   - S-50 の案件名・概要・人間が検討すべき事項を取得する。
   - 4つの検証項目 (a)〜(d) の具体的な定義を把握する。

2. **DTO プロパティ名の確認**(Read: `000_infra/003_contracts.js`)
   - `OrderDTO` の全プロパティ名(特に `発注残高(自動計算)`・`税込金額_発注`・`有効フラグ`)
   - `InvoiceDTO` の全プロパティ名(特に `親発注ID(ORD)`・`税込金額_計画`・`未決済残高(自動計算)`・`有効フラグ`)
   - プロパティ名に `_発注` / `_計画` 等のサフィックスがある場合は正確に記録する(`税込金額` と略称しない)。

3. **Repository 利用方法の確認**(Read: `200_data/202_repository.js`)
   - `OrderRepository.findAll()` の戻り値の型(`{ headers, dtos }` の構造)
   - `OrderRepository.save(dtos)` の引数・副作用(全件上書きであることを確認)
   - `InvoiceRepository.findAll()` の戻り値の型
   - `readSheetAsDtos_` は有効フラグでフィルタしないことを確認する(業務ロジック側でフィルタが必要)。

4. **Utils の確認**(Read: `000_infra/004_utils.js`)
   - `Utils.parseAmt(val)` の引数・戻り値の型(number を返すことを確認)

5. **既存バリデーターの確認**(Read: `200_data/201_data_validator.js`)
   - 公開関数名(`validateAll` 等)を実際のコードから確認する。仮定で記述しない。
   - 不整合行に `Constants.COLORS.WARN_RED_BG` / `Constants.COLORS.WARN_RED_FC` を適用している既存パターンがあれば把握する。

6. **既存テストの追加パターン確認**(Read: `900_test/901_test_runner.js`)
   - テストケースの追加方法(関数定義の形式・登録方法)を把握する。

7. **メニュー名の確認**(Read: `100_config/101_sys_config.js` の `onOpen()` 付近)
   - 再計算ツールを追加すべき実在するメニュー名を確認する。造語・推測禁止。

8. **800_ops の次の空き番号を確認**(Bash: `ls 800_ops/` )
   - 既存ファイルの最大番号を確認し、809〜の空き番号を特定する。

---

## Phase 2: 仕様書の分割作成

出力先: `docs/dev/dev_mas-122_ord_inv_consistency.md`

**【重要】1 回のツール呼び出しで全内容を出力しない。以下の Step に必ず分割すること。**

### Step 2-1: 骨格の作成(Write, ~20行)

見出しのみ・本文空でよい。以下の全セクションを含めること(省略)

### Step 2-2〜2-4: 詳細追記(省略、本仕様書本文参照)

---

## Phase 3: 後処理(3ステップ全て実行)

### 3-A: `docs/_config.json` への登録(必須)
### 3-B: `docs/_internal/changelog.md` への追記
### 3-C: コミット&プッシュ
</instruction>