# 通知設計書 22-ドキュメント置換警告

## 概要

本ドキュメントは、Juliaのドキュメントシステムにおいて、既存のドキュメント文字列が置換される際に出力される警告通知の設計を記述する。

### 本通知の処理概要

本通知は、`@doc` マクロを使用してオブジェクトのドキュメント文字列（docstring）を設定する際に、同じバインディングと型シグネチャの組み合わせに対して既にドキュメントが存在する場合に警告を出力するものである。

**業務上の目的・背景**：Juliaの `@doc` マクロは、関数やメソッド、型などにドキュメントを付与する。同一のシグネチャに対してドキュメントが重複して定義された場合、意図しない上書きの可能性がある。この警告は、開発者がドキュメントの上書きを意図しているか確認する機会を提供する。ただし、インタラクティブ利用（Main モジュールまたは現在のアクティブモジュール）での上書きは一般的な操作であるため、警告は抑止される。

**通知の送信タイミング**：`doc!` 関数が呼ばれた際に、同じバインディング（`b`）と型シグネチャ（`sig`）の組み合わせに対するドキュメントが既に `MultiDoc` に登録されている場合に発生する。

**通知の受信者**：パッケージ開発者やモジュール作成者。コンソール（stderr）に表示される。

**通知内容の概要**：どのバインディングとシグネチャのドキュメントが置換されるか、およびそのモジュール名を表示する。

**期待されるアクション**：開発者は、ドキュメントの置換が意図的なものか確認する。意図しない重複がある場合は、ドキュメント定義を修正する。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ドキュメント定義時に即時出力） |
| 優先度 | 中（ログレベル Warn） |
| リトライ | 無し（ログ出力であるため） |

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

Julia の標準ロギングフレームワークに従い、`stderr` に出力される。`CoreLogging.ConsoleLogger` がデフォルトのグローバルロガーとして設定されている場合、警告メッセージはターミナルに表示される。

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

```
┌ Warning: Replacing docs for `{binding} :: {sig}` in module `{module}`
└ @ Docs base/docs/Docs.jl:253
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| binding (`b`) | ドキュメント対象のバインディング名 | `doc!` 関数の引数 `b` | Yes |
| sig | ドキュメント対象のメソッドシグネチャ（型） | `doc!` 関数の引数 `sig` | Yes |
| module (`__module__`) | ドキュメントが定義されるモジュール名 | `doc!` 関数のスコープ内変数 `__module__` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ドキュメント定義 | `doc!` 関数呼び出し | `haskey(m.docs, sig) && __module__ !== Base.active_module()` | 同一シグネチャのドキュメントが既に存在し、かつアクティブモジュールでない場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `__module__ === Base.active_module()` | インタラクティブ環境（MainモジュールまたはREPLの現在のモジュール）ではドキュメントの置換は頻繁に行われるため抑止される（#23011） |
| 初回定義 | `haskey(m.docs, sig)` が `false` の場合、新規追加であり警告は発生しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A["@doc マクロ展開"] --> B["doc! 関数呼び出し"]
    B --> C["バインディング解決"]
    C --> D["meta(__module__)からMultiDoc取得"]
    D --> E{"haskey(m.docs, sig)?"}
    E -->|No| F["新規docstring登録"]
    E -->|Yes| G{"__module__ === active_module()?"}
    G -->|Yes| H["警告なしで上書き"]
    G -->|No| I["@warn 出力"]
    I --> J["docstring上書き"]
    F --> K["終了"]
    H --> J
    J --> K
```

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

### 参照テーブル一覧

| データ構造 | 参照先 | 参照目的 |
|----------|--------|---------|
| `MultiDoc.docs` | `Dict{Type, Any}` | 同一シグネチャのドキュメントが既に存在するか確認 |
| `META` (per module) | `IdDict{Any,Any}` | モジュール単位のドキュメントメタデータ |

### 更新テーブル一覧

