ガイド 第43

既存3アプリの収束計画

フェーズ別

@event/fours-sdk@event/core@event/schema@event/session-card@event/asset-kit@event/cms@event/shell

xdeal-lp / spikes-lp / ivs-cms の3アプリを、挙動を変えずに @event/* へ寄せる。一気に移さず、機能的に等価なコードから置換するのが原則(当初「バイト同一」と想定したが、実測では表層差分が多く diff 行数は当てにならない — export シグネチャとロジックの照合で判定する)(docs/ARCHITECTURE.md §8.2 の 5 フェーズ)。実行手順はレシピ converge-existing-app に Phase A の具体コード付きである。

フェーズ全体像(ARCHITECTURE.md §8.2)

Phase対象狙い / 受け入れ条件
Afours-sdk / core / schema抽出 & 並走。バイト同一ファイルから置換(挙動変更ゼロ)
Bsession-card / asset-kit4コピー balance engine + 約10の toPng を統合。最大の LOC 削減
Ccms / shellcontentStore + 認証を統一。id/_id 統一・lazy DB client
Dfeature modulesfeedback/spatial(ivs)・booking/mailer(xdeal)・networking(spikes)
Eexamples 化3アプリを薄い re-skin にし、starter が唯一の fork 元になる

Phase A — 抽出 & 並走(挙動変更なし)

各アプリはパッケージを deps に足しつつ自前コピーも残す。バイト同一のものから移す(差し替えても挙動が変わらない):

  1. 4S セッションハンドオフsrc/lib/4s-session/* は xdeal↔ivs で byte-identical(origin 文字列と quote style だけが違う)。consumeHandoff / tokenStore / use4SSession@event/fours-sdk/clientverify4SUser(3アプリで同じ約30行)→ @event/fours-sdkcreateLoginProxyHandler / createCognitoRefreshHandler → route を factory に
  2. 死コード削除 — 分析で確認済み: xdeal の 1,457行 ScheduleMap.tsx(未使用)、four-s.ts の OAuth stub(FOUR_S_OAUTH_* 未設定)
  3. contentStore / auth@event/corecreateContentStore(ivs canonical + sha リトライ統合版)と createSharedPasswordAuth(constant-time 統一 — spikes の平文 === を修正)へ
  4. 検証 — 各置換ごとに型チェック + 該当フローを1つ手で叩いて挙動一致を確認してから次へ

収束の3段構え — バイト同一 → 採取元 JSDoc → 段階収束

パッケージ化の作法は「バイト同一のものを最初に、採取元を JSDoc に記録し、段階的に寄せる」の3段:

  • バイト同一ファイル置換 — Phase A の 4s-session/* のように、3アプリで既に一致しているコードは差し替えてもリスクゼロ。ここから着手する
  • 採取元 JSDoc(@harvested-from — パッケージ側は必ず採取元を記録する。例: @harvested-from ivs-cms src/lib/titleBreak.ts。どのアプリのどのファイルを起源に一般化したかが追える(packages/*/src/index.ts 冒頭に集約)
  • 段階収束 — Phase B 以降は「最も重複が多く drift しやすいコードほど先」。session-card の4コピー balance engine(最多重複)→ 約10の toPng フロー → id 統一、と1論理単位=1コミットで進める

Phase B 以降のポイント

  • B: 4コピー balance engine → @event/session-card/engine(各アプリは theme token だけ残す)。約10の ad-hoc toPng@event/asset-kit。最も drift しやすく payoff が最大
  • C: 3アプリを @event/cms contentStore(ivs の楽観ロック版)+ @event/shell へ。requireRealm ガードが ivs(再検査0)/ spikes(1)のギャップを塞ぐ
  • D: 相互受粉 — xdeal は per-item カード調整 + 楽観 PATCH を、spikes は i18n + SEO + セキュリティヘッダを、ivs は CSP + Sentry を得る
  • E: 収束後、3アプリは契約を証明する薄い re-skin(examples/)になる。今後の新イベントは常に starter/ から fork する

統治ルール

イベントアプリにエンジンコードを残さない。 新イベントがロジックを要するなら、fork ではなく config knob 付きでパッケージに落とす。「エンジンはパッケージへ、アプリには config だけ」が収束後も維持すべき唯一の線である。