# 通知設計書 42-ヒープスナップショット再構成バグ警告

## 概要

本ドキュメントは、Julia の Profile.HeapSnapshot モジュールにおけるヒープスナップショット再構成時のバグ検出警告（`@warn "Bug in to_pos"`）の通知設計について記載する。

### 本通知の処理概要

ヒープスナップショットのストリーミングファイルを最終的な `.heapsnapshot` 形式にアセンブルする際、エッジデータの `to_pos` フィールドが不正な値（ノードフィールド数7の倍数でない）であることを検出した場合に警告を発行する通知である。

**業務上の目的・背景**：ヒープスナップショットは Chrome DevTools のヒープビューアで分析するためのフォーマットに準拠する必要がある。ノードデータは7フィールド（type, name, id, self_size, edge_count, trace_node_id, detachedness）で構成され、エッジの `to_pos` はノード配列内のオフセット（7の倍数）でなければならない。この制約に違反するデータが検出された場合、スナップショットの品質に問題がある可能性を示すため、本警告を発行する。これはランタイムのGCスナップショット取得処理のバグを示唆する内部デバッグ向け通知である。

**通知の送信タイミング**：`HeapSnapshot.assemble_snapshot()` がエッジデータを出力する際、各エッジの `to_pos` 値が `k_node_number_of_fields`（7）の倍数でないことを検出した時点で送信される。

**通知の受信者**：Julia ランタイム開発者、またはヒープスナップショット機能を利用してデバッグを行う上級ユーザー。

**通知内容の概要**：不正な `to_pos` 値を持つエッジのインデックス、所属ノード番号、および実際の `to_pos` 値を通知する。

**期待されるアクション**：Julia ランタイムの GC スナップショット取得処理にバグがある可能性があるため、Julia のイシュートラッカーに報告する。生成されたスナップショットファイルは Chrome DevTools で正しく読み込めない可能性がある。

## 通知種別

ログ出力（`@warn` マクロによる標準エラー出力へのWarnレベルログ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（`@warn` マクロによる即時ログ出力） |
| 優先度 | 中（Warn レベル） |
| リトライ | なし（ログ出力のため） |

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

Julia のログシステムに委譲される。デフォルトでは `stderr` に出力される。

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

```
┌ Warning: Bug in to_pos for edge $i from node $n: $(nodes.edges.to_pos[i])
└ @ Profile.HeapSnapshot stdlib/Profile/src/heapsnapshot_reassemble.jl:174
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| `i` | エッジのインデックス | ループ変数（`nodes.edge_idxs[n]` のイテレーション） | Yes |
| `n` | ノード番号 | ループ変数（1〜ノード数） | Yes |
| `nodes.edges.to_pos[i]` | エッジの to_pos 値（不正値） | `Nodes.edges.to_pos` 配列 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | `HeapSnapshot.assemble_snapshot()` | `nodes.edges.to_pos[i] % k_node_number_of_fields != 0` | to_pos が7の倍数でない場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 正常なデータ | `to_pos` が7の倍数である場合は警告なし |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A["assemble_snapshot() 呼び出し"] --> B["中間ファイル読込"]
    B --> C["ノードデータ解析"]
    C --> D["エッジデータ解析・to_pos計算"]
    D --> E["エッジ出力ループ"]
    E --> F{"to_pos % 7 == 0?"}
    F -->|Yes| G["正常出力"]
    F -->|No| H["@warn 警告出力"]
    H --> G
    G --> I["次のエッジへ"]
```

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

### 参照テーブル一覧

該当なし（ファイルI/Oのみ）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| to_posデータ不整合 | GCスナップショット取得処理のバグ | 警告を出力し処理を続行。ファイルは生成されるが品質は保証されない |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 上限 | 不正エッジごとに1回出力（レート制限なし） |

### 配信時間帯

制限なし

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

- ログメッセージには内部のノード・エッジインデックスのみ含まれ、機密情報は含まれない

## 備考

- この警告はJuliaランタイムのバグを示唆するものであり、通常の使用では発生しない
- `k_node_number_of_fields` は定数 `7` として定義されている（`heapsnapshot_reassemble.jl:54`）
- ストリーミングフォーマットではC側で `to_node` をノードインデックスとして書き出し、Julia側で `k_node_number_of_fields` を乗算して `to_pos` に変換する（`heapsnapshot_reassemble.jl:131`）

---

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

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

### 推奨読解順序

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

ヒープスナップショットの内部データ構造（`Nodes` と `Edges`）を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | heapsnapshot_reassemble.jl | `stdlib/Profile/src/heapsnapshot_reassemble.jl` | `Edges` 構造体（12-23行目）と `Nodes` 構造体（27-51行目） |
| 1-2 | heapsnapshot_reassemble.jl | `stdlib/Profile/src/heapsnapshot_reassemble.jl` | `k_node_number_of_fields` 定数（54行目） |

**読解のコツ**: SoA（Structure of Arrays）レイアウトでパディングを削減している。`to_pos` フィールドはノード配列内のオフセットで、7フィールド/ノードの倍数でなければならない。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | heapsnapshot_reassemble.jl | `stdlib/Profile/src/heapsnapshot_reassemble.jl` | `assemble_snapshot(in_prefix, io::IO)` 関数（88-213行目） |

**主要処理フロー**:
1. **89-96行目**: メタデータJSONからノード数・エッジ数を解析
2. **102-119行目**: ノードファイルからノードデータを読込
3. **122-139行目**: エッジファイルからエッジデータを読込、`to_pos` を計算（131行目: `to_node * k_node_number_of_fields`）
4. **160-178行目**: エッジデータの出力ループ、173-174行目で `to_pos` の整合性チェック

#### Step 3: 警告発行箇所を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | heapsnapshot_reassemble.jl | `stdlib/Profile/src/heapsnapshot_reassemble.jl` | 173-174行目の条件チェックと `@warn` 呼び出し |

**主要処理フロー**:
- **173行目**: `nodes.edges.to_pos[i] % k_node_number_of_fields == 0` の確認
- **174行目**: 条件不成立時に `@warn "Bug in to_pos for edge $i from node $n: $(nodes.edges.to_pos[i])"` を発行

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

```
take_heap_snapshot(filepath; streaming=false)    [Profile.jl:1407]
    │
    ├─ _stream_heap_snapshot(prefix, ...)        [Profile.jl:1428]
    │      └─ jl_gc_take_heap_snapshot (ccall)
    │             └─ .nodes, .edges, .strings, .metadata.json 出力
    │
    └─ HeapSnapshot.assemble_snapshot(prefix, filepath)  [heapsnapshot_reassemble.jl:80]
           │
           ├─ ノードデータ読込                     [102-119行目]
           ├─ エッジデータ読込・to_pos計算          [122-139行目]
           └─ エッジ出力ループ                     [160-178行目]
                  └─ to_pos % 7 != 0 → @warn      [173-174行目: 本通知]
```

### データフロー図

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

.edges バイナリ ─────────▶ エッジ読込
    (from_node,to_node)        │
                               ▼
                    to_node * 7 → to_pos
                               │
                               ▼
                    to_pos % 7 == 0 チェック ──(NG)──▶ @warn ログ出力
                               │                     (stderr)
                               ▼
                    JSON出力 ──────────────────────▶ .heapsnapshot
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| heapsnapshot_reassemble.jl | `stdlib/Profile/src/heapsnapshot_reassemble.jl` | ソース | 通知発行元、スナップショットアセンブル処理 |
| Profile.jl | `stdlib/Profile/src/Profile.jl` | ソース | ヒープスナップショット取得の上位API |
