# 通知設計書 22-インクリメンタルビジュアライザ通知

## 概要

本ドキュメントは、Bun DevServerにおけるインクリメンタルビルドの状態をビジュアライザに送信する通知機能の設計を定義する。この通知は、開発者がインクリメンタルグラフの状態をリアルタイムで視覚化するためのデバッグ機能として使用される。

### 本通知の処理概要

この通知は、Bunのインクリメンタルバンドラーの内部状態（クライアントグラフ、サーバーグラフ、ファイル間の依存関係など）をWebSocket経由でビジュアライザクライアントに送信するデバッグ機能である。

**業務上の目的・背景**：インクリメンタルバンドリングは、ファイル変更時に影響を受けるファイルのみを再バンドルする最適化技術である。しかし、この最適化が正しく動作しているかを確認することは困難である。本通知は、開発者（特にBunの開発者自身）がインクリメンタルグラフの状態を視覚的に確認し、依存関係の追跡やスタイルファイルの検出、HMR（Hot Module Reloading）の動作を検証できるようにする。これにより、バンドラーのデバッグと最適化が容易になる。

**通知の送信タイミング**：以下のイベント発生時に送信される：
1. WebSocketクライアントが`incremental_visualizer`トピックにサブスクライブしたとき
2. バンドルが完了し、グラフに変更があったとき
3. ファイル変更によるインクリメンタル更新が発生したとき

**通知の受信者**：`incremental_visualizer`トピックにサブスクライブしているWebSocketクライアント。通常は`/_bun/incremental_visualizer`にアクセスしているブラウザウィンドウ。

**通知内容の概要**：クライアントグラフとサーバーグラフの両方について、ファイル一覧（パス、状態フラグ）とエッジ一覧（依存関係）をバイナリ形式で送信する。

**期待されるアクション**：ビジュアライザクライアントはメッセージを解析し、グラフをD3.jsなどのライブラリを使用して視覚的に描画する。開発者はこの視覚化を通じて、依存関係の問題やHMRの動作を確認できる。

## 通知種別

WebSocket通知（DevServer内部デバッグ機能）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（publish） |
| 優先度 | 低（デバッグ機能） |
| リトライ | 無し |

### 送信先決定ロジック

`HmrTopic.incremental_visualizer`トピックにサブスクライブしているすべてのWebSocketクライアントに対してブロードキャストされる。サブスクライバ数は`dev.emit_incremental_visualizer_events`で参照カウントされ、0より大きい場合にのみメッセージが生成・送信される。

## 通知テンプレート

### メッセージフォーマット

| 項目 | 内容 |
|-----|------|
| プロトコル | WebSocket |
| 形式 | バイナリ（ArrayBuffer） |
| エンコーディング | Little-endian |

### 本文テンプレート

```
MessageId.visualizer (1バイト: 'v')
├─ クライアントグラフ
│   ├─ ファイル数 (u32)
│   └─ 各ファイル:
│       ├─ パス長 (u32) - 0の場合は他のフィールドなし
│       ├─ パス (UTF-8文字列)
│       ├─ staleフラグ (u8)
│       ├─ RSCフラグ (u8)
│       ├─ SSRフラグ (u8)
│       ├─ ルートフラグ (u8)
│       ├─ 特殊フレームワークファイルフラグ (u8)
│       └─ HMRルート/コンポーネント境界フラグ (u8)
├─ サーバーグラフ (同形式)
├─ クライアントエッジ
│   ├─ エッジ数 (u32)
│   └─ 各エッジ:
│       ├─ 依存元ファイルインデックス (u32)
│       └─ インポート先ファイルインデックス (u32)
└─ サーバーエッジ (同形式)
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| file_path | ファイルの相対パス | IncrementalGraph.bundled_files | Yes |
| is_stale | ファイルが古い（再ビルド必要）か | IncrementalGraph.stale_files | Yes |
| is_rsc | React Server Componentか | bundled_file.is_rsc | Yes |
| is_ssr | SSR用ファイルか | bundled_file.is_ssr | Yes |
| is_route | ルートファイルか | bundled_file.is_route | Yes |
| dependency | 依存元ファイルのインデックス | edge.dependency | Yes |
| imported | インポート先ファイルのインデックス | edge.imported | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| サブスクライブ | WebSocket subscribe メッセージ | bake_debugging_features有効 | クライアントがトピックにサブスクライブ時 |
| バンドル完了 | emitVisualizerMessageIfNeeded呼び出し | emit_incremental_visualizer_events > 0 | バンドル処理完了後に呼び出される |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| bake_debugging_features無効 | コンパイル時フラグが無効の場合、機能全体が無効 |
| emit_incremental_visualizer_events == 0 | サブスクライバがいない場合は送信をスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[バンドル完了] --> B[emitVisualizerMessageIfNeeded呼び出し]
    B --> C{bake_debugging_features有効?}
    C -->|No| D[処理終了]
    C -->|Yes| E{emit_incremental_visualizer_events > 0?}
    E -->|No| F[emitMemoryVisualizerMessageIfNeededへ]
    E -->|Yes| G[ペイロードバッファ確保]
    G --> H[writeVisualizerMessage呼び出し]
    H --> I[クライアントグラフ書き込み]
    I --> J[サーバーグラフ書き込み]
    J --> K[クライアントエッジ書き込み]
    K --> L[サーバーエッジ書き込み]
    L --> M[publish実行]
    M --> F
    F --> D
```

