# 通知設計書 17-coded/skippedLoads

## 概要

本ドキュメントは、カスタム通知 `coded/skippedLoads` の設計仕様を定義する。この通知はサーバー（serve-d）からクライアント（エディタ）に送信され、ロードがスキップされたワークスペースルートの一覧をクライアントに通知する。

### 本通知の処理概要

`coded/skippedLoads` 通知は、ワークスペース内のサブプロジェクト数が閾値（`manyProjectsThreshold`）を超え、かつ `manyProjectsAction` が `"ask"` で `bundleAskLoads` が有効な場合にロードがスキップされたルート一覧をクライアントに送信する通知である。`SkippedLoadsNotification` 構造体（`roots` フィールド）が送信される。

**業務上の目的・背景**：大規模なワークスペースでは多数のサブプロジェクト（Dubパッケージ）が含まれることがあり、全てをロードするとパフォーマンスに影響する。閾値を超えたプロジェクトはスキップされ、そのことをクライアントに通知することで、ユーザーが必要に応じて手動でプロジェクトをロードできるようにする。

**通知の送信タイミング**：`delayedProjectActivation` 関数内で、プロジェクト数が閾値を超え、かつ `bundleAskLoads` が有効で `manyProjectsAction` が `"ask"` の場合に送信される。500ミリ秒のデバウンスタイマーにより、複数のスキップが短時間に発生した場合は最後の1回にまとめられる。

**通知の受信者**：LSPクライアント（エディタ拡張機能）が受信する。

**通知内容の概要**：`SkippedLoadsNotification` 構造体が送信され、`roots` フィールドにスキップされたプロジェクトルートのファイルパスの配列が含まれる。

**期待されるアクション**：クライアントはスキップされたプロジェクトの一覧をユーザーに表示し、必要に応じて `served/forceLoadProjects` リクエストで個別にロードできるUIを提供する。

## 通知種別

LSPカスタム通知（JSON-RPC notification）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（500msデバウンス付き） |
| 優先度 | 低 |
| リトライ | 無し |

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

サーバーからクライアントへの一方向通知。LSP接続で確立されたクライアントプロセスに固定。

## 通知テンプレート

### JSON-RPC通知メッセージ

| 項目 | 内容 |
|-----|------|
| メソッド名 | `coded/skippedLoads` |
| パラメータ型 | `SkippedLoadsNotification` |
| レスポンス | なし（通知） |

### メッセージ構造

```json
{
  "jsonrpc": "2.0",
  "method": "coded/skippedLoads",
  "params": {
    "roots": [
      "/path/to/project1",
      "/path/to/project2"
    ]
  }
}
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| roots | スキップされたプロジェクトルートのファイルパス配列 | グローバル変数 `skippedRoots` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部処理 | プロジェクトロードスキップ | bundleAskLoads==true かつ manyProjectsAction=="ask" かつ numLoaded > manyThreshold | delayedProjectActivation内（extension.d L749-754） |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| bundleAskLoads==false | bundleAskLoadsが無効の場合、個別にwindow/showMessageRequestで確認する |
| manyProjectsAction!="ask" | "load"の場合は全てロード、"skip"の場合は通知なくスキップ |
| 閾値未満 | numLoadedがmanyProjectsThreshold以下の場合はスキップ自体が発生しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[delayedProjectActivation] --> B{numLoaded > manyThreshold?}
    B -->|No| C[通常ロード]
    B -->|Yes| D{manyProjectsAction}
    D -->|ask| E{bundleAskLoads?}
    D -->|load| C
    D -->|skip| F[スキップ（通知なし）]
    E -->|Yes| G[skippedRootsに追加]
    G --> H[notifySkippedRoots呼び出し]
    H --> I[500msデバウンスタイマー]
    I --> J[coded/skippedLoads送信]
    E -->|No| K[window/showMessageRequestで個別確認]
    J --> L[終了]
```

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

### 参照テーブル一覧

該当なし（データベースを使用しない）。

### 更新テーブル一覧

該当なし。グローバル変数 `skippedRoots`（string[]）の管理のみ。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| クライアント未対応 | クライアントがcoded/skippedLoadsをハンドリングしない | スキップされたプロジェクトは手動で確認する必要がある |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（500msデバウンスあり） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。ワークスペース初期化時に送信。

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

- ファイルパス情報がrootsフィールドに含まれる
- ユーザーのディレクトリ構造が漏洩する可能性があるが、クライアント-サーバー間の通信のため影響は限定的

## 備考

- `skippedRoots` はグローバル変数（extension.d L726）で管理される
- プロジェクトが後からロードされた場合、`skippedRoots` から該当ルートが除去される（extension.d L776）
- `notifySkippedRoots` 関数（extension.d L914-921）は500msのデバウンスタイマーを使用し、短時間に複数のスキップが発生した場合に通知を1回にまとめる
- `SkippedLoadsNotification` 構造体は `served/lsp/protoext.d` L531-536で定義されている

---

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

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

### 推奨読解順序

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

通知パラメータの構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protoext.d | `source/served/lsp/protoext.d` | `SkippedLoadsNotification` 構造体（L531-536）の定義 |

**読解のコツ**: `roots` フィールドはファイルパスの文字列配列（`string[] roots`）である。

#### Step 2: 送信関数を理解する

notifySkippedRoots関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | `notifySkippedRoots` 関数（L914-921）のデバウンス実装 |

**主要処理フロー**:
1. **L916**: static変数 `timer` でデバウンスタイマーを管理
2. **L917**: 前回のタイマーをクリア
3. **L918-920**: 500msのsetTimeoutでcoded/skippedLoadsを送信

#### Step 3: トリガー元を理解する

delayedProjectActivation内のスキップ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | `delayedProjectActivation` 関数（L727-912）のL741-773のmanyProjectsAction処理 |

**主要処理フロー**:
- **L743-745**: manyProjectsAction設定とmanyThreshold閾値の取得
- **L749-754**: bundleAskLoadsが有効な場合、skippedRootsに追加しnotifySkippedRootsを呼び出す
- **L776**: 後からロードされた場合にskippedRootsから除去

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

```
delayedProjectActivation (extension.d:727)
    |
    +-- [numLoaded > manyThreshold かつ manyProjectsAction=="ask"]
            |
            +-- [bundleAskLoads==true]
                    |
                    +-- skippedRoots ~= workspaceRoot (L752)
                    +-- notifySkippedRoots() (L753)
                            |
                            +-- clearTimeout(timer) (L917)
                            +-- setTimeout(500ms) (L918)
                                    |
                                    +-- rpc.notifyMethod("coded/skippedLoads",
                                            SkippedLoadsNotification(skippedRoots)) (L919)
```

### データフロー図

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

プロジェクトロード         delayedProjectActivation()      coded/skippedLoads
(閾値超過)            --> (extension.d:727-773)           {roots: [...]}
                          |                                    |
                          +-- notifySkippedRoots()             v
                              (extension.d:914-921)       クライアント:
                              [500msデバウンス]             スキップされたプロジェクト表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| protoext.d | `source/served/lsp/protoext.d` | ソース | SkippedLoadsNotification構造体の定義 |
| extension.d | `source/served/extension.d` | ソース | notifySkippedRoots関数およびdelayedProjectActivation内のスキップ処理 |
