# アプリ構造と実行時エラー

`bunx guren graph` は、アプリのルート、コントローラー、モデル、Inertia ページ、ミドルウェア、バリデーター、ポリシー、テストと、それらを結ぶ根拠を出力します。`bunx guren runtime:errors` は、開発中のアプリで最近起きたサーバーエラーを一覧します。コーディングエージェントは同じデータを MCP で読めて、Dev Center ではどちらもブラウザで確認できます。

| ツール | 開発サーバーが必要か | 節 |
|---|---|---|
| `guren graph` | 不要（ディスク上のプロジェクトを読む） | [アプリケーショングラフ](#アプリケーショングラフ) |
| `guren runtime:errors` | 必要（MCP エンドポイントを有効にする） | [実行時エラー](#実行時エラー) |
| コーディングエージェント向けの MCP ツール | 必要（MCP エンドポイントを有効にする） | [コーディングエージェントから読む](#コーディングエージェントから読む) |
| Dev Center | 必要（MCP エンドポイントを有効にする） | [Dev Center](#dev-center) |

雛形の `bun run dev` は、MCP エンドポイント（`GUREN_MCP=1`）とドキュメントビューアー（`GUREN_DOCS=1`）を最初から有効にしています。以下のコマンドは、`dev` スクリプトで有効にしていないアプリ向けに環境変数を明示しています。どれも開発用のツールです。本番環境では、実行時エラーの収集も Dev Center も有効になりません。

## アプリケーショングラフ

```bash
bunx guren graph --json
bunx guren graph --json --no-introspect
```

結果には `schemaVersion`、`snapshot`、`nodes`、`edges`、`unresolved`、`coverage` が含まれます。JSON Schema は `node_modules/@guren/cli/assets/application-graph.schema.json` にあります。ID ではファイルとモジュールを区別し、重複したルートにも個別の ID と登録順を残します。名前が一致するだけの関係は、未解決として扱います。

### グラフの集め方

通常は別プロセスでアプリを登録し、起動処理は実行しません。ただし、クラスとスキーマを照合するためにコントローラー、バインド先モデル、バリデーターのファイルを読み込むので、ファイル直下のコードは実行されます。

`--no-introspect` を付けると、ソースだけを解析します。このとき、登録済みのルートとミドルウェア、ルートから出る関係（`handles`、`binds`、`usesMiddleware`、`tests`）は `unavailable`（取得不能）になります。`validates` と `authorizes` は、ソースから読める分だけを不完全な結果として返します。

### 関係ごとの読み取り元

それぞれの関係は、ほかのコマンドが使っている解析処理から作ります。

- `handles`、`binds`、`usesMiddleware` は登録済みルートから読みます。ミドルウェアのノードは、ルーターに登録されたエイリアスとグループです。インラインのミドルウェアは関数名が重なることがあって識別できないので、未解決のまま残します。`app.use()` でアプリ全体に追加したミドルウェアはルートのチェーンに含まれないため、グラフには現れません。
- `validates` は、コントローラーが `validateBody()`、`validateQuery()`、`validateParams()` に渡すバリデーターと、ルートの `params`、`query`、`body` の契約スキーマにあたるバリデーターを結びます。コントローラーのファイル内など、バリデーターのファイル以外で宣言したスキーマは未解決になります。
- `authorizes` は、アクションがポリシークラスを import して参照している場合にだけ、コントローラーとポリシーを結びます。`this.authorize()` や `this.can()` が使うポリシーは、プロバイダーが起動時に `gate.policy()` で登録します。グラフは起動処理を実行しないので、これらはモデル名に対応するポリシーを候補に挙げたまま未解決にします。認可ミドルウェアも同じ扱いです。グラフ上でモデルとコントローラーがつながっていても、認可されているとは限りません。
- `tests` は、テストファイルと、その中の `TestApp` のリクエストが届くルートを結びます。読み取り方は、計画ページの [Impact](./implementation-plan-verification.md#impact) と同じです。リクエストが見つかっても、テストが通るとは限りません。どの登録済みルートにも届かないリクエストは未解決として一覧に載せますが、範囲は不完全として扱いません。

任意のディレクトリがまだなければ空として扱い、読み取れないソースや未対応の記法は不完全な結果として報告します。古いサーバーからモデルの識別情報を取得できない場合も、関係を推測しません。

### 終了コードとスナップショット

すべての範囲を取得でき、途中でソースが変わらなければ終了コードは 0 です。取得不能や不完全な範囲がある場合、または取得中にソースが変わった場合は、**グラフを標準出力に残したまま終了コード 1 を返します。** ゲート経由で認可するアプリや、インラインのミドルウェアを使うアプリはこの状態になるので、終了コードが 1 でも JSON を読み取ってください。取得自体に失敗した場合や、出力が 8 MiB を超えた場合は、次の形式で返します。

```json
{ "schemaVersion": 1, "error": { "code": "…", "message": "…" } }
```

スナップショットのハッシュには取得時刻を含めず、グラフとソースの内容を反映します。再取得すると、未コミットの編集も反映されます。登録処理の前後でプロジェクト内のファイルを比較し、変更があれば `snapshot.consistency` を `changed` にします。依存パッケージ、ドットファイル、生成済みのビルドディレクトリは比較の対象外です。スナップショットが一致しても、ファイルシステム全体が同じ時点の状態だったことや、テストが通ったことまでは保証されません。

## 実行時エラー

開発中のアプリで起きたエラーは、MCP エンドポイントを有効にして取得します。

```bash
GUREN_MCP=1 bun run dev
```

別のターミナルから、起動時に表示されたアドレスを指定します。

```bash
bunx guren runtime:errors --json --url http://127.0.0.1:3333
bunx guren runtime:errors --json --url http://127.0.0.1:3333 --limit 100
```

ポート番号は、実際に起動したものに置き換えてください。接続先には HTTP のループバックアドレスを明示します。認証情報付きの URL とリダイレクトは拒否し、5 秒でタイムアウトします。呼び出し元のアドレスと `Origin` ヘッダーをループバックに限る制限は、MCP エンドポイントと共通です。接続元のアドレスを報告しないランタイム向けの `GUREN_ALLOW_UNVERIFIED_PEER` も、そのまま使えます。

続きを取得するときは、`nextCursor.sessionId` を `--session` に、`nextCursor.after` を `--after` に渡してください。

### 保持される内容

エラーはアプリごとに最大 100 件を 15 分間保持し、1 件 8 KiB、合計 256 KiB までに制限します。記録するのは、例外の HTTP ステータス、メソッド、識別できた登録ルート、実在するプロジェクト内ファイルのスタック位置です。例外メッセージ、リクエストの値、ヘッダー、Cookie、スタックの全文は記録しません。独自のエラー描画処理が返すステータスは、例外のステータスと異なる場合があります。

`status: "unavailable"` は収集結果を読み取れなかったことを示し、エラーが 0 件の場合とは区別されます。破棄した件数は `dropped` に入り、保存期間外や別セッションのカーソルを渡すと `cursorExpired` が返ります。アプリを停止すると記録は消え、セッション ID も変わります。Guren の例外処理を通らない独自ハンドラー、報告対象外の例外クラス、ブラウザのエラー、ログ、バックグラウンドジョブ、失敗したテストは収集の対象外です。

## コーディングエージェントから読む

エージェントからは、`/_guren/mcp` の `guren_get_application_graph` と `guren_get_runtime_errors` を使います。後者が返すエラーは、`/_guren/runtime/errors` や CLI と同じです。MCP には `sessionId`、`after`、`limit` を直接渡します。取得件数は通常 20 件、最大 100 件です。

同じエンドポイントの `guren_get_plans` は、`/_guren/docs` のドキュメントビューアーに並ぶ[実装計画](./implementation-plans.md)を返します。対象は現在のハッシュで閉じていない計画で、まだ承認していない下書きも含みます。計画ごとに、承認の状態、各ステップで最後の `plan:verify` が記録した結果（値の意味は[計画の状態](./glossary.md#計画の状態)を参照）、免除、次に実行するコマンドが入ります。`active` には各計画で `plan:next` が印を付けたステップが入り、Stop hook が諦めたステップには `stall` が付きます。`unreadable` には一覧できなかった計画ディレクトリが、アプリからの相対パス（アプリ直下は `.`）とエラー付きで入ります。ドキュメントビューアーが計画の一覧の上に出すものと同じです。読むのは計画ファイルと `.guren/plans/` だけなので、検証は実行せず、アプリも読み込みません。計画した要素ごとの状態は `plan:status` で確認してください。

## Dev Center

MCP エンドポイントを有効にして開発サーバーを起動し、`http://localhost:3333/_guren` を開きます。ポートはアプリの設定に合わせてください。

```bash
GUREN_MCP=1 GUREN_DOCS=1 bun run dev
```

Dev Center には、`guren graph` と同じアプリケーショングラフと、`guren runtime:errors` と同じ保持中のエラーが表示されます。ルートを選ぶと関連するシンボルと根拠が表示され、種類、名前、ファイル、モジュールで絞り込めます。関係を確定できない場合も、取得範囲と未解決の関係は表示されたままです。読み取り中に変更されたスナップショットは、再取得が必要です。

画面を開くと一度読み取ります。**Refresh graph**（グラフ更新）を押すと、[グラフの集め方](#グラフの集め方)で説明した条件でアプリのモジュールを読み込み直します。**Refresh errors**（エラー更新）を押すと、保持中のエラー一覧が置き換わります。どちらのボタンも検証コマンドは実行しません。取得に失敗すると前回の結果が消え、取得できなかったことが表示されます。エラー一覧が空でも、保持中の例外がないことを示すだけで、アプリ全体が正常だとは限りません。

**Docs & plans**（ドキュメントと計画）からは、計画表示を含む `/_guren/docs` のドキュメントビューアーを開けます。この画面には `GUREN_DOCS=1` が必要です。Dev Center 自体は `GUREN_MCP=1` で有効になり、MCP エンドポイントと同じループバックの制限がかかります。本番環境では無効です。画面の配信機能がない古い CLI では MCP ツールだけが有効になるので、`/_guren` が 404 を返す場合は Guren を更新してください。
