# 帳票設計書 12-serve-dサーバー情報レポート

## 概要

本ドキュメントは、serve-dサーバーが提供する「serve-dサーバー情報レポート」の帳票設計を定義する。serve-dサーバーの状態情報（サーバーバージョン、現在の設定、モジュールインデックス、ワークスペース状態、実行中タスク一覧）をJSON形式で出力する。

### 本帳票の処理概要

本帳票は、serve-d言語サーバーの総合的な状態情報をJSON形式で出力する機能である。LSPプロトコルの `served/getInfo` リクエストを介して呼び出され、サーバーの内部状態を包括的にレポートする。

**業務上の目的・背景**：D言語のLSP（Language Server Protocol）サーバーであるserve-dは、複数のワークスペースやコンポーネントを管理する複雑なシステムである。開発者やツール開発者がサーバーの動作状態を把握し、問題の診断やデバッグを行うために、サーバーの内部状態を一元的に取得できる仕組みが必要となる。本帳票はその要件を満たすものである。

**帳票の利用シーン**：エディタ拡張機能の開発・デバッグ時、serve-dサーバーの動作不具合の調査時、サーバーのパフォーマンス監視時、ワークスペースの初期化状態の確認時に利用される。特に、タスクの実行状況やワークスペースのエラー状態を確認する際に重要な情報源となる。

**主要な出力内容**：
1. サーバー情報（名前、バージョン）
2. 現在のユーザー設定（Configuration）
3. モジュールインデックス（依存関係の逆引き情報）
4. グローバルワークスペースおよび全ワークスペースの状態
5. 実行中・最近完了したタスクの一覧

**帳票の出力タイミング**：エディタ拡張機能から `served/getInfo` リクエストが送信された時点で出力される。デバッグコマンドやステータス確認操作によりトリガーされる。

**帳票の利用者**：D言語で開発を行うソフトウェアエンジニア、エディタ拡張機能（code-d等）の開発者、serve-dサーバーの運用・デバッグ担当者。

## 帳票種別

集計表（サーバー状態レポート）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | エディタ（VSCode等）のデバッグ・ステータス画面 | LSP: `served/getInfo` | エディタ拡張機能のコマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON（LSPレスポンス） |
| 用紙サイズ | N/A（データ形式出力） |
| 向き | N/A |
| ファイル名 | N/A（LSPレスポンスとして返却） |
| 出力方法 | LSP JSON-RPCレスポンス |
| 文字コード | UTF-8 |

### PDF固有設定

該当なし（JSON形式のLSPレスポンス）

### Excel固有設定

該当なし（JSON形式のLSPレスポンス）

## 帳票レイアウト

### レイアウト概要

LSPレスポンスとして `ServedInfoResponse` 構造体をJSON形式で返却する。リクエストパラメータにより含まれる情報が変動する。

