RQ-053 monorepo 化トポロジー設計(Synthesis: 3 モデル突合 + MCDA 案 C 段階的採択)
0. この Synthesis の位置付け
本 Synthesis は ADR-0050 で確立した bizlp Synthesis テンプレート (案 C ハイブリッド) を適用する 2 例目 (1 例目 = RQ-052 Self-bootstrapping)。3 LLM (Claude / Gemini / GPT) の結果を MCDA (WSM + CBA K.O.) で突合して採択方針を決定し、ADR-NNNN 起案の根拠資料とする。
「monorepo 化したい意思はある (root を含めるかは未定)」というユーザ意思を、3 LLM 並列調査による informed synthesis で意思決定支援する。
1. Context & Problem Statement
bizlp-gas-accounting は現状「準 monorepo」状態:
- 4 projects: root (GAS),
webapp_client/(React SPA),drp/(Cloudflare Workers),docs-search-worker/(Cloudflare Workers) - 3 deploy targets: Google Apps Script (clasp), Cloudflare Workers (wrangler), Cloudflare Pages (docs)
- 依存管理混在: root に
package-lock.json+pnpm-lock.yaml両方、subproject は各自独立 lock - 既存結合 (準 monorepo の証跡):
- 型共有:
docs/spec/sidebar_api.d.ts(root) を webapp_client が import - コード同期:
webapp_client/scripts/sync-engines.mjsが400_domain/*.jsを prebuild copy - Build orchestrator: root の
npm run build:spaが 4 ターゲット並行実行
- 型共有:
- 未完成痕跡: root
pnpm-workspace.yamlがプレースホルダ (allowBuilds: fsevents: set this to true or false) でpackages:フィールド未定義 = workspace 機能実質無効
Problem: 「正式 monorepo 化」が合理的選択か、現状維持か、polyrepo 分割かの判断軸 + tooling 選択 + 段階的移行戦略を 3 LLM 並列調査で informed に決定する。
2. 3 モデル合意マトリクス
3 モデル並列調査の合意点を抽出:
| 論点 | Claude | Gemini | GPT (o3) | 合意度 |
|---|---|---|---|---|
| monorepo 化方針 | ✅ 推奨 (準→正式昇格) | ✅ 推奨 (AI 主体下で必須) | ✅ 推奨 (依存統一 + AI 効率) | 3/3 合意 |
| Package Manager | pnpm | pnpm | pnpm (Yarn Berry も併記) | 3/3 合意 |
| Build Orchestrator | Turborepo | Turborepo | Turborepo (Nx は将来) | 3/3 合意 |
| 依存統一: Catalogs 使用 | ✅ 推奨 (catalogMode: strict) | ✅ 推奨 (中央集権管理) | △ (Catalogs に触れず、pnpm.overrides 推奨) | 2/3 合意 |
| 既存 sync-engines.mjs の解消 | workspace package 化 (packages/engines) | workspace package 化 (packages/domain) | workspace package 化 (packages/400_domain) | 3/3 合意 (名前差のみ) |
sidebar_api.d.ts の扱い | packages/types 化 | packages/types 化 | packages/sidebar-api-types 化 | 3/3 合意 (名前差のみ) |
| 段階的移行 (3 phase) | Phase 1 (workspace 宣言) → Phase 2 (lock 統合) → Phase 3 (共有 packaging) | 同じ 3-phase | 同じ 3-phase | 3/3 合意 |
| broken pnpm-workspace.yaml の扱い | Phase 1 で削除 + 正規化 | Phase 1 で削除 + 正規化 | Phase 1 で削除 (pnpm v10 allowBuilds は別途検討) | 3/3 合意 |
| Vercel Remote Cache 活用 | ✅ 無料化済 (2024-12-22) で活用推奨 | 言及なし | ✅ Turbo/Nx Cloud で活用 | 2/3 合意 |
| AI エージェント文脈効率の重視 | ✅ Nested CLAUDE.md パターン | ✅ コンテキスト窓効率がコアな利点 | ✅ 統一構造が AI 有利 | 3/3 合意 |
3/3 合意の核心: pnpm workspaces + Turborepo + 段階的 3-phase 移行 + AI 文脈効率重視。
3. 最大相違: Root 包含可否
3 モデルが最も明確に分岐した論点は「root を monorepo の workspace member として包含するか / 分離するか」。
3.1 各モデルの立場と根拠
| モデル | 立場 | 主たる根拠 |
|---|---|---|
| Claude | 同梱 (root を packages: ['.', ...] に含める) | (1) docs/spec/sidebar_api.d.ts / 400_domain/*.js の SSoT がルート配下、(2) 既存 sync 結線をワークスペース化しやすい、(3) pnpm 公式が '.' パターンをサポート、(4) GAS は package manager 非依存で .clasp.json rootDir で隔離可能 |
| Gemini | 分離 (GAS を apps/gas-core/ に移動、Root は純粋 orchestrator 化) | (1) Root に GAS コード + workspace は致命的副作用 (node_modules 漏洩リスク)、(2) AI 探索効率上 Root は orchestration 専用が clean、(3) apps/gas-core/ への移行は esbuild + @gas-plugin/unplugin で dist/gas-core/ から clasp push する近代的構成 |
| GPT (o3) | 段階的 (まず root 除外で検証 → 後に包含可否を再判断) | (1) GAS 固有制約 (TypeScript 非対応、.gs のみ deploy) の影響範囲を実 install で検証してから判断、(2) 「含めない場合」のメリット (既存 GAS フロー無影響) を最初は享受、(3) 段階的に effort を分散 |
3.2 3 案を MCDA で評価 (Q42 5 軸、ADR-0050 準拠)
評価軸 (重み付き):
| 軸 | 重み | 解釈 |
|---|---|---|
#maintainable [Must] | ×2.0 | AI agent / Jr が 6 ヶ月後に構造を再現可能 |
#suitable [Must] | ×2.0 | 既存結線 (sync-engines.mjs, sidebar_api.d.ts) + CLAUDE.md / ADR-0019 整合 |
#operable High | ×1.0 | 実装コスト (Claude Code セッション数) |
#usable Medium | ×0.5 | Jr onboarding 学習コスト |
K.O.: Must 軸 score < 3 は不採用。
| 軸 | 係数 | 案 A (Claude: 同梱) | 案 B (Gemini: 分離) | 案 C (GPT: 段階的) |
|---|---|---|---|---|
#maintainable [Must] | ×2.0 | 4 (sync 結線を workspace で表現可能、ただし GAS が root だと AI 探索時にコード/orchestrator 混在) | 5 (apps/gas-core 分離で構造的に clean、AI 探索効率最大) | 5 (Phase 2 完了時点で正式 monorepo、Phase 3 で再判断可能) |
#suitable [Must] | ×2.0 | 5 (pnpm 公式パターン、.clasp.json rootDir で漏洩制御) | 3 (GAS を apps/gas-core/ に移動は破壊的、.clasp.json / scripts 等の path 大量変更) | 5 (Phase 1 は root 除外で既存 GAS フロー無影響、段階的) |
#operable High | ×1.0 | 5 (workspace 宣言のみで完了、Phase 1 が軽い) | 2 (GAS ディレクトリ大量移動、scripts/path 全面書換、Mega 工数) | 4 (Phase 1-2 軽量、Phase 3 で必要なら分離追加実施) |
#usable Medium | ×0.5 | 4 (ルートに既存通り GAS があるので Jr が現行構造から繋がる) | 5 (apps/ + packages/ の業界標準構造で Jr の学習コストが低い) | 4 (Phase 進行に応じて段階的に学習可能) |
| 加重和 (満点 27.5) | 0.836 (4×2+5×2+5+4×0.5)/27.5 | 0.673 (5×2+3×2+2+5×0.5)/27.5 | 0.927 (5×2+5×2+4+4×0.5)/27.5 | |
| K.O. (Must ≥3) | ✓ (4, 5) | ✓ (5, 3) | ✓ (5, 5) |
採択: 案 C (GPT: 段階的) — 加重和 0.927 首位、K.O. 通過、Must 軸両方 5 点。
3.3 案 C 採択の根拠詳述
- #suitable 5 点の決め手: Phase 1 で root を workspace 除外 → 既存 GAS フロー (
.clasp.json/clasp push/npm run push:dev) に 影響ゼロ。Phase 2 で lock 統合 → 既に webapp_client 等は独立した pnpm で動いているため移行コストが分散される。Phase 3 で初めて共有 packaging に踏み込む際、root 包含可否を実データに基づいて再判断できる。 - #operable 4 点の理由: Phase 1 / 2 / 3 で Claude Code セッション数を 1 / 2-3 / 4-6 と分散できる (Claude/Gemini の試算と整合)。Mega 工数 (Gemini 案の GAS ディレクトリ全面移動) を一度に行わない安全策。
- #maintainable 5 点の理由: Phase 2 完了時点で正式 monorepo (workspace + lock 統合) が成立し、AI agent 探索効率が向上。Phase 3 で必要なら apps/gas-core 分離も追加可能だが、必須ではない (現行 root pattern でも CLAUDE.md nested で AI 文脈は確保可能)。
- Gemini 案 (B) の弱点:
#suitable=3(.clasp.json/ scripts / GitHub Actions /docs/_config.json等で root path 仮定を大量に書き換える破壊的変更) と#operable=2(Mega 工数) で総合的に劣る。理論的優位 (clean 構造) は認めるが、本リポの現実 (個人開発 + 既存資産大量) では cost-benefit が合わない。
4. 採択方針 (確定版)
4.1 Tooling Stack (3 モデル合意ベース)
| レイヤ | 採用 | 根拠 |
|---|---|---|
| Package manager | pnpm 10.x | 3 モデル合意 (phantom dep 防止、Catalogs 機能、content-addressable store) |
| Workspace | pnpm workspaces + Catalogs (catalogMode: strict) | Claude / Gemini 合意 + GPT は明示なしだが反対なし。Catalogs で version drift 構造的防止 |
| Build orchestrator | Turborepo 2.x | 3 モデル合意 (個人開発で Nx は過剰、Vercel Remote Cache 無料化済) |
| 共有型管理 | TypeScript Project References + workspace:* | 3 モデル合意 (path aliases 非推奨、TypeScript 公式推奨) |
| Remote cache | Vercel Remote Cache (2024-12-22 以降無料) | Claude / GPT 合意、個人開発でも CI ↔ ローカルでキャッシュ共有可能 |
| Dep drift 監視 | syncpack + pnpm catalog: 強制 | Claude 推奨、Gemini も Catalogs 推奨で実質合意 |
| CI | GitHub Actions + pnpm/action-setup@v4 + turbo run --affected | 3 モデル合意 |
4.2 Root 包含戦略: 段階的 (案 C)
- Phase 1: Root を pnpm-workspace.yaml に含めない。
packages: ['webapp_client', 'drp', 'docs-search-worker']で 3 subproject のみ workspace 化 - Phase 2: lock 統合 (subproject の
package-lock.json/pnpm-lock.yaml削除 → root でpnpm import→ 統合pnpm-lock.yaml)。Turborepo 導入、root のnpm run build:spaをturbo run build --filter=webapp_clientに置換 - Phase 3: 共有 packaging。
packages/types/(sidebar_api.d.ts 移管) +packages/engines/(400_domain 切り出し、sync-engines.mjs 廃止)。ここで初めて root 包含可否を再判断 (実データベース)
4.3 broken pnpm-workspace.yaml の処置
- Phase 1 着手時に 削除 (現行プレースホルダ
allowBuilds: fsevents: set this to true or falseは無効値、workspace 機能未設定) - 新規
pnpm-workspace.yamlを Phase 1 内容で書き直し allowBuilds(pnpm v10+ 機能) は当面省略。必要時にpnpm approve-buildsで必要 package のみ許可 (GPT 指摘の正しい運用)
4.4 後戻り戦略 (案 C 採択時の rollback)
- Phase 1:
pnpm-workspace.yaml削除のみで完全ロールバック可 - Phase 2: 各 subproject で
pnpm install再実行 +pnpm-lock.yamlgit revert で復元可 - Phase 3: git tag
monorepo-phase-2-stableを Phase 2 完了時点で打ち、Phase 3 の破壊的変更は revert 可能 - GPT 推奨の
git subtree戦略は 採用しない (Claude 指摘の通り、本リポは単一 git repo で完結しており、ポリレポへ戻すコストは Claude Code 数十分セッションで完了するため subtree 戦略のメリットが薄い)
5. 残る論点 (未採択 = 将来 ADR 候補)
| 論点 | 元提案者 | 採択判断 | 理由 |
|---|---|---|---|
GAS を apps/gas-core/ に分離 | Gemini | 本 ADR では不採用 | Phase 3 で必要性が顕在化した時点で別 ADR で再評価 (root を含めるか分離するかは Phase 3 時点の実データで判断) |
git subtree で後戻り保険 | GPT | 不採用 | 単一 repo で完結、ポリレポへの戻し作業コストが低いため保険不要 (Claude 指摘) |
Frontmatter に機械可読 citations: | (Gemini @ ADR-0065) | 別 ADR | ADR-0065 の将来課題、本 RQ-053 範囲外 |
apps/gas-core/ への移行で esbuild + @gas-plugin/unplugin | Gemini | Phase 3 で再評価 | 案 C 採択で初期 Phase は GAS 現状維持 |
| Cloudflare Builds の自動 install workspace 全体初期化問題 | Claude | 採択 | Phase 2 で対処方針確定 (GitHub Actions 経由の手動 deploy を併用) |
6. 段階的移行ロードマップ (Claude Code 駆動前提)
| Phase | 主タスク | Claude Code セッション数 | 期待時間 | リスク | ロールバック |
|---|---|---|---|---|---|
| Phase 0 | 凍結 & インベントリ | 1 | ~1h | なし | N/A |
| Phase 1 | pnpm-workspace.yaml 正規化 (root 除外) + workspace 宣言 | 1 | ~1h | 最小 (各 subproject の lock は維持) | pnpm-workspace.yaml 削除 (即時) |
| Phase 2 | lock 統合 (pnpm import) + Turborepo 導入 + turbo.json 作成 | 2-3 | ~3-4h (CI 含む) | 中 (lock 衝突調整、CI 設定変更) | git revert + 各 subproject pnpm install 再実行 |
| Phase 3 | 共有 packaging (packages/types/, packages/engines/) + Root 包含可否 再判断 | 4-6 | ~6-8h | 高 (破壊的変更、全 import 書換) | git tag monorepo-phase-2-stable から復元 |
7. 6 ヶ月後の評価指標 (Phase 完了時の判定基準)
3 モデルの KPI 提案を統合:
| KPI | 計測方法 | 成功閾値 | 出典 |
|---|---|---|---|
pnpm install 全 workspace 所要時間 | CI ログ | 90 秒以内 (cold) | Claude |
| Turbo cache hit 率 (ローカル + Remote 合算) | turbo run build --summarize JSON | 60% 以上 | Claude |
| 共有依存の version drift 数 | syncpack list-mismatches 週次 CI | 0 件 | Claude |
| Cross-package PR の比率 | GitHub label / git diff stats | 月 30% 以上 | Claude |
| Claude Code セッションでの誤探索率 | 主観評価 + grep 失敗ログ | 移行前比 50% 減 | Claude |
| GAS ランタイムでの「想定外 module」起因エラー | clasp push 後 Stackdriver ログ | 0 件 | Claude |
| AI エージェント API トークン消費効率 | 同一タスクの token 消費比較 (Polyrepo vs Monorepo) | 後者で削減 | Gemini |
| 依存衝突インシデント数 | PR 件数 | 0 件維持 | GPT |
8. ADR-NNNN 起案準備事項
本 Synthesis を根拠に起案する ADR は以下の構造を想定:
- Status: Proposed (初稿、Pipeline retroactive validation 不要、新規起案で順方向 validation)
- Mode: Standard (個人開発 + AI agent 主体下では Critical までは不要、Standard 閾値 40/50 を超える品質目標)
- Scope: Platform (build infrastructure 全体)
- Title 候補: 「monorepo 構成と pnpm workspaces + Turborepo 採用 (Phase 1: root 除外型から段階移行)」
- §1 Context: 本 Synthesis §1 を流用
- §2 決定: 本 Synthesis §4 を流用
- §3 判断基準: 本 Synthesis §3.2 MCDA 表を流用 (Q42 5 軸 + 案 A/B/C スコア)
- §4 代替案: 案 A (Claude 同梱) / 案 B (Gemini 分離) を「検討した代替案」として記載
- §5 影響: Phase 別の影響範囲を §6 Roadmap から抽出
- §6 撤退条件: §4.4 後戻り戦略を流用
- §7 References: 本 Synthesis + 3 LLM 結果 + Claude/Gemini/GPT 主要 citation (pnpm 公式 / Turborepo 公式 / Cloudflare Builds 公式 / Google モノレポ論文 / Nx blog 等)
- §7.2 設計根拠 (Theoretical Foundation): ADR-0065 の citation 5 タイプ準拠で 6-10 件記載
9. Meta 示唆
9.1 3 LLM 並列調査の効果検証
本 RQ-053 は ADR-0065 Pipeline validation Gate 3 と同様に 3 LLM (Claude / Gemini / GPT) の並列調査を活用したが、各モデルの 役割分担 が顕著に表れた:
- Claude: 詳細な業界事例 + 具体的 issue 番号 (Cloudflare Builds #10941, Turborepo #11144 等) + Vercel Remote Cache 無料化等の最新情報 = factual depth
- Gemini: AI コンテキスト窓効率論 + esbuild GAS bundle 構成 + apps/gas-core 分離設計 = architectural insight
- GPT (Light Deep Research): 段階的アプローチ +
git subtree後戻り保険 +pnpm approve-builds正しい解釈 = pragmatic / cautious balance
3 モデルの突合により、単独モデルでは見落としていた重要論点 (例: Cloudflare Builds 罠 / 段階的移行の現実性) を採択方針に組み込めた。これは ADR-0042 (LLM プロンプト lifecycle) で示唆される multi-model validation の有効性を実 RQ で確認した好例。
9.2 GPT Light Deep Research mode の挙動
GPT は Plus の Deep Research 上限超過のため Light mode で実行。結果は Claude/Gemini に比べ簡潔 (66 行 vs Claude 16 ページ / Gemini 13 ページ) だが、独自視点 (git subtree / pnpm approve-builds) は確実に提供。Light mode でも 3 モデル synthesis の triangulation に十分貢献することを確認。
将来は o3-deep-research の API 経由実行で更に詳細な GPT 結果を得る選択肢も検討 ([[openai-deep-research-api]])。
10. 参照リソース
10.1 本 RQ の構成要素
- Prompt:
RQ-053_monorepo_topology_prompt.md - Claude 結果:
RQ-053_monorepo_topology_result_claude.md(16 ページ転記) - Gemini 結果:
RQ-053_monorepo_topology_result_gemini.md(13 ページ転記) - GPT 結果:
RQ-053_monorepo_topology_result_gpt.md(66 行 Light mode)
10.2 関連 ADR / RQ
- ADR-0019 (drp 移行): subproject 化の先例
- ADR-0050 (Synthesis 標準テンプレート / Q42 + WSM + CBA): 本 Synthesis の評価枠組み根拠
- ADR-0054 (Lint Rule Reference SSoT): 3 層構造の先例
- ADR-0058 (frontmatter-lint SSoT): 同パターン
- ADR-0065 (設計根拠 framework): 引用形式の根拠 (本 ADR でも §7.2 を採用)
- RQ-052 (MCDA for ADR Synthesis): Synthesis テンプレ Self-bootstrapping の先例
10.3 外部引用 (3 LLM 結果から主要分のみ)
- Potvin & Levenberg (2016), "Why Google Stores Billions of Lines of Code in a Single Repository", Communications of the ACM 59(7). DOI: 10.1145/2854146
- pnpm 公式: https://pnpm.io/workspaces, https://pnpm.io/catalogs, https://pnpm.io/pnpm-workspace_yaml
- Turborepo 公式: https://turborepo.com (Vercel)
- monorepo.tools (Nx): https://monorepo.tools/
- Vercel Changelog (2024-12-22): https://vercel.com/changelog/free-vercel-remote-cache
- Cloudflare Workers Builds: https://developers.cloudflare.com/workers/ci-cd/builds/advanced-setups/
- Anthropic Best Practices: https://code.claude.com/docs/en/best-practices
- daily.dev Kramer (2026): "Monorepo in 2026: Turborepo vs Nx vs Bazel"