概要

項目内容
案件IDMAS-017
カテゴリFP&A・シミュレーション
PhaseP3
優先度
実装ステータス📝 仕様書段階・実装未着手 (2026-04-28 監査時点)
対象ファイル000_infra/004_utils.jsUtils.calculateLoanSchedule() 新規追加)
000_infra/002_constants.jsMENU_DEFINITION にメニュー 1 項目追加)
600_report/611_service_funding_simulation.js(新規・シミュレーション本体 + 94_sim_funding 動的生成)
CLAUDE.md(「DDL (setupAllSchemas) で管理されないタブ」リストに 94_sim_funding を追記)
前提案件MAS-008(資金繰り予測の高度化 / Cash Runway・ベース cashEnd[] を再利用する想定。ただし MAS-008 未実装時は dmCalcCf_() が生成する既存 ctx.cashEnd を直接参照する)

目的

資金ショート回避のために「いつ・いくら」の資金調達が必要かを複数シナリオで逆算・比較できるシミュレーション機能を追加する。

  • エクイティ調達(増資)・デット調達(借入)の 2 系統の調達手段を対象とし、シナリオごとに「調達時期・調達額・年利・返済条件」を入力すると、ベース資金繰り(dmCalcCf_() の月次キャッシュ推移)に対して調達インパクトを重ね合わせた予測を 94_sim_funding シートに出力する。
  • シナリオは横並びで比較可能とし、各シナリオの「最小月末現預金(最悪月)」「ランウェイ改善幅」「通期支払利息」「期末借入金残高」等のサマリー指標を一目で比較できるようにする。
  • 本機能はあくまで意思決定支援ツールであり、シミュレーション結果を 32_wrk_invoice / 42_trn_journal / 41_trn_budget / 24_bud_capex 等の実績・予算データに自動反映する機能はスコープ外とする(Human-in-the-Loop の原則)。

現在のコード

新機能のため本案件の「現在のコード」は存在しない。以下は実装時に参照する既存実装・データ構造であり、Phase 1 調査で裏取り済。

ベース資金繰り計算 dmCalcCf_(ctx)600_report/605_datamart_cf.js L12-34

dmCalcCf_(ctx) はマート生成パイプラインの中で ctx に以下を書き込む(本案件の上乗せ計算の土台として参照):

プロパティ備考
ctx.cfOp[0..12]number[13]営業CF月別(index 0 = 通期Total、1-12 = 月別)
ctx.cfInv[0..12]number[13]投資CF月別
ctx.cfFin[0..12]number[13]財務CF月別(本案件の調達インパクトはこの系譜に加算する)
ctx.cfNet[0..12]number[13]ネットCF月別
ctx.cashStart[0..12]number[13]各月の期首現預金残高
ctx.cashEnd[0..12]number[13]各月の期末現預金残高(B/S 現預金と完全一致)
ctx.targetMonths[0..11]string[12]'YYYY-MM' 配列(startYear-07startYear+1-06

MAS-008 仕様書(docs/dev/dev_mas-008_cash_runway.md)で示された dmCalcCashRunway_(ctx)2026-04-21 時点で未実装605_datamart_cf.jsdmCalcCashRunway_ という関数は存在しない)。したがって本案件では MAS-008 実装を待たず、ctx.cashEnd[] を直接再利用して調達シナリオの上乗せ計算を行う。MAS-008 実装後は ctx.burnRate[] / ctx.runway[] も再利用できるよう、本案件の計算は純粋関数として切り出す。

Constants.getParam(key, defaultVal)03_sys_params 読込

000_infra/002_constants.js L146-167。03_sys_params シートからパラメータを読み込む既存ヘルパー。本案件でも「デフォルト年利・デフォルト返済期間」等のシナリオ初期値を 03_sys_params 化する場合に使用する。

Utils.parseDateToYm / Utils.addMonths — 日付処理

000_infra/004_utils.js L92-99 / L127-132。シナリオ入力の「調達予定年月」正規化と、返済スケジュール生成時の月次加算に使用する。

関数引数戻り値
Utils.parseDateToYm(val)Date / 'YYYY-MM' / 'YYYY/MM' / 'YYYY年MM月''YYYY-MM' 文字列、パース不可なら ''
Utils.addMonths(ymStr, months)'YYYY-MM' 文字列 + 整数(正負可)'YYYY-MM' 文字列

Utils.calculateLoanSchedule()現時点では存在しない(本案件で新規追加)

Phase 1 で 000_infra/004_utils.js を Read した結果、返済スケジュール生成ユーティリティは未実装。本案件で新規追加する。

予算データ 41_trn_budget / CAPEX データ 24_bud_capex へのアクセス

Phase 1 で 200_data/202_repository.js を Read した結果、実在する Repository は OrderRepository (L107) / InvoiceRepository (L152) / BankTxRepository (L214) / JournalRepository (L259) / AccountRepository (L304) / PartnerRepository (L356) の 6 種のみ。BudgetRepository / CapexRepository は存在しない

予算シート・CAPEX シートへのアクセスは、既存マート生成コード 600_report/602_datamart_main.js L181 と同じパターン(Utils.getSheetByKey('TRN_BUDG', '41_trn_budget') で取得)を使う。ただし本案件はベース資金繰り ctx.cashEnd[] の再利用で十分であり、予算・CAPEX シートを直接読む必要はない(ベース CF 計算の中で既に反映済み)。

93_kpi_dashboard パターン — 動的生成シートの先例

100_config/101_sys_config.js L813 で KPI_DASH / 93_kpi_dashboard01_sys_config に登録されるのみで、schemas 辞書には登録されていない(DDL 管理外の動的生成タブ)。本案件の 94_sim_funding も同パターンに倣う。

修正方針

アーキテクチャ

[メニュー: 📋 サイドバー: 📊 マート更新 > 💰 資金調達シミュレーション]
       │
       ▼
[runFundingSimulation()] ← 600_report/611_service_funding_simulation.js (新規)
       │
       ├─▶ [dmCalcCf_() を用いたベース ctx 構築]  ← 既存 602_datamart_main.js を再利用
       │      └─▶ ctx.cashEnd[] / ctx.cfFin[] / ctx.targetMonths[]
       │
       ├─▶ [94_sim_funding シートからシナリオ入力読込]
       │      └─▶ A:G 列(ヘッダー+シナリオ行・最大 10 行)
       │
       ├─▶ [各シナリオの上乗せ計算]
       │      ├─▶ Utils.calculateLoanSchedule()  ← 000_infra/004_utils.js 新規
       │      └─▶ シナリオ別の {月末現預金[], 調達CF[], 支払利息[], 借入残高[]}
       │
       └─▶ [94_sim_funding シートの I 列以降にサマリー+月次推移を書き込み]

