# 画面設計書 16-スキップ済みプロジェクト通知

## 概要

プロジェクト読み込みがスキップされた場合に `coded/skippedLoads` 通知をクライアントに送信し、スキップされたプロジェクトの一覧を通知する画面の設計書である。

### 本画面の処理概要

本画面は、manyProjectsThreshold（多数プロジェクト閾値）を超えるサブプロジェクトが検出され、bundleAskLoadsフラグがtrueの場合にプロジェクト読み込みがバッチスキップされた際に、クライアントへスキップされたプロジェクトルートの一覧を `coded/skippedLoads` 通知で送信する処理を担当する。

**業務上の目的・背景**：大規模なワークスペースでは多数のサブプロジェクトが存在する場合がある。全てのプロジェクトを自動的に読み込むとリソース消費が大きくなるため、閾値を超えたプロジェクトの読み込みをスキップする機能がある。スキップされたプロジェクトの情報をクライアントに通知することで、ユーザーが必要に応じて `served/forceLoadProjects` で強制読み込みを要求できるようにする。

**画面へのアクセス方法**：本通知はワークスペース初期化時に自動的にトリガーされる。manyProjectsActionが"ask"でbundleAskLoadsがtrueの場合、プロジェクトがskippedRootsに追加され、500msのデバウンス後に通知が送信される。

**主要な操作・処理内容**：
1. delayedProjectActivation内でプロジェクト数が閾値を超えた場合の判定
2. manyProjectsActionが"ask"でbundleAskLoadsがtrueの場合、プロジェクトをskippedRootsに追加
3. notifySkippedRoots関数が呼ばれ、500msのデバウンスタイマーを設定
4. タイマー発火後に `coded/skippedLoads` 通知をSkippedLoadsNotificationと共に送信

**画面遷移**：本通知の前段階として、ワークスペーススタートアップ（No.3）でサブプロジェクトの検出が行われる。本通知の後、クライアントはforceLoadProjects（No.67）を呼び出してスキップされたプロジェクトの強制読み込みを要求できる。

**権限による表示制御**：権限による表示制御は存在しない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | プロジェクト強制ロード (served/forceLoadProjects) | 遷移先機能 | スキップされたプロジェクトに対してクライアントがforceLoadProjectsで強制読み込みを要求できる |

## 画面種別

通知（カスタム通知）

## URL/ルーティング

LSPカスタム通知: `coded/skippedLoads`（サーバーからクライアントへの通知）

パラメータ: `SkippedLoadsNotification` 構造体

## 入出力項目

| 項目名 | 型 | 入力/出力 | 説明 |
|--------|-----|----------|------|
| skippedRoots | string[] | 出力 | スキップされたプロジェクトルートパスの配列 |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| スキップされたプロジェクト一覧 | リスト | クライアント側でスキップされたプロジェクトの一覧を表示し、強制読み込みの操作を提供 |

## イベント仕様

### 1-プロジェクトスキップ検出

delayedProjectActivation関数内でプロジェクト数が閾値を超え、bundleAskLoadsがtrueの場合:

1. **752行目**: skippedRootsにワークスペースルートを追加
2. **753行目**: notifySkippedRoots()を呼び出し
3. **754行目**: ManyProjectsAction.skipへgoto（プロジェクト読み込みをスキップ）

### 2-デバウンス付き通知送信

notifySkippedRoots関数:

1. **916行目**: 既存タイマーをクリア
2. **917行目**: 500msのsetTimeoutデリゲートを設定
3. **918-919行目**: タイマー発火後に `coded/skippedLoads` 通知をSkippedLoadsNotification(skippedRoots)と共に送信

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | なし | なし | データベースアクセスなし |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 条件 |
|-------------|------|---------------|------|
| なし | 通知 | coded/skippedLoads（SkippedLoadsNotification） | プロジェクトがスキップされた場合 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| skippedRootsが空の場合 | 通知は送信されるが、空のリストとなる |
| forceLoadProjectsで読み込まれた場合 | skippedRootsからそのルートが削除される（776行目） |

## 備考

- coded/skippedLoadsはserve-d独自のカスタムLSP通知であり、標準LSPプロトコルには含まれない
- 500msのデバウンスにより、複数プロジェクトのスキップが連続して発生しても通知は1回にまとめられる
- bundleAskLoadsフラグは、ダイアログを個別に表示する代わりにバッチ処理でスキップする場合にtrueとなる
- delayedProjectActivation内の776行目で、forceLoadProjectsによる読み込み時にskippedRootsからルートが削除される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | extension.d | `source/served/extension.d` | skippedRoots変数（726行目）：スキップされたルートパスの配列 |
| 1-2 | extension.d | `source/served/extension.d` | bundleAskLoads変数（724行目）：バッチスキップフラグ |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | delayedProjectActivation関数（727-912行目）の749-754行目がスキップ判定のエントリーポイント |

**主要処理フロー**:
1. **743行目**: manyProjectsAction取得
2. **744行目**: manyThreshold取得
3. **745行目**: numLoaded > manyThresholdの判定
4. **749-754行目**: bundleAskLoadsがtrueの場合、skippedRootsに追加してnotifySkippedRoots呼び出し

#### Step 3: 通知送信を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | notifySkippedRoots関数（914-921行目）のデバウンス付き通知送信 |

**主要処理フロー**:
- **916行目**: `clearTimeout(timer)` 既存タイマーのクリア
- **917行目**: `timer = setTimeout(delegate() { ... }, 500.msecs)` 500msデバウンス
- **919行目**: `rpc.notifyMethod("coded/skippedLoads", SkippedLoadsNotification(skippedRoots))` 通知送信

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

```
delayedProjectActivation() [extension.d:727]
    |
    +-- [numLoaded > threshold && bundleAskLoads]
            |
            +-- skippedRoots ~= workspaceRoot [extension.d:752]
            +-- notifySkippedRoots() [extension.d:753]
            |       |
            |       +-- clearTimeout(timer) [extension.d:916]
            |       +-- setTimeout(500ms) [extension.d:917]
            |               |
            |               +-- rpc.notifyMethod("coded/skippedLoads", ...) [extension.d:919]
            |
            +-- goto ManyProjectsAction.skip [extension.d:754]
                    +-- backend.removeInstance(workspaceRoot) [extension.d:770]
```

### データフロー図

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

プロジェクト数         +-- delayedProjectActivation     +-- coded/skippedLoads通知
（閾値超過）                |                                  (SkippedLoadsNotification)
                             +-- skippedRoots追加
bundleAskLoads              +-- notifySkippedRoots       +-- クライアント側でUI表示
（バッチフラグ）             +-- 500msデバウンス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | notifySkippedRoots関数（914-921行目）、delayedProjectActivation（727-912行目） |
| types.d | `source/served/types.d` | ソース | rpcグローバル変数の定義 |