```
┌──────────────────────────────────────────────┐
│  ServedInfoResponse                          │
│  ├─ serverInfo                               │
│  │   ├─ name: "serve-d"                      │
│  │   └─ version: "vX.Y.Z"                    │
│  ├─ currentConfiguration (optional)          │
│  │   └─ Configuration全体                     │
│  ├─ moduleIndex (optional)                   │
│  │   └─ { module: [dependants...] }          │
│  ├─ globalWorkspace                          │
│  │   ├─ uri, name, initialized, selected      │
│  │   └─ pendingErrors                        │
│  ├─ workspaces[]                             │
│  │   └─ WorkspaceState (同上構造)             │
│  ├─ selectedWorkspaceIndex                   │
│  └─ runningTasks[] (optional)                │
│      └─ Task{ name, queued, started, ... }   │
└──────────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | serverInfo.name | サーバー名 | makeServerInfo() | 文字列（"serve-d"固定） |
| 2 | serverInfo.version | サーバーバージョン | served.info.Version | "vX.Y.Z"形式 |
| 3 | selectedWorkspaceIndex | 選択中ワークスペースのインデックス | workspaces配列内走査 | 整数（-1はグローバル） |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | currentConfiguration | 現在の設定全体 | config(selectedWorkspaceUri) | Configuration構造体JSON | 可変 |
| 2 | moduleIndex | モジュール依存関係逆引き | IndexComponent.dumpReverseImports() | { module: string[] } | 可変 |
| 3 | globalWorkspace.uri | グローバルワークスペースURI | fallbackWorkspace.describeState() | DocumentUri文字列 | 可変 |
| 4 | globalWorkspace.name | グローバルワークスペース名 | 同上 | 文字列 | 可変 |
| 5 | globalWorkspace.initialized | 初期化済みフラグ | 同上 | boolean | 可変 |
| 6 | globalWorkspace.selected | 選択フラグ | 同上 | boolean | 可変 |
| 7 | globalWorkspace.pendingErrors | 起動エラー情報 | 同上 | { path: errorMsg } | 可変 |
| 8 | workspaces[].uri | 各ワークスペースのURI | workspaces[].describeState() | DocumentUri文字列 | 可変 |
| 9 | workspaces[].name | 各ワークスペースの名前 | 同上 | 文字列 | 可変 |
| 10 | workspaces[].initialized | 初期化済みフラグ | 同上 | boolean | 可変 |
| 11 | workspaces[].selected | 選択フラグ | 同上 | boolean | 可変 |
| 12 | runningTasks[].name | タスク名 | FiberManager.fiberInfos | 文字列 | 可変 |
| 13 | runningTasks[].queued | キュー投入からの経過秒数 | MonoTime計算 | float（秒） | 可変 |
| 14 | runningTasks[].started | 実行開始からの経過秒数 | MonoTime計算 | float（秒） | 可変 |
| 15 | runningTasks[].ended | 終了からの経過秒数 | MonoTime計算 | float（秒、0は実行中） | 可変 |
| 16 | runningTasks[].running | 実行中フラグ | Fiber.State判定 | boolean | 可変 |
| 17 | runningTasks[].numSteps | 再開回数 | FiberInfo.numSteps | 整数 | 可変 |
| 18 | runningTasks[].timeSpent | 合計実行時間（秒） | FiberInfo.timeSpent | float（秒） | 可変 |

### フッター部

該当なし

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| includeConfig | trueの場合、現在の設定をレスポンスに含める | No（デフォルト: false） |
| includeIndex | trueの場合、モジュールインデックスをレスポンスに含める | No（デフォルト: false） |
| includeTasks | trueの場合、実行中タスク一覧をレスポンスに含める | No（デフォルト: false） |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | workspaces | 登録順（配列インデックス順） |
| 2 | runningTasks | FiberManager内部の管理順 |

### 改ページ条件

該当なし（JSON形式で一括返却）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| workspaces配列（メモリ） | ワークスペース状態の取得 | 全件走査 |
| FiberManager（メモリ） | タスク情報の取得 | fiberInfos + recentlyEnded |
| IndexComponent（メモリ） | モジュールインデックスの取得 | 選択中ワークスペースのインスタンス |
| Configuration（メモリ） | ユーザー設定の取得 | selectedWorkspaceUri |

### テーブル別参照項目詳細

#### workspaces配列

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| folder.uri | workspaces[].uri | 全件 | describeState()メソッド経由 |
| folder.name | workspaces[].name | 全件 | 同上 |
| initialized | workspaces[].initialized | 全件 | 同上 |
| selected | workspaces[].selected / selectedWorkspaceIndex | 全件 | selected==trueの最初のインデックス |

#### FiberManager

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| fiberInfos | runningTasks[] | includeTasks==true時 | recentlyEndedも結合 |
| info.name | runningTasks[].name | 同上 | ネストタスクの場合プレフィックス付加 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| queued | `(MonoTime.currTime - info.queueTime).total!"hnsecs" / 10_000_000.0` | N/A | 秒単位のfloat |
| started | `(MonoTime.currTime - info.startTime).total!"hnsecs" / 10_000_000.0` | N/A | startTimeが初期値の場合は0 |
| ended | `(MonoTime.currTime - info.endTime).total!"hnsecs" / 10_000_000.0` | N/A | endTimeが初期値の場合は0 |
| timeSpent | `info.timeSpent.total!"hnsecs" / 10_000_000.0` | N/A | Fiber実行時間の累計 |
| running | `info.fiber.state != Fiber.State.TERM` | N/A | Fiberの終了状態で判定 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[served/getInfoリクエスト受信] --> B[ServedInfoParamsパース]
    B --> C[serverInfo構築 - makeServerInfo]
    C --> D{includeConfig?}
    D -->|Yes| E[selectedWorkspaceUri取得 → config読み込み]
    D -->|No| F{includeIndex?}
    E --> F
    F -->|Yes| G[選択中ワークスペースのIndexComponent.dumpReverseImports]
    F -->|No| H{includeTasks?}
    G --> H
    H -->|Yes| I[FiberManager走査 → Task配列構築]
    H -->|No| J[fallbackWorkspace.describeState → globalWorkspace]
    I --> J
    J --> K[workspaces全件 → describeState → workspaces配列]
    K --> L[selectedWorkspaceIndex計算]
    L --> M[ServedInfoResponse返却]
    M --> N[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| インスタンスなし | includeIndex指定時にワークスペースインスタンスが取得できない | N/A（moduleIndex省略） | moduleIndexフィールドが空のまま返却 |
| IndexComponent未ロード | インスタンスにIndexComponentがアタッチされていない | N/A（moduleIndex省略） | moduleIndexフィールドが空のまま返却 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | ワークスペース: 1-10件、タスク: 0-100件 |
| 目標出力時間 | 200ms以下 |
| 同時出力数上限 | LSPリクエストキューに依存（通常1件） |

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

本帳票はサーバーの内部状態（ファイルパス、設定値等）を出力するため、信頼できるクライアントからのリクエストのみに応答する必要がある。LSPプロトコルの通信チャネル（標準入出力）のセキュリティに依存する。

## 備考

- `serverInfo` は非ユニットテストビルド時のみ `makeServerInfo()` から構築される。ユニットテスト構成ではserved.infoモジュールが除外される
- `includeTasks` がtrueの場合、ネストされたFiberの情報も再帰的に収集される（`addTasks` 関数の再帰呼び出し）
- `selectedWorkspaceIndex` は workspaces 配列内でselectedフラグが立っている最初の要素のインデックス。見つからない場合は-1

---

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

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

### 推奨読解順序

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

まず、リクエスト/レスポンスのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protoext.d | `source/served/lsp/protoext.d` | `ServedInfoParams`構造体（354-361行目）。リクエストの3つのオプションフラグ定義 |
| 1-2 | protoext.d | `source/served/lsp/protoext.d` | `ServedInfoResponse`構造体（364-413行目）。レスポンスの全フィールド定義 |
| 1-3 | protoext.d | `source/served/lsp/protoext.d` | `ServedInfoResponse.Task`内部構造体（369-384行目）。タスク情報のフィールド定義 |

**読解のコツ**: `@serdeOptional` アノテーションが付いたフィールドはJSONシリアライズ時にnull/空の場合省略される。`Optional!T` 型は値が設定されていない場合にフィールド自体が出力されない。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | `getServedInfo`関数（1226-1314行目）。`@protocolMethod("served/getInfo")` で登録されたLSPメソッドハンドラ |

**主要処理フロー**:
1. **1226行目**: `@protocolMethod("served/getInfo")` でLSPメソッドとして登録
2. **1229-1234行目**: serverInfoの構築。非ユニットテスト時に `makeServerInfo()` を呼び出し
3. **1236-1240行目**: `includeConfig` チェック。trueの場合、`selectedWorkspaceUri` を基に設定を取得
4. **1242-1262行目**: `includeIndex` チェック。trueの場合、選択中ワークスペースの `IndexComponent.dumpReverseImports()` を取得
5. **1264-1300行目**: `includeTasks` チェック。trueの場合、`lspRouter.fibers` からFiber情報を収集しTask配列を構築
6. **1302-1303行目**: `fallbackWorkspace.describeState` と `workspaces.map!"a.describeState"` でワークスペース状態を取得
7. **1305-1311行目**: `selectedWorkspaceIndex` を計算（selectedフラグが立った最初のワークスペースのインデックス）

#### Step 3: サーバー情報構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | `makeServerInfo`関数（334-349行目）。`served.info` モジュールからバージョン情報を取得 |

**主要処理フロー**:
- **342-345行目**: `ServerInfo` 構造体を構築。name="serve-d"、version_はVersion配列とVersionSuffixから生成

#### Step 4: ワークスペース状態記述を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | types.d | `source/served/types.d` | `Workspace.describeState`プロパティ（301-318行目）。ワークスペースの状態をWorkspaceState構造体に変換 |

**主要処理フロー**:
- **303-308行目**: `WorkspaceState` 内部構造体定義（uri, name, initialized, selected, pendingErrors）
- **310-317行目**: Workspaceの各フィールドからWorkspaceStateへの変換

#### Step 5: タスク情報収集を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | extension.d | `source/served/extension.d` | `getServedInfo`関数内のタスク収集ロジック（1264-1300行目）。`addTasks` ローカル関数の再帰処理 |

**主要処理フロー**:
- **1269-1271行目**: `toSeconds` ヘルパー関数。Duration を秒単位のdoubleに変換
- **1277-1296行目**: `addTasks` ローカル関数。FiberManagerからFiber情報を走査しTask構造体を構築
- **1279行目**: `fiberInfos ~ recentlyEnded` で現在実行中と最近終了したタスクを結合
- **1294-1295行目**: ネストされたFiberの情報を再帰的に取得（`info.nested`）

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

```
served/getInfo (LSPリクエスト)
    │
    ├─ extension.getServedInfo()                    [extension.d:1226-1314]
    │      │
    │      ├─ makeServerInfo()                       [extension.d:334-349]
    │      │      └─ served.info.Version             [バージョン情報取得]
    │      │
    │      ├─ [includeConfig] config(uri)            [types.d:489-493]
    │      │      └─ workspace(uri).config           [Configuration取得]
    │      │
    │      ├─ [includeIndex]
    │      │      ├─ backend.getInstance()           [ワークスペースインスタンス取得]
    │      │      └─ IndexComponent.dumpReverseImports() [逆引きインデックス取得]
    │      │
    │      ├─ [includeTasks]
    │      │      └─ addTasks(lspRouter.fibers)      [再帰的Fiber情報収集]
    │      │             └─ addTasks(info.nested)    [ネストFiber]
    │      │
    │      ├─ fallbackWorkspace.describeState()      [types.d:301-318]
    │      └─ workspaces.map!"a.describeState"       [types.d:301-318]
    │
    └─ [LSP JSON-RPCレスポンス送信]
```

### データフロー図

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

ServedInfoParams          ───▶  extension.getServedInfo()      ───▶  ServedInfoResponse
  ├─ includeConfig               │                                    (JSON)
  ├─ includeIndex                ├─ makeServerInfo() → serverInfo
  └─ includeTasks                ├─ config() → currentConfiguration
                                 ├─ dumpReverseImports() → moduleIndex
served.info.Version       ───▶  ├─ describeState() → workspaces
Workspace[] (メモリ)      ───▶  └─ FiberManager → runningTasks
FiberManager (メモリ)     ───▶
IndexComponent (メモリ)   ───▶
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | getServedInfo関数、makeServerInfo関数の定義 |
| protoext.d | `source/served/lsp/protoext.d` | ソース | ServedInfoParams, ServedInfoResponse, Task構造体の定義 |
| types.d | `source/served/types.d` | ソース | Workspace構造体、describeState、Configuration定義 |
| fibermanager.d | `source/served/utils/fibermanager.d` | ソース | FiberManager、FiberInfo（タスク情報管理） |
| info.d | `source/served/info.d` | ソース | Version、VersionSuffix定数（バージョン情報） |
