# 通知設計書 30-表示エラー通知

## 概要

本ドキュメントは、JuliaのフォールバックREPLおよびエラー表示処理において、値の表示やエラーの表示自体がエラーを起こした場合に出力されるエラー通知の設計を記述する。

### 本通知の処理概要

本通知は、`base/client.jl` のREPL評価ループ内で、値の `display` 呼び出しやエラー表示処理がさらなる例外をスローした場合に出力される一連のエラーログである。具体的には以下の3つのパターンがある。

1. **値の表示エラー** (`@error`): 式の評価は成功したが、`display(value)` が例外をスロー
2. **エラー表示エラー** (`@error`): `display_error(errio, lasterr)` が例外をスロー
3. **致命的表示エラー** (`@error`): エラー表示が2回以上連続で失敗し、回復不能と判断

**業務上の目的・背景**：REPLの評価ループでは、式の評価結果を表示する必要がある。しかし、カスタムの `show` メソッドや `display` メソッドがバグを含む場合、値の表示自体がエラーを起こす可能性がある。同様に、エラーの表示処理もエラーを起こす可能性がある。このような二重・三重のエラーを適切にハンドリングし、REPLがクラッシュしないようにすることが本通知の目的である。

**通知の送信タイミング**：フォールバックREPL (`run_fallback_repl_code`) の評価ループ内で発生する。

**通知の受信者**：Julia REPL ユーザー。

**通知内容の概要**：
- パターン1: 「Evaluation succeeded, but an error occurred while displaying the value」とともに値の型情報
- パターン2: 「SYSTEM: display_error(errio, lasterr) caused an error」
- パターン3: 「It is likely that something important is broken, and Julia will not be able to continue normally」とともにエラーカウント

**期待されるアクション**：
- パターン1: カスタム `show`/`display` メソッドの修正
- パターン2,3: Julia環境の修復、再起動

## 通知種別

ログ（Error） -- Julia標準ロギングフレームワーク（`@error` マクロ）によるコンソール出力

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（REPL評価ループ内で即時出力） |
| 優先度 | 高（ログレベル Error） |
| リトライ | パターン2: エラー表示を再試行（最大2回まで） |

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

Julia の標準ロギングフレームワークに従い、`stderr` に出力される。

## 通知テンプレート

### メール通知の場合

該当なし（コンソールログ出力）

### 本文テンプレート

**パターン1: 値の表示エラー**
```
┌ Error: Evaluation succeeded, but an error occurred while displaying the value
│   typeof(value) = SomeType
└ @ Base client.jl:153
```

**パターン2: エラー表示エラー**
```
┌ Error: SYSTEM: display_error(errio, lasterr) caused an error
└ @ Base client.jl:161
```

**パターン3: 致命的表示エラー**
```
┌ Error: It is likely that something important is broken, and Julia will not be able to continue normally
│   errcount = 3
└ @ Base client.jl:167
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| typeof(value) | 表示に失敗した値の型 | `typeof(value)` | Yes（パターン1のみ） |
| errcount | 連続エラー回数 | 評価ループ内のカウンタ | Yes（パターン3のみ） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 値表示 | `invokelatest(display, value)` | `display` が例外をスロー | パターン1 |
| エラー表示 | `display_error(errio, lasterr)` | `display_error` が例外をスロー かつ `errcount > 0` | パターン2 |
| 致命的エラー | 連続エラー | `errcount > 2` | パターン3 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `value === nothing` | `nothing` は表示しないため、パターン1は発生しない |
| `!show_value` | 値の表示が不要な場合（パターン1は発生しない） |
| `errcount == 0` | 初回のエラー表示失敗時はパターン2のメッセージは出力されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A["REPL評価ループ"] --> B["式のパース・評価"]
    B --> C{"評価成功?"}
    C -->|Yes| D{"value !== nothing && show_value?"}
    D -->|Yes| E["try: invokelatest(display, value)"]
    D -->|No| F["ループ継続"]
    E --> G{"例外?"}
    G -->|No| F
    G -->|Yes| H["@error パターン1 + rethrow"]
    H --> I["catch ブロック（外側）"]
    C -->|No| I
    I --> J{"errcount > 0?"}
    J -->|Yes| K["@error パターン2"]
    J -->|No| L["errcount++"]
    K --> L
    L --> M{"errcount > 2?"}
    M -->|Yes| N["@error パターン3 + break"]
    M -->|No| O["エラー表示試行"]
    O --> A
```

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

### 参照テーブル一覧

該当なし

### 更新テーブル一覧

