# 通知設計書 8-モジュール置換警告

## 概要

本ドキュメントは、Juliaランタイムにおけるモジュール置換警告通知の設計を記述する。既にロード済みのモジュールが異なるモジュールオブジェクトで置き換えられる場合に警告ログを出力する。

### 本通知の処理概要

**業務上の目的・背景**：Juliaのモジュールロードシステムでは、`loaded_modules`辞書でロード済みモジュールを管理する。同一の`PkgId`キーで異なるモジュールオブジェクトが登録されようとした場合、既存のモジュールが置換される。これは通常の使用では発生しない状況であり、パッケージの再ロードやモジュール名の衝突を示唆する。本通知はこの潜在的な問題を開発者に警告する。

**通知の送信タイミング**：`register_root_module`関数内で、`loaded_modules`辞書に同一キーで異なるモジュールオブジェクトが既に存在する場合に通知される。インクリメンタルプリコンパイル時はエラーとして扱われる。

**通知の受信者**：Juliaプログラムを実行している開発者。ログメッセージとして標準エラー出力（または設定されたログハンドラ）に出力される。

**通知内容の概要**：「Replacing module `ModuleName`」というメッセージが`@warn`マクロにより出力される。置換されるモジュールの名前が含まれる。

**期待されるアクション**：開発者はモジュール名の衝突がないか確認し、同名パッケージの重複ロードやモジュール再定義の原因を調査する。

## 通知種別

ログ出力（Warnレベル） - Juliaの`@warn`マクロによるロギングシステム経由の警告通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（`register_root_module`関数内で即座に出力） |
| 優先度 | 中（モジュール置換は予期しない動作を引き起こす可能性あり） |
| リトライ | 無し |

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

Juliaのロギングフレームワーク（`CoreLogging`）に委譲される。デフォルトでは`stderr`に出力される。

## 通知テンプレート

### メール通知の場合

該当なし（ログ出力のみ）

### 本文テンプレート

```
┌ Warning: Replacing module `MyModule`
└ @ Base loading.jl:2747
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| key.name | 置換されるモジュールの名前 | `PkgId(m, String(nameof(m)))` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | `register_root_module(m::Module)`の実行 | `haskey(loaded_modules, key) && loaded_modules[key] !== m` | 同一PkgIdで異なるモジュールオブジェクトが既に登録済み |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 同一モジュールオブジェクト | `oldm === m`の場合は置換とみなさず通知しない |
| モジュールが未登録 | `!haskey(loaded_modules, key)`の場合は新規登録なので通知しない |
| インクリメンタルプリコンパイル中 | `generating_output(true)`の場合は警告ではなくエラーを投げる |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[register_root_module呼び出し] --> B["key = PkgId(m, nameof(m))"]
    B --> C{loaded_modulesにkeyが存在?}
    C -->|No| D[新規登録]
    C -->|Yes| E{oldm === m?}
    E -->|Yes| F[同一オブジェクト - 更新のみ]
    E -->|No| G{generating_output incremental?}
    G -->|Yes| H["error Replacing module"]
    G -->|No| I["@warn Replacing module"]
    I --> D
    F --> D
    D --> J["loaded_modules[key] = m"]
```

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

### 参照テーブル一覧

該当なし（インメモリの`loaded_modules`辞書を参照する）

### 更新テーブル一覧

該当なし（`loaded_modules`辞書の更新のみ）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| エラー（インクリメンタル時） | インクリメンタルプリコンパイル中のモジュール置換 | `error("Replacing module")`で処理を停止 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（モジュール置換ごとに出力） |

### 配信時間帯

制限なし

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

本通知にはセキュリティ上の懸念はない。モジュール名のみが出力される。

## 備考

- `register_root_module`は`require_lock`の下で実行される（2739行目）
- Core、Base、Mainの3つのモジュールは起動時に登録される（2757-2759行目）
- `@constprop :none`アノテーションにより定数伝搬が無効化されている（2736行目）
- `loaded_modules_order`にも追加される（2751行目）

---

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

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

### 推奨読解順序

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

モジュール管理に関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | loading.jl | `base/loading.jl` | `loaded_modules`辞書と`PkgId`型の定義 |

**読解のコツ**: `loaded_modules`は`PkgId => Module`のマッピングを保持する辞書である。`PkgId`はパッケージのUUIDと名前から構成される。

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

通知が発生する`register_root_module`関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | loading.jl | `base/loading.jl` | `register_root_module`関数（2736-2755行目） |

**主要処理フロー**:
1. **2739行目**: `@lock require_lock`でロックを取得
2. **2740行目**: `PkgId(m, String(nameof(m)))`でキーを構築
3. **2741行目**: `haskey(loaded_modules, key)`で既存チェック
4. **2743行目**: `oldm !== m`で異なるオブジェクトか判定
5. **2744-2745行目**: インクリメンタル時はエラー
6. **2747行目**: それ以外は`@warn "Replacing module"`
7. **2751行目**: `maybe_loaded_precompile`チェック後、`loaded_modules_order`に追加
8. **2752行目**: `loaded_modules[key] = m`で登録

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

```
C/Julia ランタイム (Base.__toplevel__ から)
    |
    +-- register_root_module(m::Module)  [base/loading.jl:2736]
        |
        +-- @lock require_lock
        +-- PkgId(m, nameof(m))
        +-- haskey(loaded_modules, key)
        +-- (置換時) @warn "Replacing module `name`"  [base/loading.jl:2747]
        +-- loaded_modules[key] = m
```

### データフロー図

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

Module オブジェクト ──> register_root_module           ──> loaded_modules辞書の更新
                        |
                        +-- PkgId生成
                        +-- 既存チェック
                        +-- (置換時) @warn ──> stderr
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| loading.jl | `base/loading.jl` | ソース | モジュール登録・ロード管理の全実装 |