| データ構造 | 更新内容 | 更新条件 |
|----------|---------|---------|
| `MultiDoc.docs[sig]` | 新しいドキュメント文字列で上書き | 常に（警告の有無に関わらず） |
| `MultiDoc.order` | シグネチャ追加 | 新規追加時のみ（上書き時は順序維持） |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ログ出力失敗 | stderr が閉じている場合 | Juliaランタイムのデフォルトエラー処理に委ねる |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（`@warn` のデフォルト maxlog は使用していない） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（ドキュメント定義時に即時出力）

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

モジュール名とバインディング名がログに含まれるが、これらは通常パブリックなAPI情報であり、機密性はない。

## 備考

- ドキュメントの順序は初回追加時に決まり、置換しても順序は変わらない（`push!(m.order, sig)` は新規時のみ）
- この警告はパッケージのプリコンパイル時にも発生する可能性がある
- Issue #23011 に基づき、インタラクティブ使用時の抑止ロジックが追加された

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Docs.jl | `base/docs/Docs.jl` | 77-79行目: `modules`, `META`, `METAType` の定義。モジュール単位でドキュメントメタデータを管理する仕組み |
| 1-2 | Docs.jl | `base/docs/Docs.jl` | 81-99行目: `meta` 関数と `initmeta` 関数。モジュールのメタデータ初期化 |
| 1-3 | Docs.jl | `base/docs/Docs.jl` | `MultiDoc` 構造体（`docs` フィールドと `order` フィールド）。複数シグネチャのドキュメントを管理 |

**読解のコツ**: `META` はモジュール毎に `IdDict` として格納され、キーは `Binding`、値は `MultiDoc`。`MultiDoc` は型シグネチャごとのドキュメントを `Dict{Type, DocStr}` で保持する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Docs.jl | `base/docs/Docs.jl` | `@doc` マクロ定義部分。ドキュメント付与の起点 |
| 2-2 | Docs.jl | `base/docs/Docs.jl` | `doc!` 関数の呼び出し箇所 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Docs.jl | `base/docs/Docs.jl` | 237-263行目: `doc!` 関数。警告の発生箇所 |

**主要処理フロー**:
- **240行目**: バインディング `b` からオブジェクトを解決
- **245行目**: `initmeta(__module__)` でモジュールのメタデータを初期化
- **246行目**: `get!` で `MultiDoc` を取得（なければ新規作成）
- **247行目**: `haskey(m.docs, sig)` で既存ドキュメントの有無を確認
- **252-253行目**: アクティブモジュールでなければ `@warn` 出力
- **259行目**: `m.docs[sig] = str` でドキュメントを登録/上書き

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

```
@doc マクロ
    │
    └─ doc!() [Docs.jl:237]
           │
           ├─ resolve(b) [Docs.jl:240]
           │
           ├─ initmeta(__module__) [Docs.jl:91]
           │
           ├─ get!(meta(__module__), b, MultiDoc()) [Docs.jl:246]
           │      └─ meta() [Docs.jl:81]
           │
           ├─ haskey(m.docs, sig) [Docs.jl:247]
           │
           ├─ @warn "Replacing docs..." [Docs.jl:253]  (条件付き)
           │
           └─ m.docs[sig] = str [Docs.jl:259]
```

### データフロー図

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

@doc マクロ引数          ┌─ バインディング解決
  docstring ──────────▶ │
  対象オブジェクト ─────▶ ├─ MultiDoc取得/作成
                        │
META[module][binding] ─▶ ├─ 既存ドキュメント存在チェック ──▶ @warn メッセージ ──▶ stderr
                        │
__module__ ────────────▶ ├─ active_module() 比較
                        │
                        └─ ドキュメント登録/上書き ────────▶ META 更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Docs.jl | `base/docs/Docs.jl` | ソース | 通知の発生元。ドキュメントシステム全体の実装 |
| bindings.jl | `base/docs/bindings.jl` | ソース | `Binding` 型と `resolve` 関数の定義 |
| logging.jl | `base/logging/logging.jl` | ソース | `@warn` マクロの実装 |
