MAS-031: Compound Growth シミュレーション
概要
| 項目 | 内容 |
|---|---|
| 案件ID | MAS-031 |
| カテゴリ | FP&A / シミュレーション(BizDev) |
| Phase | P3 |
| 優先度 | ★ |
| 所要時間 | 2〜3時間 |
| 対象ファイル | 300_ui/302_compound_growth_ui.js(新規作成)400_domain/421_compound_growth_engine.js(新規作成)000_infra/002_constants.js(MENU_DEFINITION にメニュー項目追記のみ)CLAUDE.md(DDL管理外タブリストに 94_sim_compound_growth を追記) |
| 前提案件 | なし(Utils / Constants の共通基盤を利用) |
目的
成長率 × 年数の複利計算で ARR の将来推移を予測する専用シートを新設する。 「現在の成長率が続くと N 年後に ARR X に到達する」を可視化し、事業計画の数値的根拠・投資家/経営陣向け説明資料として FP&A の意思決定支援に使う。
計算式
ARR(n) = 初期ARR × (1 + 年間成長率)^n (n = 1, 2, ..., シミュレーション期間(年))
現在のコード
該当なし(新規機能)。
シミュレーション専用の UI・エンジンはいずれも未存在。類似の動的生成シートとして 93_kpi_dashboard(F-03)があり、同じ運用パターン(DDL管理外・クリア→再構築)を踏襲する。
シート番号は既存の 9X 系(91_fs_bs / 92_fs_pl / 93_kpi_dashboard)の次番号 94_sim_compound_growth で採番する。後続の ARR/MRR トラッキング(F-28)等で 94 系が複数必要になる場合に備え、プレフィックス sim_ でシミュレーション種別を明示する。
修正方針
アーキテクチャ設計
新規シート:
94_sim_compound_growth93_kpi_dashboardと同様の DDL管理外・動的生成シート。setupAllSchemasの対象外。CLAUDE.mdの「DDL (setupAllSchemas) で管理されないタブ」リストに94_sim_compound_growthを追記する。Constants.SHEET_DEFAULTS/Constants.ID_PREFIX_MAPへの登録は 不要(トランザクション管理対象外のシミュレーション出力シートのため)。- レイアウト:
- 上部(A1〜B5): パラメータ入力欄
- A1:
パラメータ(見出し) - A2/B2:
初期ARR(円)/ 数値入力セル - A3/B3:
年間成長率(%)/ 数値入力セル(例:20と入れる → 内部で 0.20 換算) - A4/B4:
シミュレーション期間(年)/ 数値入力セル - A5/B5: 実行ボタン(描画シェイプ)を配置(代替: 手動実行はメニュー経由でも可)
- A1:
- 結果出力範囲(A7 以降):
- A7:
年次/ B7:ARR(円)/ C7:前年比成長額(円) - A8〜A(7+years): 各年の
Y+nラベル(Utils.addMonths()は年単位ではないため、単純に初期ARR の入力時点 + n 年のラベルは整数年として自明) - B8〜B(7+years): 各年の ARR 数値(
Constants.NUMBER_FORMATS.CURRENCY適用) - C8〜C(7+years): 前年比成長額(
Constants.NUMBER_FORMATS.CURRENCY適用)
- A7:
- フッター: 前提条件注記を
シミュレーション期間 + 9行目から書き込む。
- 上部(A1〜B5): パラメータ入力欄
新規ファイル 1:
300_ui/302_compound_growth_ui.js300_ui/の既存ファイルは301_ui_assist.jsのみ(Phase 1 でls確認済)。次番号 302 で採番。- グローバル関数
runCompoundGrowthSimulation()を実装する。GAS のシートボタン(描画シェイプのスクリプト割当)およびメニュー項目はいずれもグローバル関数名を参照するため、オブジェクト化せずトップレベル関数として定義する。
新規ファイル 2:
400_domain/421_compound_growth_engine.js400_domain/の既存ファイルは420_project_profitability.jsまで使用済み(Phase 1 でls確認済)。次番号 421 で採番。CompoundGrowthEngineオブジェクトとして計算ロジックを分離。公開 API はCompoundGrowthEngine.simulate(initialArr, growthRate, years)。- 戻り値:
[{ year: 1, arr: 数値, delta: 数値 }, ...]の配列。deltaは前年との差額(year === 1の場合はarr - initialArr)。
メニュー登録:
000_infra/002_constants.jsのConstants.MENU_DEFINITIONに、既存の「📋 サイドバー: 📊 マート更新」カテゴリの末尾(savePlSnapshot項の直後)に次の 1 行を追記する:{ label: '📈 Compound Growth シミュレーション', funcName: 'runCompoundGrowthSimulation', description: 'ARR の複利成長シミュレーションを 94 タブに描画' },- 📈 FP&A メニューは現時点で未実在(Phase 1 で
Constants.MENU_DEFINITIONを Read し確認済)。新規カテゴリを作ると他の FP&A 機能(F-24 BEP・F-20 YoY 等)のメニュー配置方針にも影響するため、新カテゴリ化は本案件スコープ外とし、既存マート更新サイドバーへの相乗りに留める。新カテゴリ採用の要否は「人間が検討すべき事項」へ記載。
- 📈 FP&A メニューは現時点で未実在(Phase 1 で
排他制御・UI 制御
- 排他ロックは
LockService.getScriptLock().tryLock(3000)を使用する。PropertiesService.getScriptLock()は存在しない(PropertiesServiceはスクリプトプロパティ管理 API であり Lock API を持たない)。- 取得失敗時は
Utils.toastResult('runCompoundGrowthSimulation', '処理中です。しばらくお待ちください。', 5)を通知して早期return。
- 実行前に結果出力範囲を
sheet.getRange('A7:C' + sheet.getMaxRows()).clearContent()でクリアし、結果が常に上書きされるようにする。パラメータ入力欄(A1:B5)はクリアしない。 - 入力パラメータのパース:
Utils.parseAmt()を使用(全角数字・カンマ・%記号も除去される仕様)。 - 完了通知:
Utils.toastResult('runCompoundGrowthSimulation', 'シミュレーション完了(N 年分を出力)', 5)。
数値フォーマット(Phase 1 で 002_constants.js から実読取り済)
- ARR・前年比成長額列:
Constants.NUMBER_FORMATS.CURRENCY='#,##0;[Red]△ #,##0;"-"' - (パラメータ入力欄の年間成長率%欄で %表示したい場合のみ)
Constants.NUMBER_FORMATS.PERCENT='0.0%;[Red]△ 0.0%;"-"' - 文字列として書き込むセル(前提条件注記等): 事前に
range.setNumberFormat(Constants.NUMBER_FORMATS.TEXT)='@'を適用してからsetValue()。
影響範囲
| ファイル | 種別 | 変更内容 |
|---|---|---|
300_ui/302_compound_growth_ui.js | 新規 | グローバル関数 runCompoundGrowthSimulation() |
400_domain/421_compound_growth_engine.js | 新規 | CompoundGrowthEngine オブジェクト・simulate() 実装 |
000_infra/002_constants.js | 既存変更 | MENU_DEFINITION の「📋 サイドバー: 📊 マート更新」末尾に 1 行追記のみ |
CLAUDE.md | 既存変更 | 「DDL (setupAllSchemas) で管理されないタブ」リストに 94_sim_compound_growth を追記 |
docs/_config.json | 既存変更 | §E.5 FP&A・レポーティング セクションに本仕様書を登録 |
既存ロジックへの影響なし: 601_datamart_ingest.js 系のマート構築、410_subledger_engine.js の仕訳エンジン、RPA 自動起票のいずれにも影響しない。新規シートはデータマート・INV・STL を参照しない独立した計算系。
注意事項
数式設計の落とし穴(failure_patterns.md #21-#24)
本案件ではシート出力は GAS 側で計算した結果を setValues() で書き込む方式に統一する。以下の禁止事項を厳守する:
sheet.getLastColumn()による動的列範囲取得は禁止(failure_patterns.md #21)。ARR 出力は B・C 列固定、クリア対象はA7:C<maxRows>で明示指定。- 全角スペース
U+3000混入リスク(failure_patterns.md #22): ラベル正規化が不要な設計(ラベルは GAS 側でリテラル生成)だが、もし将来的に MATCH 等を使う場合は.replace(/[\s ]+/g, '')で除去する。 YYYY-MMの文字列セルが日付に自動パースされる問題(failure_patterns.md #23): 本案件の年次ラベルはY1・Y2形式で出力し、YYYY-MMは使用しない。ただしフッター注記等で年月を文字列で書く場合はrange.setNumberFormat('@')を先に設定してからsetValue()する。ARRAYFORMULA + MATCH + SUBSTITUTEの組合せ禁止(failure_patterns.md #24): ラベル解決は GAS 側で行番号を特定してリテラル埋め込みで実施する。
その他
- 月列範囲を動的取得する場合は
getLastColumn()を使わず、固定範囲または「値の有無」で判定する。 - パラメータ入力欄の値は「空 →
Utils.parseAmt()が0に変換する」仕様のため、空チェックはparseAmt適用前の生セル値で実施する(val === "" || val === nullの判定)。 - 実行ボタンは描画シェイプ(Insert → Drawing)で作り、右クリック → 「スクリプトを割り当て」で
runCompoundGrowthSimulationを割り当てる。これは初回手動設定が必要(GAS からは自動設置できない)。代替としてメニュー経由実行で十分な運用であれば省略可。
エッジケース
| 条件 | 表示値 / 挙動 | 理由 |
|---|---|---|
| 成長率 = 0% | 全期間で初期ARRと同額(delta = 0) | 0% 複利は横ばい(ARR × (1+0)^n = ARR) |
| 成長率 < 0(縮小シナリオ) | 逓減する数列を正常表示 + Toast で「縮小シナリオで実行しました」と警告通知 | 入力を弾かず業務判断に委ねる。マイナス成長での将来 ARR 予測も実務上有用 |
| 初期ARR = 0 | 全期間 0 を正常表示 | 0 × (1+r)^n = 0。エラー扱いしない |
| 初期ARR < 0 | バリデーションエラー + Utils.toastResult() でエラー通知、処理中断(シートには書き込まない) | 負の ARR は業務上非現実的 |
パラメータ欄が空(セル値が "" または null) | バリデーションエラー + Utils.toastResult('runCompoundGrowthSimulation', 'パラメータを入力してください', 5)、処理中断 | Utils.parseAmt() は空文字を 0 に変換するため、空チェックは parseAmt の前に生値で実施する |
パラメータ欄に非数値文字列(例: "abc") | バリデーションエラー + Utils.toastResult() でエラー通知、処理中断 | Utils.parseAmt('abc') は 0 を返すため、空チェックと同様に parseAmt の前に isNaN(Number(String(val).replace(/[,%\s ]/g, ''))) で判定する |
| シミュレーション期間 = 0 年 | ヘッダー行のみ出力、データ行なし(エラーではない) | 0 年分のループは空。フッター注記は引き続き書き込む |
| シミュレーション期間 < 0 | バリデーションエラー + Utils.toastResult() でエラー通知、処理中断 | 負の期間は非現実的 |
| シミュレーション期間が極端に大きい(例: 100 年) | 正常実行するが、Toast で「大きな期間が指定されました(N 年)」と念押し通知 | Constants.MONTH_ITERATION_LIMIT = 120 と同趣旨の安全上限を年単位で Constants.SIMULATION_YEAR_LIMIT = 50 等として導入することも検討(実装プロンプト側で任意) |
| 多重クリック | LockService.getScriptLock().tryLock(3000) で 3 秒待機後にロック取得失敗 → Utils.toastResult('runCompoundGrowthSimulation', '処理中です。しばらくお待ちください。', 5) で通知して早期リターン | 二重実行防止 |
シミュレーション前提条件
本シミュレーションの 機械的な単純モデルとしての前提を、シート上にも明示する。
- 成長率は期間を通じて一定と仮定する(実際には成長率は時期により変動)。
- 季節変動・市場環境の変化・マクロ経済要因は考慮しない。
- 解約率(チャーン)・顧客減少は考慮しない。Net ARR ではなく「総 ARR の単純複利成長」を計算する。
- Expansion ARR(既存顧客の単価上昇・プラン変更)は考慮しない。
- 通貨単位は **JPY(円)**固定(入力時点の前提。将来的なマルチカレンシー対応は本案件スコープ外)。
出力シートのフッター(シミュレーション期間 + 9 行目付近)に以下の注記を書き込む:
注記: 本シミュレーションは入力されたパラメータに基づく機械的な予測値であり、実績を保証するものではありません。 季節変動・チャーン・市場環境の変化は考慮していません。経営判断に用いる際は他の指標と併せて参照してください。
実データ検証
実装完了後、以下の手順で動作確認を行う。
- 基本ケース: 初期 ARR = 10,000,000 円・成長率 = 20% / 年・期間 = 5 年 で実行
- 期待値: Y1=12,000,000 / Y2=14,400,000 / Y3=17,280,000 / Y4=20,736,000 / Y5=24,883,200
- 手計算または電卓で検証し、誤差が円単位で一致すること(
Math.round()で四捨五入)
- T2D3 モデル比較: 初期 ARR = 1,000,000 円・成長率 = 300% 初年度 → 300% → 200% → 200% → 200% は 本モデルでは表現不可(成長率一定)のため、人間検討事項として将来拡張候補に含める。
- メニュー露出確認:
npm run push:dev後にスプレッドシートを開き、「📋 サイドバー: 📊 マート更新」セクション(サイドバー経由 or トップメニュー経由)に「📈 Compound Growth シミュレーション」が表示されること。 - シート参照方法:
94_sim_compound_growthは動的生成シートのため、01_sys_configへの登録は不要。ss.getSheetByName('94_sim_compound_growth')で直接参照する(シートが無ければss.insertSheet()で作成)。 - 排他制御確認: 2 つのブラウザタブで同時にメニュー実行し、2 つ目が「処理中です」Toast で早期リターンすること。
関連ドキュメント
docs/_internal/TODO_future.md— F-31 の原案(Phase・優先度・人間検討事項の元ネタ)docs/dev/dev_F-24_bep_analysis.md— FP&A 系計算ロジック + 専用シート出力の構成参考docs/dev/dev_F-03_kpi_dashboard.md— 動的生成シート(93 タブ)のクリア→再構築パターン参考docs/_internal/failure_patterns.md— 数式設計の失敗パターン #21-#24(getLastColumn()膨張・全角スペース・YYYY-MM 自動パース・ARRAYFORMULA+MATCH 禁止)docs/dev/dev_F-28_arr_mrr_tracking.md— F-28 ARR/MRR 実績トラッキング(本案件の実績データ側、F-31 はその予測側に相当)
人間が検討すべき事項
TODO_future.md から転記
- 成長率の前提をどう置くか: 過去実績ベース(直近 12 ヶ月の CAGR を自動計算)vs 目標ベース(経営陣が設定)。初版はパラメータ入力方式(手入力)とし、自動計算は将来拡張候補。
- 季節変動の補正方法: SaaS 業態では年度末・四半期末の契約更改集中により季節性がある。単純複利では表現できないため、将来拡張として「月次成長率×12」方式や「S カーブ当てはめ」を検討する。
本案件で追加した検討事項
- 新レイヤー
700_simulation/採用要否: 原案では700_simulation/というディレクトリが示唆されていたが、CLAUDE.mdの「GAS ファイル番号体系(Modular Monolith)」セクションに 未定義。新レイヤー採用にはCLAUDE.md更新・レイヤー責務の合意形成が必要でリスクが高い。本仕様書では 既存の400_domain/に配置する方針とし、新レイヤー採用は別 ADR で議論する。- 将来的に F-11/F-12/F-13/F-17(いずれもシミュレーション系)が増えた段階で、
700_simulation/への集約リファクタを別案件として検討する。
- 将来的に F-11/F-12/F-13/F-17(いずれもシミュレーション系)が増えた段階で、
- チャーンレート・Expansion ARR の将来モデル拡張: Net ARR ベースの Compound Growth モデル化(
ARR(n) = ARR(n-1) × (1 + growthRate - churnRate + expansionRate))への拡張要否。F-28(ARR/MRR 実績トラッキング)と統合するタイミングで再検討。 - シミュレーション結果の
93_kpi_dashboard連携: 予測値を KPI ダッシュボードの「将来 ARR 予測」指標として自動反映するか。初版はスタンドアロンのシミュレーションシートとし、ダッシュボード連携は F-28 実装後に再検討。 - T2D3 モデル(Triple-Triple-Double-Double-Double)との比較表示: TODO_future.md の原案に言及あり。初版では「成長率一定」の単純モデルに絞り、T2D3 比較表示(別列で年次ごとの異なる成長率を入力する高度モード)は将来拡張候補とする。
- メニュー新カテゴリ「📈 FP&A」新設の判断: 現時点では「📋 サイドバー: 📊 マート更新」相乗りで十分だが、F-11/F-12/F-13/F-16/F-17/F-19/F-28 等の FP&A 系機能が増えてきたタイミングで独立カテゴリに再編することを検討する。
- 実行ボタン(描画シェイプ)の設置方法: GAS からは描画シェイプを自動配置できないため、初回は人間が手動で「図形 → スクリプトを割り当て」する必要あり。メニュー経由実行だけで運用可能な場合は省略可。
実装プロンプト(Claude Code 用)
あなたはGAS会計システムのシニア開発者です。
案件 F-31「Compound Growth シミュレーション」を実装してください。
## 実行前タスク
- `100_config/101_sys_config.js` の `onOpen()` と `000_infra/002_constants.js` の `MENU_DEFINITION` を Read し、既存メニュー構造と追加位置(「📋 サイドバー: 📊 マート更新」カテゴリの末尾)を確認する。
- `ls 300_ui/` で既存ファイル一覧を確認し、UI ファイルの連番 302 を確定する(`301_ui_assist.js` の次)。
- `ls 400_domain/` で既存ファイル一覧を確認し、エンジンファイルの連番 421 を確定する(`420_project_profitability.js` の次)。
- `000_infra/004_utils.js` の `Utils.parseAmt` / `Utils.toastResult` のシグネチャを確認する。
- `000_infra/002_constants.js` の `Constants.NUMBER_FORMATS.CURRENCY` / `PERCENT` / `TEXT` の書式文字列を確認する。
## 修正対象ファイル
- `300_ui/302_compound_growth_ui.js`(新規作成)— グローバル関数 `runCompoundGrowthSimulation()` のみ
- `400_domain/421_compound_growth_engine.js`(新規作成)— `CompoundGrowthEngine` オブジェクト
- `000_infra/002_constants.js`(既存・`MENU_DEFINITION` の「📋 サイドバー: 📊 マート更新」末尾に 1 行追記のみ)
- `CLAUDE.md`(既存・「DDL で管理されないタブ」リストに `94_sim_compound_growth` を追記のみ)
## 実装内容
### 1. `400_domain/421_compound_growth_engine.js`
- `var CompoundGrowthEngine = { simulate: function(initialArr, growthRate, years) { ... } };` の形で定義する。
- 入力: `initialArr`(数値・円単位)、`growthRate`(小数形式・`0.20` 等)、`years`(整数)。
- 出力: `[{ year: 1, arr: 数値, delta: 数値 }, ...]` の配列。
- `arr = Math.round(initialArr * Math.pow(1 + growthRate, year))`
- `delta = arr - (year === 1 ? initialArr : prevArr)`
- 入力バリデーションは呼び出し側(UI 層)で行い、エンジンは素直に計算するだけ。負の `initialArr` / 負の `years` は呼ばれないことを前提にする(防御的にガードしてもよい)。
### 2. `300_ui/302_compound_growth_ui.js`
以下の順序で `runCompoundGrowthSimulation()` を実装する:
a. `LockService.getScriptLock().tryLock(3000)` で排他ロック取得。取得失敗時は `Utils.toastResult('runCompoundGrowthSimulation', '処理中です。しばらくお待ちください。', 5)` で通知して早期 `return`。
b. シート `94_sim_compound_growth` を `ss.getSheetByName('94_sim_compound_growth')` で取得。存在しない場合は `ss.insertSheet('94_sim_compound_growth')` で作成し、A1:B5 にパラメータ入力欄のラベルと初期値(初期ARR=0 / 成長率%=0 / 期間=0)を書き込む(初回ヘルパー)。
c. パラメータ入力欄(B2/B3/B4)の**生値**を取得し、空文字・`null` チェック → `Utils.toastResult` でエラー通知して `return`。
d. 非数値チェック: `isNaN(Number(String(val).replace(/[,%\s ]/g, '')))` で判定。エラー時は `Utils.toastResult` で通知して `return`。
e. `Utils.parseAmt()` でパラメータをパース。`initialArr` / `growthRatePct` / `years` を取得。`growthRate = growthRatePct / 100`(例: `20` → `0.20`)。
f. 追加バリデーション: `initialArr < 0` → エラー通知して `return`。`years < 0` → エラー通知して `return`。`growthRate < 0` → Toast で警告のみ(処理は継続)。
g. 出力範囲をクリア: `sheet.getRange('A7:C' + sheet.getMaxRows()).clearContent()`。
h. `CompoundGrowthEngine.simulate(initialArr, growthRate, years)` を呼び出して結果を取得。
i. ヘッダー行(A7:C7)に `['年次', 'ARR(円)', '前年比成長額(円)']` を書き込む。
j. 結果を A8 以降に `setValues()` で一括書き込み。`arr` 列・`delta` 列には `Constants.NUMBER_FORMATS.CURRENCY` を `setNumberFormat()` で適用。
k. フッター行(`7 + years + 2` 行目)に前提条件注記を書き込む(`setNumberFormat(Constants.NUMBER_FORMATS.TEXT)` を先に適用)。
l. `lock.releaseLock()` でロック解放(`try/finally` で保証)。
m. `Utils.toastResult('runCompoundGrowthSimulation', 'シミュレーション完了(' + years + ' 年分を出力)', 5)` で完了通知。
### 3. `000_infra/002_constants.js`
`MENU_DEFINITION` の「📋 サイドバー: 📊 マート更新」カテゴリ(`savePlSnapshot` 項の直後)に次の 1 行を追記する:
```js
{ label: '📈 Compound Growth シミュレーション', funcName: 'runCompoundGrowthSimulation', description: 'ARR の複利成長シミュレーションを 94 タブに描画' },
```
### 4. `CLAUDE.md`
「## DDL (setupAllSchemas) で管理されないタブ」セクションの動的生成タブ一覧に `94_sim_compound_growth` を追記する。
## 制約
- **`PropertiesService.getScriptLock()` は存在しない**。必ず `LockService.getScriptLock()` を使用すること。
- `700_simulation/` ディレクトリは**作成しない**。`CLAUDE.md` のレイヤー体系に未定義のため既存 `400_domain/` に配置する。
- `101_sys_config.js` / `002_constants.js` / `CLAUDE.md` 以外の既存ファイルは変更禁止。
- 列参照はヘッダー名ベース。列番号ハードコード禁止(本案件は固定レイアウトだが、将来拡張時のため `A1` 系の `getRange(addr)` 記法を使う)。
- `sheet.getLastColumn()` は使用しない(failure_patterns.md #21)。クリア範囲は `A7:C<maxRows>` で明示指定。
- シート出力に数式は使わない。GAS 側で計算した結果を `setValues()` で書き込む。
- 結果は常に上書きされる(実行のたびに `clearContent()` → 再描画)。履歴は残さない。
## エッジケース(UI 層のバリデーション対象)
| 条件 | 挙動 |
|------|------|
| 成長率 = 0% | 全期間で初期 ARR と同額(`delta = 0`) |
| 成長率 < 0 | 逓減する数列を正常表示 + Toast で「縮小シナリオで実行しました」と警告通知 |
| 初期 ARR = 0 | 全期間 0 を正常表示 |
| 初期 ARR < 0 | バリデーションエラー + Toast 通知、処理中断 |
| パラメータ欄が空 | バリデーションエラー + Toast 通知、処理中断 |
| パラメータ欄に非数値 | バリデーションエラー + Toast 通知、処理中断 |
| 期間 = 0 年 | ヘッダー行のみ出力、データ行なし |
| 期間 < 0 | バリデーションエラー + Toast 通知、処理中断 |
| 多重クリック | `LockService.getScriptLock().tryLock(3000)` で 3 秒待機後にロック取得失敗 → Toast で「処理中です」通知して早期リターン |
## 動作確認
1. `npm run push:dev` でデプロイ。
2. スプレッドシートを開き、「📋 サイドバー: 📊 マート更新」メニューに「📈 Compound Growth シミュレーション」が表示されることを確認。
3. 基本ケース(初期 ARR=10,000,000 円・成長率=20%・期間=5 年)を実行し、`94_sim_compound_growth` に以下の結果が出力されることを確認:
- Y1=12,000,000 / Y2=14,400,000 / Y3=17,280,000 / Y4=20,736,000 / Y5=24,883,200
4. 各エッジケース(成長率 0% / 成長率マイナス / 初期 ARR 負値 / パラメータ空 / 非数値 / 期間 0 / 期間負値 / 多重クリック)を順に確認。
5. Constants.NUMBER_FORMATS.CURRENCY 適用により、負値は `△ 1,000` のように赤字表示されること。
### 拡張思考の使用状況
| フェーズ | 拡張思考 | 備考 |
|---------|--------|------|
| 実行前タスク | あり | メニュー構造・連番の確定 |
| 実装 | なし | 仕様書の書き下しに徹する |
推奨実行モデル
新規ファイル 2 件の作成 + 既存ファイル 2 件(002_constants.js・CLAUDE.md)への既存パターンに沿った統合作業が主体。重度な会計ロジック判断や複数ファイル横断の設計判断は不要(シミュレーションは他システムから独立)。
| ステップ | 推奨モデル | 理由 |
|---|---|---|
| Step 1(実行前タスク: メニュー構造・連番の確認) | Sonnet | 既存の MENU_DEFINITION 構造を読み、追記位置を特定する中程度の判断が必要 |
Step 2(421_compound_growth_engine.js 新規作成) | Haiku | 仕様書で関数シグネチャ・計算式・戻り値形式が完全定義済み |
Step 3(302_compound_growth_ui.js 新規作成) | Sonnet | バリデーション順序・ロック制御・エラー通知の組立てに中程度の判断が必要 |
Step 4(002_constants.js メニュー追記) | Haiku | 追記位置と文字列が仕様書で完全指定済み |
Step 5(CLAUDE.md DDL 対象外リスト追記) | Haiku | 追記位置と文字列が仕様書で完全指定済み |
| Step 6(動作確認・Toast 文言調整) | Sonnet | 実行時の UI フィードバックは微調整が必要 |
全体として、仕様書の書き下しが中心であり Claude Sonnet を推奨する。
変更履歴
| 日時 | 変更者 | 変更内容 |
|---|---|---|
| 2026-04-21 | t_saitoh | 初版作成 |
仕様書作成プロンプト
展開して表示
【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】
1. **拡張思考の使い分け**: Phase 1(設計)では拡張思考をフル活用し、ファイル名形式・エッジケース一覧・Step 分割粒度・固有名詞(関数名/シート名/列名/行番号)を完全に確定させる。Phase 2(清書)の各 Step 内では拡張思考を最小限に抑え、Phase 1 で確定済みの内容の書き下しに徹する。出力途中で再考しない。
2. **テキスト報告の禁止**: 「〜を作成します」等の text のみで tool_use なしに turn を終了しない。説明は 1 文以内。直ちに tool を呼ぶ。
3. **4-5 分割の Write/Edit 実行**: 2-1(骨格)/2-2(概要〜注意事項)/2-3a(エッジケース〜人間検討事項)/2-3b(実装プロンプト〜変更履歴)/2-4(`<details>` 記録) に分割。1 回の Write/Edit は約 300 行以内を目安にする。
4. **各 Step で何を書くかを具体指示**: 設計判断を Phase 2 実行時に持ち込まない。各 Step の内容は Phase 1 で確定させた固有名詞・行番号をそのまま書き下す。
======================================================================
あなたはGAS会計システムのシニア開発者兼仕様書ライターです。
案件 F-31「Compound Growth シミュレーション」の開発仕様書を作成してください。
仕様書を新規作成したら、`docs/_config.json` の `nav` 配列の適切なセクションにも必ず追記してください。
---
## Phase 1: 実行前タスク(テキスト報告禁止。即座にツール実行)
以下をすべて Read/Grep で調査し、Phase 2 で使う固有名詞・ファイル名・行番号を確定させる。
### 1-A: 案件定義の取得
`docs/_internal/TODO_future.md` で F-31 の行を検索し、概要・期待効果・人間が検討すべき事項を取得。
### 1-B: 類似仕様書の読み込み(構成の参考)
- `docs/dev/dev_F-24_bep_analysis.md` — 計算ロジックと専用シート出力を伴う案件の構成参考
- `docs/dev/dev_F-03_kpi_dashboard.md` — シート生成・数式設計の注意点(`docs/_internal/failure_patterns.md` #21-#24: `getLastColumn()` 膨張・全角スペース・YYYY-MM 自動パース・ARRAYFORMULA+MATCH 禁止)の参考
### 1-C: メニュー構造の確認(固有名詞クロスチェック)
`100_config/101_sys_config.js` の `onOpen()` 関数を **Read** し、以下を確認する(記憶や推測で書かない。failure_patterns.md #20 の再発防止):
- 「📈 FP&A」メニューが実在するか・正確なラベル文字列と追加位置(行番号)
- 存在しない場合は新規メニューとして追加する旨を仕様書に明記
- 9X 系シート(`91_fs_bs` 等)の DDL 管理状況を確認し、`94_sim_compound_growth` が DDL 対象か動的生成シートかを判断
### 1-D: 新規ファイルの配置先確認(連番決定)
- `ls 300_ui/` で既存ファイル一覧を取得し、次の連番を確定(既存が `301_ui_assist.js` のみなら `302_compound_growth_ui.js` が候補)
- `ls 400_domain/` で既存ファイル一覧を取得し、最大連番の次を確定(例: `420_project_profitability.js` まで使用済みなら `421_compound_growth_engine.js` が候補)
- **⚠️ 原案の `700_simulation/` というディレクトリは `CLAUDE.md` の「GAS ファイル番号体系」に未定義**。新レイヤーを作成する場合は `CLAUDE.md` への追記も必要となるためリスクが高い。シミュレーションエンジンは既存の `400_domain/` に配置する方針を仕様書に明記し、新レイヤー採用要否を「人間が検討すべき事項」に挙げる。
### 1-E: インフラコードの引数・定数値の確認
`000_infra/004_utils.js` を Read し、以下のシグネチャを確認:
- `Utils.parseAmt(val)` — 数値パース
- `Utils.addMonths(ymStr, months)` — 月加算
- `Utils.toastResult(funcName, message, duration)` — Toast通知(バリデーションエラー通知に使用)
`000_infra/002_constants.js` を Read し、以下の実際のフォーマット文字列を確認:
- `Constants.NUMBER_FORMATS.CURRENCY`
- `Constants.NUMBER_FORMATS.PERCENT`
- `Constants.NUMBER_FORMATS.TEXT`
---
## Phase 2: 仕様書の分割作成
出力先: `docs/dev/dev_F-31_compound_growth_simulation.md`
**絶対に 1 回のツール呼び出しで全内容を出力しない。**
### Step 2-1: 骨格の作成(Write, ~20 行)
(見出しのみの骨格作成。本文は空)
### Step 2-2: 概要〜注意事項の追記(Edit, ~300 行)
Phase 1 で確定した固有名詞を使い、概要テーブル・目的・現在のコード・修正方針・影響範囲・注意事項を書き下す。
### Step 2-3a: エッジケース〜人間検討事項の追記(Edit, ~200 行)
エッジケーステーブル・シミュレーション前提条件・実データ検証・関連ドキュメント・人間検討事項を書き下す。
### Step 2-3b: 実装プロンプト〜変更履歴の追記(Edit, ~250 行)
実装プロンプトは行頭スペース 4 つのインデントで出力。推奨実行モデルと変更履歴を続けて記載。
### Step 2-4: 仕様書作成プロンプトの記録(Edit)
末尾の「## 仕様書作成プロンプト」セクションに `<details><summary>展開して表示</summary>` ブロックを設け、この `<instruction>` 全文を追記する。
---
## Phase 3: 後処理(テキスト報告禁止。即座にツール実行)
1. **`docs/_config.json` への追記**: 追記直前に `git pull origin main` を実行。`nav` 配列の §E.5(FP&A・レポーティング)セクションに追加。
2. **`docs/_internal/changelog.md` への追記**: ヘッダー直後の先頭行に追記。
3. **コミット&プッシュ**: `git add` → `git commit` → `git push -u origin {現在のブランチ}`
📌 取り込み時の注記 (2026-06-02 sub 復元)
本仕様書は旧 F-番号体系で作成され PR 未マージのまま孤立していたドラフトを、
origin/docs/dev-*ブランチから内容無改変で復元し、案件ID のみ MAS 体系へ正規化したもの。status: Open(未実装)。⚠️ ファイル番号ドリフト: 本文「対象ファイル」が指す
600_report/610〜612_*.jsは現行 main で 別機能に使用済み(610=投資分析/MAS-013・611=財務モデリング/MAS-010・612=採用sim/MAS-012)。 実装時にファイル番号の再割当が必要。