| データ構造 | 更新内容 | 更新条件 |
|----------|---------|---------|
| `Base.MainInclude.ans` | 評価結果の値 | 評価成功時 |
| `Base.MainInclude.err` | エラー情報 | エラー発生時 |
| `errcount` (ローカル) | エラー回数カウンタ | 外側 catch に到達するたびにインクリメント。成功時にリセット |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 値表示エラー | `display(value)` が例外をスロー | `@error` 出力後 `rethrow()` で外側 catch に遷移 |
| エラー表示エラー | `display_error` が例外をスロー | `@error` 出力、エラーカウントをインクリメントしてリトライ |
| 致命的エラー | `errcount > 2` | `@error` 出力後 `break` でループ脱出 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 最大2回（`errcount > 2` で打ち切り） |
| リトライ方式 | 外側ループの次のイテレーションでエラー表示を再試行 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（ただし errcount > 2 でループが終了するため、パターン3は1回のみ） |

### 配信時間帯

制限なし

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

パターン1では `typeof(value)` が出力される。値の型情報は一般的に機密ではないが、カスタム型名にドメイン情報が含まれる可能性がある。値自体の内容は出力されない。

## 備考

- このコードはフォールバックREPL（`run_fallback_repl_code`）内にあり、標準REPL（`REPL` stdlib）では異なるエラー処理が行われる
- パターン1では `rethrow()` により、表示エラーが外側の `catch` ブロックに伝播される。これにより、エラーとして処理される
- `errcount` は成功時（`break` 前）に `0` にリセットされる
- `lasterr = scrub_repl_backtrace(current_exceptions())` でバックトレースが整形される
- `Base.MainInclude.err` でエラー情報が保存され、次の式で `err` 変数として参照可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | client.jl | `base/client.jl` | `MainInclude` モジュール。`ans` と `err` 変数がREPL結果を保持 |
| 1-2 | client.jl | `base/client.jl` | `errcount` ローカル変数。連続エラーのカウンタ |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | client.jl | `base/client.jl` | `run_fallback_repl_code` 関数。フォールバックREPLの評価ループ |
| 2-2 | client.jl | `base/client.jl` | `run_fallback_repl` 関数からの呼び出し |

#### Step 3: 通知発生箇所を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | client.jl | `base/client.jl` | 150-155行目: `display(value)` の try-catch とパターン1 |
| 3-2 | client.jl | `base/client.jl` | 159-162行目: 外側 catch のパターン2 |
| 3-3 | client.jl | `base/client.jl` | 166-168行目: パターン3の致命的エラー判定 |

**主要処理フロー**:
- **137行目**: `while true` ループ開始
- **138行目**: `errcount == 0` なら入力読み取り
- **143-144行目**: 式のパースと評価
- **145行目**: `ans = value` を設定
- **146行目**: `value !== nothing && show_value` のチェック
- **150-155行目**: `try: invokelatest(display, value)` / `catch: @error パターン1 + rethrow()`
- **159行目**: 外側 `catch`
- **160-161行目**: `errcount > 0` なら `@error` パターン2
- **163行目**: `errcount += 1`
- **164行目**: `lasterr = scrub_repl_backtrace(current_exceptions())`
- **166-167行目**: `errcount > 2` なら `@error` パターン3 + `break`

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

```
run_fallback_repl() [client.jl:442]
    │
    └─ run_fallback_repl_code() [client.jl:~130]
           │
           ├─ while true ループ
           │      │
           │      ├─ __repl_entry_client_lower + __repl_entry_client_eval
           │      │
           │      ├─ try: invokelatest(display, value)
           │      │      └─ @error "Evaluation succeeded, but..." [client.jl:153] (パターン1)
           │      │
           │      └─ catch (外側)
           │             ├─ @error "SYSTEM: display_error..." [client.jl:161] (パターン2)
           │             └─ @error "It is likely that..." [client.jl:167] (パターン3)
           │
           └─ println() [client.jl:172]
```

### データフロー図

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

ユーザー入力 ─────────────────▶ パース・評価
                               │
                               ├─ 評価成功 ──▶ display(value)
                               │                  │
                               │                  ├─ 正常 ──▶ 値表示 ──▶ stdout
                               │                  │
                               │                  └─ 例外 ──▶ @error パターン1 ──▶ stderr
                               │
                               └─ 評価失敗 ──▶ display_error(lasterr)
                                                  │
                                                  ├─ 正常 ──▶ エラー表示 ──▶ stderr
                                                  │
                                                  └─ 例外 ──▶ @error パターン2 ──▶ stderr
                                                                 │
                                                                 └─ errcount>2 ──▶ @error パターン3 ──▶ stderr + break
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| client.jl | `base/client.jl` | ソース | 通知の発生元。REPL評価ループとエラー処理 |
| show.jl | `base/show.jl` | ソース | `display` 関数の実装 |
| errorshow.jl | `base/errorshow.jl` | ソース | `display_error`, `showerror` の実装 |
| logging.jl | `base/logging/logging.jl` | ソース | `@error` マクロの実装 |