新規シート 94_sim_funding

  • 管理方針: CLAUDE.md「DDL (setupAllSchemas) で管理されないタブ」の 93_kpi_dashboard パターンに倣い、DDL 管理外とする。100_config/101_sys_config.jsschemas 辞書には登録しない。01_sys_config への登録(SIM_FUND キー)のみ行う(MAS-011〜MAS-013 の 94_sim_* と同じ運用)。
  • 生成タイミング: メニュー実行時に ss.getSheetByName('94_sim_funding') || ss.insertSheet('94_sim_funding') で取得。入力エリア(A:G 列)はユーザー編集を尊重して温存し、結果エリア(I 列以降)のみ getRange(...).clearContent() → 再書き込みする。
  • レイアウト: 左右 2 分割。
    • 入力エリア(A〜G 列・ヘッダー 1 行 + シナリオ最大 10 行):

      ヘッダー名備考
      Aシナリオ名string任意テキスト。空行はスキップ
      B調達予定年月string (YYYY-MM)Utils.parseDateToYm() で正規化
      C調達手段string (エクイティ / デット)プルダウン候補。それ以外はエラー
      D調達額 (税抜)number円単位。整数
      E年利 (%)numberデット時のみ使用。0 以上
      F返済期間 (月)numberデット時のみ使用。1 以上
      G返済方式string (元利均等 / 元金均等)デット時のみ使用
    • 結果エリア(I 列以降):

      • サマリーブロック(I:P・シナリオ横並び): ベースライン+各シナリオの列を並べ、以下の行を出力。
        1. 最小月末現預金(最悪月の cashEnd
        2. 最小月末現預金 発生月(YYYY-MM
        3. 資金ショート月数(cashEnd <= 0 の月数)
        4. 通期支払利息(デット時のみ。エクイティは 0)
        5. 期末借入金残高(12 月末時点)
        6. 調達時期から通期末までの月数
      • 月次推移ブロック(サマリーの下・13 列 × シナリオ数): ベースライン+各シナリオの cashEnd[1..12] を月別に並べ、最小値セルを条件付き書式で赤色ハイライト(実装は SpreadsheetApp の標準 API)。

シミュレーション計算ロジック

  1. ベース取得: 既存マート生成関数 dmCalcCf_() を経由して得られる ctx.cashEnd[] / ctx.cfFin[] / ctx.targetMonths[] をコピーする(シミュレーションで書き戻さない)。
  2. エクイティ上乗せ: 調達月以降の全月に対して cashEnd_new[i] = cashEnd_base[i] + 調達額 を加算。B/S への影響(資本金増加)は出力表の注記行に計上するのみ。
  3. デット上乗せ:
    • Utils.calculateLoanSchedule(principal, annualRate, periodsInMonths, type) を呼び出して月別返済スケジュール [{ ym, principal, interest, balance }] を取得。
    • 調達月に +principal をキャッシュインとして加算。
    • 返済月ごとに -(principal + interest) をキャッシュアウトとして加算。
    • 支払利息の累計を シナリオ.通期支払利息 に集計。
    • 期末借入金残高(12 月末時点)をサマリーに計上。
  4. 全計算はインメモリ完結: 94_sim_funding 以外のシートへの書き込みは厳禁。

新規関数 Utils.calculateLoanSchedule()

000_infra/004_utils.js に以下のシグネチャで追加する:

/**
 * F-17: 借入金の月次返済スケジュールを計算
 * @param {number} principal        - 借入元本(円・正値)
 * @param {number} annualRate       - 年利(例: 0.03 = 3%)。0 以上
 * @param {number} periodsInMonths  - 返済期間(月)。1 以上の整数
 * @param {string} type             - '元利均等' or '元金均等'
 * @returns {Array<{monthIndex:number, principalPay:number, interestPay:number, balance:number}>}
 *   - monthIndex: 0-based(0 = 調達直後、1 = 初回返済月)
 *   - principalPay: その月の元本返済額
 *   - interestPay:  その月の支払利息
 *   - balance: 月末残高(最終月で 0)
 */
Utils.calculateLoanSchedule = function(principal, annualRate, periodsInMonths, type) { ... }
  • periodsInMonths <= 0 / principal <= 0 / annualRate < 0 の場合は空配列 [] を返す(呼び出し側でシナリオ全体をエラー扱い)。
  • 元利均等: 月利 r = annualRate/12、月次返済額 A = principal * r * (1+r)^n / ((1+r)^n - 1) で計算。r = 0 のときは A = principal/n
  • 元金均等: 月次元本 P = principal/n、月利息 interest = 残高 * r

メニュー登録

000_infra/002_constants.jsMENU_DEFINITION 配列 L229-239「📋 サイドバー: 📊 マート更新」カテゴリの末尾に以下を追加(MAS-012「🧮 人員計画シミュレーション」と同じ追加位置パターン):

{ label: '💰 資金調達シミュレーション', funcName: 'runFundingSimulation', description: 'エクイティ/デット調達シナリオを比較し 94_sim_funding に出力' },

メニュー名 📋 サイドバー: 📊 マート更新000_infra/002_constants.js L230 の実在カテゴリ名。存在しないメニュー名(📊 FP&Aツール 等)をコードに書かない(失敗パターン #18-#20 対策)。

データ取得

  • JournalRepository.findAll() の戻り値は { headers, dtos } オブジェクト。フィルタは result.dtos.filter(...) で行う(200_data/202_repository.js L259 の readSheetAsDtos_ に委譲)。本案件では直接呼ぶ必要はなく、dmCalcCf_() 経由で ctx に反映済み。
  • InvoiceRepository.findAll() も同じく { headers, dtos } オブジェクト。
  • BudgetRepository / CapexRepository202_repository.js に存在しないため呼び出さない。予算・CAPEX データは dmCalcCf_() のベース計算経由で取り込まれる。

二重計上防止

94_sim_funding 以外のシート(32_wrk_invoice42_trn_journal41_trn_budget24_bud_capex81_cf_indirect 等)への書き込みは一切禁止。シミュレーション結果は実績データマートに混入させない(601_datamart_ingest.js 等を呼び出さない)。

影響範囲

変更対象変更内容変更量
000_infra/004_utils.jsUtils.calculateLoanSchedule() 新規追加+40行
000_infra/002_constants.jsMENU_DEFINITION に 1 項目追加+1行
600_report/611_service_funding_simulation.js新規ファイル(runFundingSimulation 本体 + 94_sim_funding 動的生成)+350行
100_config/101_sys_config.js01_sys_config への SIM_FUND キー登録+1行
CLAUDE.md「DDL (setupAllSchemas) で管理されないタブ」リストに 94_sim_funding を追記+1行
  • 既存動作への影響なし: 本案件は「読み取り専用 + 94_sim_funding への書き込みのみ」。dmCalcCf_() を読み取りモードで利用し、ctx.cashEnd[] 等のコピーを生成する純粋関数として実装
  • DDL への影響なし: 94_sim_funding は DDL 管理外(schemas 辞書に追加しない)
  • 既存 Repository への影響なし: BudgetRepository / CapexRepository は新設しない(存在しない Repository の呼び出しを避ける)

注意事項

  1. BudgetRepository / CapexRepository は存在しない: Phase 1 で 200_data/202_repository.js を Read した結果、この 2 つは未実装。予算・CAPEX データへのアクセスは dmCalcCf_() のベース計算経由で反映済みのため、本案件では直接シート読込を行わない。どうしても必要な場合は 600_report/602_datamart_main.js L181 と同じ Utils.getSheetByKey('TRN_BUDG', '41_trn_budget') パターンを使う(BudgetRepository.findAll() 等の未実装メソッド名を絶対に書かない)。
  2. Utils.calculateLoanSchedule() は新規追加関数: 000_infra/004_utils.js 既存の parseDateToYm / addMonths 等と命名規則を合わせる(関数名は camelCase、_ サフィックスは内部ヘルパー専用)。
  3. 94_sim_funding は DDL 管理外: CLAUDE.md「DDL (setupAllSchemas) で管理されないタブ」の 93_kpi_dashboard と同じ動的生成パターン。100_config/101_sys_config.jsschemas 辞書には追加しない。01_sys_config の登録行(L813 近傍)にはキー SIM_FUND を追加する。
  4. 実績データマートへの混入禁止: シミュレーション結果は 601_datamart_ingest.js / 602_datamart_main.js 等を呼び出さない。94_sim_funding への書き込みのみ。
  5. 日付・年月の比較は必ず Utils.parseDateToYm()YYYY-MM 正規化: String(Date) による比較や独自パースは禁止(失敗パターン #18-#20 対策)。
  6. MAS-008 実装有無に依存しない: ctx.burnRate / ctx.runway は MAS-008 実装後にしか存在しない。本案件では ctx.cashEnd[] のみを必須依存とし、MAS-008 指標は「存在すれば参照・なければスキップ」の防御的アクセスとする。
  7. 入力エリア保護: A:G 列(ユーザー入力)は clearContent() の対象外。結果エリア I 列以降 のみクリア&再書き込みする。
  8. メニューカテゴリ名の実在確認: 📋 サイドバー: 📊 マート更新000_infra/002_constants.js L230 の実在カテゴリ名。他のカテゴリ名を造語しない。
  9. JournalRepository.findAll() / InvoiceRepository.findAll() の戻り値型: 配列ではなく { headers: string[], dtos: object[] } オブジェクト。必要時は必ず result.dtos.filter(...) でアクセスする。
  10. 行番号ハードコード禁止: 結果エリアの書き込み位置はサマリーブロックを I2 起点とし、月次推移ブロックはサマリーの最終行 + 2 行下からスタートする等、コード内の定数で管理する。マジックナンバーをスプレッド全体に散らさない。

エッジケース

#条件表示値・動作理由
1調達額 <= 0そのシナリオをスキップし、結果サマリー注記列に「入力値エラー: {シナリオ名} / 調達額」と出力計算不能な入力を除外。他シナリオの処理は継続
2年利 < 0(デット時)そのシナリオをスキップし「入力値エラー: {シナリオ名} / 年利」と注記負の利率は実務で想定外。サイレント通過を防止
3返済期間 = 0 ヶ月(ゼロ除算リスク)Utils.calculateLoanSchedule() 内で事前ガード(空配列 [] を返す)。シナリオ全体をエラー扱いゼロ除算防止。principal/nn=0(1+r)^n-1=0 を起こさせない
4返済期間 < 0(負値)上記と同様にスキップ・エラー注記入力値エラーとして扱う
5調達予定年月が実行日より過去(Utils.parseDateToYm(today) より小さい)計算を実行せず「過去年月は指定不可: {シナリオ名}」と結果エリアに出力意味のないシミュレーション防止
6調達予定年月が ctx.targetMonths[] の範囲外(通期末 +1 ヶ月以降)計算は実行するが「調達月が通期範囲外のため当期 CF には反映されない」注記を出力翌期以降の調達計画も許容しつつ、当期サマリーは 0 インパクト
7エクイティ調達で E 列(年利)・F 列(返済期間)・G 列(返済方式)が入力されている当該フィールドを無視してエクイティとして処理。結果エリアに「エクイティ調達のため年利・返済期間は無視しました: {シナリオ名}」注記入力ミスのサイレント通過を防止
8デット調達で E 列(年利)空・F 列(返済期間)空デフォルト値 0% / 12 ヶ月 で計算し注記(※ 03_sys_paramsFUND_DEFAULT_RATE / FUND_DEFAULT_PERIOD があればそちらを優先)後続入力フローを止めない運用デフォルト
9返済方式(G 列)が 元利均等 / 元金均等 のいずれでもない元利均等 にフォールバックし注記「返済方式を元利均等に補正: {シナリオ名}」タイポ・全角スペース混入等のサイレント通過を防止
10シナリオ名(A 列)が空その行を「空行」とみなし、以降の行も走査打切り(連続空行で終了)ヘッダー行+シナリオ行の有限テーブル構造を維持
11シナリオ名(A 列)が重複後から定義(テーブル下方)のシナリオで上書き。重複件数を結果サマリー注記に記載ユーザーが誤って同名を登録した場合の安全動作
12全シナリオがエラー(有効シナリオ 0 件)結果エリアに「有効なシナリオが 0 件です。入力エリア (A:G) を確認してください」と表示し、サマリーブロック・月次推移ブロックは出力しない空の結果シートを生成しない
13ベース ctx.cashEnd[] がすべて 0(JournalRepository.findAll() でデータ 0 件の初期環境)ベース資金繰りを 0 として計算し、サマリーの先頭に「⚠️ ベース CF が 0: 実績データが未登録の可能性」警告を出力初期設定時・dev 環境での動作確保
14月利 r = annualRate/12 = 0(無利子借入)元利均等A = principal/n で計算、元金均等interest = 0 固定ゼロ除算((1+0)^n - 1 = 0)の回避
15シナリオ調達額が過大で全月プラス化正常に計算継続。最小月末現預金 = 全月中の最小値(調達後でも最も低い月)過大調達もユーザー判断で許容
16返済期間が通期(12 ヶ月)を超える通期末までの返済分のみ上乗せ計算し、期末借入金残高 = 残元本をサマリーに表示翌期以降の返済は本案件スコープ外。サマリーで残債を明示
17シナリオ行数が 10 を超える先頭 10 件のみ処理し、11 件目以降は「行数上限超過: {件数} 件をスキップ」と注記シート幅・処理時間の安定性確保。上限は MAX_SCENARIOS 定数で定義

実データ検証

実装前に MCP 等で以下を確認する。

#確認項目確認方法想定結果
141_trn_budget シートの実際の列構成が 003_contracts.jsBudgetDTO と一致しているかMCP でシートヘッダー取得、003_contracts.js L131-149 と突合列名が完全一致(本案件では直接読み込まないが、MAS-018 等の後続案件のため事前確認)
203_sys_params に資金繰り計算関連パラメータ(FUND_DEFAULT_RATE / FUND_DEFAULT_PERIOD 等)が登録されているか03_sys_params シートを MCP で読み取り、Constants.getParam() で取得できる値を確認未登録でも良い(デフォルト値でフォールバック)。登録時はシナリオのデフォルト入力値として活用
394_sim_funding というシート名が既存のスプレッドシートに存在しないかMCP でシート一覧を取得存在する場合は上書き方針(入力エリア温存・結果エリアのみクリア)に従う。存在しない場合は insertSheet() で新規作成
401_sys_configSIM_FUND キーが登録されているかMCP で 01_sys_config の A 列を確認未登録の場合は setupAllSchemas() 実行時に confSheet.appendRow(['SIM_FUND', '', '94_sim_funding', '資金調達シミュレーション']) を追加
5600_report/602_datamart_main.jsdmCalcCf_() が ctx に cashEnd[0..12] を確実に書き込んでいるか該当コード Read(L12-34)ctx.cashEnd = cashEnd; で書込済み(L33)。本案件から ctx.cashEnd を読むのは安全

関連ドキュメント

仕様書関連箇所
dev_mas-008_cash_runway.mdベース cashEnd[] / cfOp[] / バーンレート / ランウェイ概念。本案件は MAS-008 の発展版
dev_mas-012_headcount_simulation.md94_sim_* 命名規則・DDL 管理外シートの生成パターン・メニュー追加位置の先例
dev_mas-013_investment_simulation.mdFP&A シミュレーション全般のテンプレート(NPV/IRR 計算エンジン設計・動的上書き型シート)
dev_mas-011_what_if_simulation.mdWhat-if シミュレーションの既存設計思想(インメモリ完結・Human-in-the-Loop)
dev_mas-001_variance_analysis.mdFP&A マート拡張の実装パターン(参考)
spec/spec_cf.mdCF(間接法)の既存仕様。cashEnd[] の定義元
CLAUDE.mdコーディング規約・ファイル番号体系(600_report/ 配下の番号割当)・DDL 管理外タブ一覧
failure_patterns.md#2(ゼロ除算)・#18-#20(固有名詞 Read 裏取り)・存在しない Repository 名呼び出し

人間が検討すべき事項

#項目詳細
1調達手段の選択肢拡張TODO_future.md 上の MAS-017 案件では「調達手段の選択肢(エクイティ/デット/助成金等)」が人間検討事項として明記されている。本仕様ではエクイティ・デットの 2 系統に限定。助成金(返済不要・一時キャッシュインのみ)・社債・ストックオプション・転換社債(CB)等の扱いは後続案件で検討
2シミュレーション結果の自動反映の可否本機能はあくまで意思決定支援ツール。シミュレーション結果を 24_bud_capex_loan / 41_trn_budget 等に自動書き戻す機能は本案件スコープ外。採用決定後の予算化フローは Human-in-the-Loop で別途運用する
3B/S インパクト表現の UIエクイティ(資本金増加)とデット(借入金増加)の B/S インパクトの違いをユーザーが直感的に理解できる UI 表現(科目別のサブマリー・積み上げ棒グラフ等)が必要か検討する
4返済方式のガイドテキスト元利均等(毎月同額)と 元金均等(毎月元本同額・初期利息大)の違いをユーザーに説明するガイドテキストを入力エリア上部に注記する必要があるか検討
5Utils.calculateLoanSchedule() の汎用利用本関数を 004_utils.js に追加することで、CAPEX 借入金(24_bud_capex_loan)の返済スケジュール計算(現行は 403_rpa_capex.js で独自実装)との統合も可能。MAS-017 完了後に 403_rpa_capex.js をリファクタする案件を起票するかを運用で判断
6調達タイミングの粒度本仕様では YYYY-MM の月単位。日次粒度(入金日の細かい時期合わせ)は 84_cf_daily_plan との統合時に再検討(MAS-008 拡張の日次ランウェイ相当)
7複数シナリオの組み合わせ現状は各シナリオが独立(横並び比較)。「エクイティ 1 億 + 1 年後にデット 5000 万」のようなシナリオ内の複数調達イベントは未対応。必要性を運用で確認
8ランウェイとの統合表示MAS-008(Cash Runway)実装後は、各シナリオのランウェイ改善幅(調達前 N ヶ月 → 調達後 M ヶ月)を追加表示可能。MAS-008 完了後に仕様追記を検討
9税引後キャッシュフロー影響支払利息は損金算入で税負担を減らす効果がある。厳密には税引後 CF で比較すべきだが、本案件では税引前で簡略化。必要性を Constants.TAX_RATES と合わせて検討
1003_sys_params 化の対象MAX_SCENARIOS (シナリオ行数上限) / FUND_DEFAULT_RATE / FUND_DEFAULT_PERIOD03_sys_params 化するか、コード定数のままにするかを運用開始後に判断

実装プロンプト

【タイムアウト回避・実行原則(v1.7)】
1. Phase 1(設計)では拡張思考フル活用・Read で裏取り。Phase 2(清書)の各 Step は最小限思考で書き下し。
2. 「〜作成します」等の text のみで tool_use なしに turn 終了しない。
3. 実装は 骨格 Write → 追記 Edit/Bash を分割実行。1 回あたり ~300 行以内。
4. 各 Step で書く内容を事前に洗い出してから tool_use へ進む。

あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-017「資金調達シミュレーション」を実装してください。

## 実行前タスク

以下のファイルを Read し、既存パターンを把握してください:

- `docs/dev/dev_mas-017_funding_simulation.md` — 本仕様書(修正方針・エッジケース・注意事項を全て読む)
- `200_data/202_repository.js` — `JournalRepository.findAll()`(L259-272)・`InvoiceRepository.findAll()`(L152-)の戻り値型(`{ headers, dtos }` オブジェクト)を確認
- `000_infra/003_contracts.js` — `BudgetDTO`(L131-149)・`InvoiceDTO`(L38-67)のフィールド名を確認
- `000_infra/004_utils.js` — `parseDateToYm`(L92-99)・`addMonths`(L127-132)のシグネチャを確認。`calculateLoanSchedule` は存在しないことを再確認
- `600_report/605_datamart_cf.js` — `dmCalcCf_(ctx)`(L12-34)で ctx に `cashEnd[0..12]` / `cfFin[0..12]` / `targetMonths[0..11]` が書き込まれる流れを把握
- `600_report/602_datamart_main.js` — `updateDatamartMain()` の構造(L181 の `Utils.getSheetByKey('TRN_BUDG', '41_trn_budget')` パターン)
- `100_config/101_sys_config.js` — `01_sys_config` 登録行(L813 近傍の `KPI_DASH` パターン)と `schemas` 辞書(`93_kpi_dashboard` が未登録の動的生成タブである点を確認)
- `000_infra/002_constants.js` — `MENU_DEFINITION`(L206-324)内「📋 サイドバー: 📊 マート更新」カテゴリ(L229-239)の実在ラベルを確認
- `CLAUDE.md` — 「DDL (setupAllSchemas) で管理されないタブ」リスト。`94_sim_funding` を追記する

## 修正対象ファイル

- `000_infra/004_utils.js` — `Utils.calculateLoanSchedule()` の新規追加のみ
- `000_infra/002_constants.js` — `MENU_DEFINITION` 内「📋 サイドバー: 📊 マート更新」カテゴリの末尾に 1 項目追加
- `600_report/611_service_funding_simulation.js` — 新規ファイル(ファイル番号体系に従い、MAS-013 用の `610_service_investment_analysis.js` の次番号 `611` を採番)
- `100_config/101_sys_config.js` — `01_sys_config` 登録行に `SIM_FUND` キーを 1 行追加
- `CLAUDE.md` — 「DDL (setupAllSchemas) で管理されないタブ」リストに `94_sim_funding` を追記

上記以外のファイル(`202_repository.js`・`003_contracts.js` 等)は変更禁止。

## 実装内容

### Step 1: `Utils.calculateLoanSchedule()` の追加(000_infra/004_utils.js)

`Utils` オブジェクトに以下シグネチャで追加:

    Utils.calculateLoanSchedule = function(principal, annualRate, periodsInMonths, type) {
      // ガード: principal <= 0 / annualRate < 0 / periodsInMonths <= 0 → []
      // 元利均等: 月利 r = annualRate/12、A = principal*r*(1+r)^n/((1+r)^n-1)、r=0 は A=principal/n
      // 元金均等: P = principal/n、interest = 残高*r
      // 戻り値: [{ monthIndex, principalPay, interestPay, balance }, ...]
      // 丸め: Math.round(1 円単位)
    };

### Step 2: `600_report/611_service_funding_simulation.js` の新規作成

以下の関数を公開:

    function runFundingSimulation() {
      // 1) 権限チェック・ログ出力開始
      // 2) ベース ctx 構築(既存 dmCalcCf_() を使って ctx.cashEnd[] / ctx.cfFin[] / ctx.targetMonths[] を生成)
      //    ※ マート生成パイプラインの読み取り専用サブセットを呼び出す
      // 3) 94_sim_funding シート取得 or 新規作成
      // 4) A:G 列からシナリオ読み取り(最大 MAX_SCENARIOS=10 件、空行で打切り)
      // 5) 各シナリオをバリデーション → エラーシナリオは注記列に記録
      // 6) 各有効シナリオについてベース cashEnd[] をコピー → 調達インパクトを上乗せ
      // 7) サマリーブロック(I2: 最小月末現預金・発生月・ショート月数・通期支払利息・期末借入金残高)を書き込み
      // 8) 月次推移ブロック(サマリーの下・13 列 × シナリオ数)を書き込み
      // 9) 条件付き書式で最小月末現預金セルを赤色ハイライト
    }

### Step 3: メニュー追加(000_infra/002_constants.js)

`📋 サイドバー: 📊 マート更新` カテゴリ(L229-239 近傍)の末尾に以下を追加:

    { label: '💰 資金調達シミュレーション', funcName: 'runFundingSimulation', description: 'エクイティ/デット調達シナリオを比較し 94_sim_funding に出力' },

### Step 4: `01_sys_config` 登録(100_config/101_sys_config.js)

`KPI_DASH` 登録行(L813 近傍)の直後に以下を追加:

    if (!existKeys.includes('SIM_FUND')) confSheet.appendRow(['SIM_FUND', '', '94_sim_funding', '資金調達シミュレーション']);

### Step 5: CLAUDE.md への追記

「DDL (setupAllSchemas) で管理されないタブ」セクションに `94_sim_funding` を追記(既存の `93_kpi_dashboard` と並べる)。

## 制約

- `32_wrk_invoice`・`42_trn_journal`・`41_trn_budget`・`24_bud_capex`・`81_cf_indirect` 等の**実績・予算・データマートシートへの書き込み禁止**
- `94_sim_funding` 以外のシートへの書き込み禁止
- **`BudgetRepository`・`CapexRepository` は存在しないため呼び出さない**(`202_repository.js` にないメソッド名をコードに書かない)
- 日付比較は必ず `Utils.parseDateToYm()` で `YYYY-MM` 正規化後に実施(`String(Date)` 比較禁止)
- 列参照はヘッダー名ベース。列番号ハードコード禁止
- メニューカテゴリ名は実在文字列 `📋 サイドバー: 📊 マート更新` を使用(造語禁止)
- `JournalRepository.findAll()` / `InvoiceRepository.findAll()` の戻り値は `{ headers, dtos }` オブジェクト。配列として扱わない

## エッジケース

仕様書「エッジケース」テーブルの全 17 項目に準拠。特に以下を厳守:

- 返済期間 `<= 0` / 調達額 `<= 0` / 年利 `< 0` → `Utils.calculateLoanSchedule` が空配列 `[]` を返しシナリオ全体をエラー扱い
- 月利 `r = 0` の場合は `元利均等` = `principal/n`、`元金均等` = 利息 0 固定(ゼロ除算回避)
- 過去年月 / 範囲外年月 / 空行 / 重複シナリオ名は注記で明示し、サイレント通過させない
- 全シナリオエラー → サマリー・月次推移は出力せず警告メッセージのみ
- ベース `cashEnd[]` すべて 0 → 警告注記を先頭に出力
- シナリオ行数上限 `MAX_SCENARIOS=10`、超過分は注記でスキップ報告

## 動作確認

1. `npm run push:dev` でデプロイ
2. `setupAllSchemas` を実行し `01_sys_config` に `SIM_FUND / 94_sim_funding` が追加されていることを確認
3. スプレッドシートのメニュー `📋 サイドバー: 📊 マート更新 > 💰 資金調達シミュレーション` が表示されることを確認
4. `94_sim_funding` シートの A:G 列にシナリオを 2 件入力(例: `A案 / 2026-07 / エクイティ / 50000000 / - / - / -` と `B案 / 2026-10 / デット / 30000000 / 3 / 60 / 元利均等`)
5. メニュー実行 → I 列以降にサマリー・月次推移が出力されることを確認
6. **検証**: エクイティシナリオで調達月以降の `cashEnd[]` が一律 +50,000,000 円されていること
7. **検証**: デットシナリオで調達月にキャッシュイン、翌月以降に返済キャッシュアウトが計上されていること
8. **検証**: 元利均等の月次返済額が一定、元金均等の月次返済額が逓減していること
9. **エッジケース検証**: シナリオに `返済期間=0` を入れて実行 → エラー注記が出力されシナリオがスキップされることを確認
10. **エッジケース検証**: 調達年月に `2020-01`(過去)を入れて実行 → 「過去年月は指定不可」が出力されることを確認
11. **エッジケース検証**: 全シナリオをエラー入力にして実行 → 「有効なシナリオが 0 件です」が出力されることを確認
12. **回帰確認**: `42_trn_journal` / `32_wrk_invoice` / `41_trn_budget` / `24_bud_capex` / `81_cf_indirect` / `82_cf_indirect_plan` の各シートが変更されていないことを確認
13. **回帰確認**: `updateDatamartMain()` を実行し既存マート(P/L・B/S・CF)に影響がないことを確認

### 拡張思考の使用状況

| フェーズ | 拡張思考 | 備考 |
|---------|:--------:|------|
| 実行前タスク(Read・調査) | あり | データ構造・挿入位置の確定 |
| `Utils.calculateLoanSchedule()` 実装 | なし | 数学式が仕様書で完全定義済み・清書のみ |
| `runFundingSimulation` 実装 | あり | ベース ctx 構築フロー・シート I/O・条件付き書式の挿入位置判断 |
| メニュー・`01_sys_config` 追記 | なし | 挿入位置特定のみ |

推奨実行モデル

工程推奨モデル理由
Utils.calculateLoanSchedule() 追加Claude Haiku 4.5数学的ロジックのみ・仕様完全定義済み・判断要素なし
600_report/611_service_funding_simulation.js 実装Claude Sonnet 4.6既存 dmCalcCf_() との統合・シート I/O・条件付き書式の挿入位置判断に中程度の判断が必要
メニュー登録・01_sys_config 追記・CLAUDE.md 追記Claude Haiku 4.5挿入位置特定のみ・既存パターンの踏襲
動作確認ユーザー手動94_sim_funding への出力目視確認と実績シート非改変の検証

変更履歴

日付変更内容
2026-04-21初版作成。エクイティ/デット 2 系統の調達シナリオを比較するシミュレーション機能の仕様書。Utils.calculateLoanSchedule() 新規追加・94_sim_funding 動的生成(DDL 管理外)・BudgetRepository/CapexRepository 非実在を前提とした代替アクセス方法(ctx.cashEnd[] 再利用)・17 項目のエッジケース・10 項目の人間検討事項を定義

仕様書作成プロンプト(再現性・監査性のため必ず記録)

展開して表示
<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(骨格 ~20行) / 2-2(概要〜注意事項 ~300行) / 2-3a(エッジケース〜人間検討事項 ~200行) / 2-3b(実装プロンプト〜変更履歴 ~250行) / 2-4(<details>プロンプト全文記録・独立Step) に分割する。1 回の Write/Edit は約 300 行以内。
4. **各 Step で何を書くかを具体指示**: 設計判断を Phase 2 実行時に持ち込まない。Phase 1 で固有名詞・行番号・データ構造を完全確定してから清書に入る。

======================================================================
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者兼仕様書ライターです。
案件 F-17「資金調達シミュレーション」の開発仕様書を作成してください。
作成後は `docs/_config.json` の `nav` 配列「§E.5 FP&A・レポーティング」セクションにも必ず追記してください。

---

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

### 1-A: 案件定義の読み込み
- `docs/_internal/TODO_future.md` で案件 **F-17** の行を検索し、案件名・概要・人間が検討すべき事項を取得する。

### 1-B: プロジェクト規約の読み込み
- `CLAUDE.md` を読み込み、コーディング規約・ファイル番号体系・DDL管理対象外タブ一覧(`94_sim_funding` が DDL 管理外かどうかに特に注目)を把握する。

### 1-C: 既存仕様書テンプレートの読み込み
- F-08「資金繰り予測」の仕様書 `docs/dev/dev_mas-008_cash_runway.md` を Read し、資金繰り計算のロジック・データソース・シート構成を完全に把握する。
  - ファイルが存在しない場合は「要調査」と記録し、次ステップで資金繰り関連コードを直接調査する。
- フォーマット参考として `docs/dev/dev_mas-001_variance_analysis.md`(新機能・FP&A)を Read する。

### 1-D: 関連コードの調査(Grep は発見まで。「どう書くか」の判断は必ず Read)

**① データアクセス層の実態確認**
- `200_data/202_repository.js` を Read し、実在する Repository クラスと `findAll()` の戻り値型を確認する。
  - 実在が確認できるもの: `JournalRepository`(`42_trn_journal`)、`InvoiceRepository`(`32_wrk_invoice`)、`BankTxRepository`(`33_wrk_bank`)、`AccountRepository`(`11_mst_account`)。
  - `BudgetRepository`・`CapexRepository` は **このファイルに存在しない**。予算データ(`41_trn_budget`)・CAPEX データ(`24_bud_capex`)へのアクセス方法を `202_repository.js` と `101_sys_config.js` で確認し、直接シート読み込みが必要か判断する(推測で書かず、Read で裏取りする)。

**② DTO 型定義の確認**
- `000_infra/003_contracts.js` を Read し、`BudgetDTO`(`41_trn_budget`)・`InvoiceDTO`(`32_wrk_invoice`)のフィールド名を正確に把握する(シミュレーション計算で参照するフィールド名の誤記防止)。

**③ ユーティリティ関数の確認**
- `000_infra/004_utils.js` を Read し、`Utils.parseDateToYm()`・`Utils.addMonths()` のシグネチャと戻り値型を確認する。
- `Utils.calculateLoanSchedule()` が **現時点では存在しない**ことを確認する(新規追加関数として仕様書に明記するため)。

**④ キャッシュフロー関連レポートコードの確認**
- `600_report/` 配下のファイルを Grep し、`84_cf_daily_plan` や資金繰り関連の既存実装(特に現預金残高の計算ロジック)を Read して、シミュレーションのベース計算に再利用できるロジックを特定する。

**⑤ システム設定・シート登録の確認**
- `100_config/101_sys_config.js` を Read し、新規シート `94_sim_funding` を DDL(`setupAllSchemas`)に追加すべきか、または `CLAUDE.md` の「DDL で管理されないタブ」リストに倣って動的生成にすべきかを判断する(`93_kpi_dashboard` と同様の動的生成パターンか確認)。
- `000_infra/002_constants.js` の `SHEET_DEFAULTS` と `ID_PREFIX_MAP` を Read し、`94_sim_funding` にデフォルト値設定・ID 発番が必要かを確認する。

**⑥ 既存テストの確認**
- `900_test/901_test_runner.js` を Read し、F-08 / 資金繰り関連のテストケースが存在するか確認する。

---

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

出力先: `docs/dev/dev_mas-017_funding_simulation.md`

### Step 2-1: 骨格の作成(Write・~20行)
以下の見出しのみを含む骨格ファイルを Write する(本文は空で可):

MAS-017: 資金調達シミュレーション

概要 / ## 目的 / ## 現在のコード / ## 修正方針 / ## 影響範囲

注意事項 / ## エッジケース / ## 実データ検証 / ## 関連ドキュメント

人間が検討すべき事項 / ## 実装プロンプト / ## 推奨実行モデル

変更履歴 / ## 仕様書作成プロンプト


### Step 2-2: 前半セクションの追記(Edit または Bash heredoc・~300行)
以下の内容を各セクションに記述する:

**概要テーブル**: 案件ID=F-17、カテゴリ=FP&A、Phase・優先度は TODO_future.md から転記、対象ファイル(後述)、前提案件=F-08。

**目的**: 資金ショート回避のために「いつ・いくら」の資金調達が必要かを複数シナリオで逆算・比較できるシミュレーション機能の追加。

**現在のコード**: F-08 で実装済みの資金繰り予測ロジック(Phase 1 調査で特定したファイル・関数名・行番号)を記載。該当コードが存在しない場合は「F-08 未実装のため本案件で新規実装」と明記。

**修正方針**(アーキテクチャ方針を具体化):
- **新規シート `94_sim_funding`**: CLAUDE.md の「DDL で管理されないタブ」の `93_kpi_dashboard` パターンに倣い、実行時に動的生成・上書きする(Phase 1 調査結果で確定した方針を記載)。シートは「シナリオ入力エリア(A〜G列)」と「結果出力エリア(I列以降)」に分離する。
- **入力エリア定義**: ヘッダー行+シナリオ行テーブル形式。列構成:シナリオ名・調達予定年月(YYYY-MM)・調達手段(エクイティ/デット)・調達額(税抜)・年利(デット時のみ)・返済期間(月)・返済方式(元利均等/元金均等)。
- **計算ロジック**: F-08 の資金繰りベース計算(Phase 1 で特定した関数)をインメモリで実行し、各シナリオのインパクト(現預金キャッシュイン・資本金または借入金 B/S 計上・支払利息 P/L 計上・元本返済 CF)を上乗せ。全計算はインメモリ完結。
- **データ取得**: `JournalRepository.findAll()`・`InvoiceRepository.findAll()` を使用(Phase 1 で確認した実在 Repository のみ使用)。予算データ・CAPEX データは Phase 1 調査で確認したアクセス方法を記載(`BudgetRepository` / `CapexRepository` は存在しないため、直接シート読み込みまたは代替手段を明記)。
- **新規追加関数**: `004_utils.js` に `Utils.calculateLoanSchedule(principal, annualRate, periodsInMonths, type)` を追加(**現時点では未実装**)。引数・戻り値(月ごとの `{ ym, principal, interest, balance }` 配列)のインターフェースを明記。
- **二重計上防止**: `94_sim_funding` 以外のシート(`32_wrk_invoice`・`42_trn_journal` 等)への書き込みは一切禁止。

**影響範囲**: 変更ファイルと変更量(新規: `94_sim_funding` 動的生成関数・`Utils.calculateLoanSchedule`、追記: `101_sys_config.js` のメニュー登録)、既存動作への影響なし(読み取り専用 + 専用シートへの書き込みのみ)。

**注意事項**:
1. `BudgetRepository`・`CapexRepository` は `202_repository.js` に存在しない。予算・CAPEX データへのアクセスは Phase 1 調査で確認した方法に従う。
2. `Utils.calculateLoanSchedule()` は新規追加関数。`004_utils.js` の既存関数(`parseDateToYm`・`addMonths`)との命名規則を合わせる。
3. `94_sim_funding` の生成は CLAUDE.md「DDL で管理されないタブ」の動的生成パターンに従い、`setupAllSchemas` への追加は原則不要(Phase 1 調査結果で最終確認)。
4. シミュレーション結果は実績データマートに混入させない(`601_datamart_ingest.js` 等を呼び出さない)。
5. 日付・年月の比較は必ず `Utils.parseDateToYm()` で YYYY-MM 形式に正規化してから行う(`String(Date)` による比較禁止)。

### Step 2-3a: エッジケース〜人間検討事項の追記(Edit または Bash・~200行)

**エッジケーステーブル**(全項目をテーブル形式で定義):

| 条件 | 表示値・動作 | 理由 |
|------|-----------|------|
| 調達額・年利・返済期間が 0 または負値 | そのシナリオをスキップし、結果サマリーに「入力値エラー: {シナリオ名}」を注記 | 計算不能な入力を排除 |
| 返済期間 = 0 ヶ月(ゼロ除算) | `Utils.calculateLoanSchedule()` 内で事前ガード処理。返済期間 0 はシナリオ全体をエラー扱い | ゼロ除算防止 |
| 調達予定年月が実行日より過去 | 計算を実行せず「過去年月は指定不可: {シナリオ名}」メッセージを `94_sim_funding` の結果エリアに出力 | 意味のないシミュレーション防止 |
| エクイティ調達で年利・返済期間が入力されている | 当該フィールドを無視してエクイティとして処理。注記を出力 | 入力ミスのサイレント対応 |
| シナリオ名が重複 | 後から定義(テーブル下方)のシナリオで上書き。重複件数を結果サマリーに注記 | ユーザーが誤って同名を登録した場合の安全動作 |
| 全シナリオがエラー | 結果出力エリアに「有効なシナリオが 0 件です」と表示し、以降の処理を中断 | 空の結果シートを生成しない |
| `JournalRepository.findAll()` でデータ 0 件 | ベース資金繰りを 0 として計算し、警告を注記 | 初期設定時や開発環境での動作を確保 |

**実データ検証**(実装前に MCP 等で確認すべき項目):
- `41_trn_budget` シートの実際の列構成が `003_contracts.js` の `BudgetDTO` と一致しているか確認。
- `03_sys_params` に資金繰り計算に必要なパラメータ(開始年月等)が登録されているか確認(`Constants.getParam()` で取得できる値)。
- `94_sim_funding` というシート名が既存のスプレッドシートに存在しないか確認(既存の場合は上書き方針を明記)。

**人間が検討すべき事項**:
- TODO_future.md からの転記事項(Phase 1 で確認した内容を全件転記)。
- 本機能はあくまで意思決定支援ツール。シミュレーション結果を自動で仕訳・実績データに反映する機能は **本案件のスコープ外**。
- 調達手段(エクイティ/デット)による B/S インパクトの違い(資本金増加 vs. 借入金増加)をユーザーが直感的に理解できる UI 表現が必要か検討する。
- 元利均等・元金均等の返済方式の違いをユーザーに説明するガイドテキストを入力エリアに含めるか検討する。
- `Utils.calculateLoanSchedule()` を `004_utils.js` に追加するにあたり、他の案件(CAPEX 返済スケジュール等)でも汎用利用できる設計にすることを推奨する。

### Step 2-3b: 実装プロンプト〜変更履歴の追記(Edit または Bash・~250行)

**実装プロンプト**は行頭 4 スペースインデント(バッククォートで囲まない)で以下の内容を記述:

    あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
    案件 F-17「資金調達シミュレーション」を実装してください。

    ## 実行前タスク
    - `200_data/202_repository.js` を Read し、`JournalRepository.findAll()`・`InvoiceRepository.findAll()` の戻り値型(headers, dtos)を確認する。
    - `000_infra/003_contracts.js` を Read し、`BudgetDTO` のフィールド名を確認する。
    - `000_infra/004_utils.js` を Read し、`Utils.parseDateToYm()`・`Utils.addMonths()` のシグネチャを確認する。
    - `100_config/101_sys_config.js` を Read し、メニュー追加の挿入位置と既存メニュー名を確認する(メニュー名は `onOpen()` の実在文字列をそのまま使う)。
    - 仕様書 `docs/dev/dev_mas-017_funding_simulation.md` の「修正方針」「エッジケース」「注意事項」を全て読んでから実装に着手する。

    ## 修正対象ファイル
    - `000_infra/004_utils.js` — `Utils.calculateLoanSchedule()` の追記のみ
    - `600_report/`(または新規ファイル: 番号体系に従い `60X_sim_funding.js` を新規作成)— シミュレーション本体ロジック
    - `100_config/101_sys_config.js` — メニュー登録の追記のみ
    - 上記以外のファイル(`202_repository.js`・`003_contracts.js` 等)は変更禁止

    ## 実装内容
    (仕様書「修正方針」の Step 分割に従い具体的な実装手順を記述)

    ## 制約
    - `32_wrk_invoice`・`42_trn_journal` 等の実績・計画データシートへの書き込み禁止
    - `94_sim_funding` 以外のシートへの書き込み禁止
    - `BudgetRepository`・`CapexRepository` は存在しない。`202_repository.js` にない Repository 名を呼び出さない
    - 日付比較は必ず `Utils.parseDateToYm()` で YYYY-MM 正規化後に実施

    ## エッジケース
    (仕様書「エッジケース」テーブルの全項目を転記)

    ## 動作確認
    1. `npm run push:dev` でデプロイ
    2. スプレッドシートのメニューから「{実在するメニュー名}」を実行
    3. `94_sim_funding` が生成され、シナリオ入力エリアと結果出力エリアが正しく構成されているか確認
    4. 正常シナリオ(エクイティ1件・デット1件)で計算が実行されることを確認
    5. エッジケース(過去年月・返済期間0)で正しくエラー注記が出力されることを確認
    6. `42_trn_journal` 等の実績シートが変更されていないことを確認

    ### 拡張思考の使用状況
    | フェーズ | 拡張思考 | 備考 |
    |---------|---------|------|
    | 実行前タスク(Read・調査) | あり | データ構造・挿入位置の確定 |
    | 実装(Write/Edit) | なし | 調査済み内容の清書に徹する |

**推奨実行モデル**:
| 工程 | 推奨モデル | 理由 |
|------|----------|------|
| `Utils.calculateLoanSchedule()` 追加 | Claude Haiku 4.5 | 数学的ロジックのみ・仕様完全定義済み |
| シミュレーション本体・`94_sim_funding` 生成 | Claude Sonnet 4.6 | 既存資金繰りロジックとの統合判断が必要 |
| メニュー登録追記 | Claude Haiku 4.5 | 挿入位置特定のみ・判断要素少 |

**変更履歴**:
| 日付 | 変更内容 |
|------|---------|
| 2026-04-20 | 初版作成 |

### Step 2-4: 仕様書作成プロンプトの記録(Edit または Bash・独立 Step)
末尾に以下の形式で、この `<instruction>` 全文を記録する:

仕様書作成プロンプト(再現性・監査性のため必ず記録)

展開して表示

(この 全文をここに貼り付ける)

```

Phase 3: 保存と記録

3-B: _config.json にナビゲーション登録(必須)

docs/_config.jsonnav 配列「§E.5 FP&A・レポーティング」セクションに以下を追加:

{ "file": "dev/dev_mas-017_funding_simulation.md", "title": "E.5.X MAS-017 資金調達シミュレーション" }

追記前に git pull origin main で最新状態を確認する。

3-C: changelog 追記

docs/_internal/changelog.md の先頭行(ヘッダー直後)に追記:

| 2026-04-20 | [dev_mas-017_funding_simulation.md](dev_mas-017_funding_simulation.md) | 初版作成。資金調達シミュレーション仕様書 |

3-D: コミット&プッシュ

git add docs/dev/dev_mas-017_funding_simulation.md docs/_internal/changelog.md docs/_config.json
git commit -m "docs: MAS-017 資金調達シミュレーションの開発仕様書を作成

複数の資金調達シナリオ(エクイティ/デット)を比較するシミュレーション機能の仕様書。
Utils.calculateLoanSchedule() 新規追加・94_sim_funding 動的生成の設計方針を記載。
BudgetRepository/CapexRepository 非実在を確認・代替アクセス方法を要調査として記録。"
git push -u origin {現在のブランチ}
```