## データベース参照・更新仕様

### 参照テーブル一覧

本通知はデータベースを使用しない。すべてのデータはメモリ上のインクリメンタルグラフ構造から取得される。

| 構造体名 | 用途 | 備考 |
|---------|------|------|
| IncrementalGraph(.client) | クライアント側のファイルグラフ | dev.client_graph |
| IncrementalGraph(.server) | サーバー側のファイルグラフ | dev.server_graph |

### 更新テーブル一覧

なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| メモリ不足 | ペイロード生成中にOOM | 処理を中断し、メッセージは送信されない |
| バッファオーバーフロー | グラフが極端に大きい場合 | スタックフォールバックからヒープアロケーションに切り替え |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0回（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（開発環境デバッグ機能）

## セキュリティ考慮事項

- この機能はデバッグ機能であり、`bake_debugging_features`フラグで制御される
- デフォルトではリリースビルドでは無効
- ソースコードのパス情報が含まれるため、本番環境では使用不可
- ローカル開発環境でのみ使用されることを想定

## 備考

- この機能は`/_bun/incremental_visualizer`エンドポイントで提供されるHTMLページと組み合わせて使用される
- グラフの視覚化にはクライアント側のJavaScriptが必要
- 大規模プロジェクトでは、グラフデータが大きくなる可能性がある

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

インクリメンタルグラフの構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DevServer.zig | `src/bake/DevServer.zig` | IncrementalGraph構造体の定義、client_graphとserver_graphフィールド（行68-69） |
| 1-2 | DevServer.zig | `src/bake/DevServer.zig` | HmrTopic列挙型の定義（行3925-3960）、incremental_visualizerの値 |

**読解のコツ**: Zigの`@This()`パターンに注意。`IncrementalGraph`は`DevServer`の内部で定義されている可能性がある。

#### Step 2: エントリーポイントを理解する

通知の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DevServer.zig | `src/bake/DevServer.zig` | emitVisualizerMessageIfNeeded関数（行3608-3621） |
| 2-2 | HmrSocket.zig | `src/bake/DevServer/HmrSocket.zig` | subscribeメッセージ処理（行62-106）、incremental_visualizerのon-subscribeフック（行78-82） |

**主要処理フロー**:
1. **行3609**: bake_debugging_featuresフラグチェック
2. **行3611**: emit_incremental_visualizer_eventsの参照カウントチェック
3. **行3613-3616**: スタックフォールバックバッファの確保
4. **行3618**: writeVisualizerMessageでペイロード生成
5. **行3620**: publishでトピックに配信

#### Step 3: メッセージ生成処理を理解する

ペイロードの生成ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DevServer.zig | `src/bake/DevServer.zig` | writeVisualizerMessage関数（行3705-3749） |

**主要処理フロー**:
- **行3706**: MessageId.visualizerを先頭に追加
- **行3709-3739**: クライアントとサーバーの両グラフについてファイル情報を書き込み
- **行3740-3749**: 両グラフのエッジ情報を書き込み

#### Step 4: サブスクリプション管理を理解する

クライアントのサブスクライブ/アンサブスクライブ処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | HmrSocket.zig | `src/bake/DevServer/HmrSocket.zig` | onUnsubscribe関数（行223-235）、参照カウントの管理 |

### プログラム呼び出し階層図

```
[サブスクライブ時]
HmrSocket.onMessage() [HmrSocket.zig:43]
    │
    └─ subscribe処理 [HmrSocket.zig:61-106]
           │
           ├─ ws.subscribe() [WebSocket購読]
           │
           └─ [incremental_visualizerの場合]
                  │
                  ├─ emit_incremental_visualizer_events += 1
                  └─ dev.emitVisualizerMessageIfNeeded()

[バンドル完了時]
DevServer (バンドル完了)
    │
    └─ emitVisualizerMessageIfNeeded() [DevServer.zig:3608]
           │
           ├─ bake_debugging_features チェック
           │
           ├─ emit_incremental_visualizer_events > 0 チェック
           │
           ├─ writeVisualizerMessage() [DevServer.zig:3705]
           │      │
           │      ├─ client_graph イテレート
           │      ├─ server_graph イテレート
           │      ├─ client edges イテレート
           │      └─ server edges イテレート
           │
           └─ dev.publish(.incremental_visualizer, payload)
                  │
                  └─ WebSocket broadcast
```

### データフロー図

```
[入力]                      [処理]                         [出力]

IncrementalGraph           writeVisualizerMessage        WebSocket
(client_graph)      ───▶        │                   ───▶  クライアント
                                │                         (ビジュアライザ)
IncrementalGraph                ▼
(server_graph)      ───▶   バイナリ
                           ペイロード生成
                                │
                                ▼
                           publish()
                           (.incremental_visualizer)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DevServer.zig | `src/bake/DevServer.zig` | ソース | メイン実装、emitVisualizerMessageIfNeeded、writeVisualizerMessage |
| HmrSocket.zig | `src/bake/DevServer/HmrSocket.zig` | ソース | WebSocket接続管理、サブスクリプション処理 |
| IncrementalGraph | `src/bake/DevServer.zig` 内 | ソース | グラフデータ構造の定義 |
