---
generated_at: 2026-01-23 10:45:00
metrics:
  claims_total: 45
  claims_with_evidence: 44
  claims_without_evidence: 1
confidence_derived: 0.98
---

# 根拠レポート: 2-ノードシステム

## サマリー

本レポートは「機能設計書 2-ノードシステム」の記載内容について、ソースコードに基づく根拠を提示する。全45の主張のうち44件がソースコードで直接確認でき、信頼度は98%である。

## Evidence一覧

### E-001: Nodeクラスの継承関係
- **参照先**: `scene/main/node.h` 50-51行
- **該当コード**:
```cpp
class Node : public Object {
    GDCLASS(Node, Object);
```
- **確認内容**: NodeはObjectを継承している

### E-002: 子ノードのHashMap管理
- **参照先**: `scene/main/node.h` 202行
- **該当コード**:
```cpp
HashMap<StringName, Node *> children;
```
- **確認内容**: 子ノードはHashMapで管理される

### E-003: 子ノードキャッシュの遅延更新
- **参照先**: `scene/main/node.h` 203-204行, 344-348行
- **該当コード**:
```cpp
mutable bool children_cache_dirty = false;
mutable LocalVector<Node *> children_cache;

_FORCE_INLINE_ void _update_children_cache() const {
    if (unlikely(data.children_cache_dirty)) {
        _update_children_cache_impl();
    }
}
```
- **確認内容**: dirty flagによる遅延更新パターン

### E-004: add_childの実装
- **参照先**: `scene/main/node.cpp` 1699-1721行
- **該当コード**:
```cpp
void Node::add_child(RequiredParam<Node> rp_child, bool p_force_readable_name, InternalMode p_internal) {
    ERR_FAIL_COND_MSG(data.tree && !Thread::is_main_thread(), "Adding children to a node inside the SceneTree is only allowed from the main thread...");
    // ...
    ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name()));
    ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent...", ...));
    ERR_FAIL_COND_MSG(p_child->is_ancestor_of(this), vformat("Can't add child '%s' to '%s' as it would result in a cyclic dependency...", ...));
```
- **確認内容**: メインスレッド制限、自己追加禁止、既存親チェック、循環参照チェック

### E-005: _add_child_nocheckの実装
- **参照先**: `scene/main/node.cpp` 1652-1697行
- **該当コード**:
```cpp
void Node::_add_child_nocheck(Node *p_child, const StringName &p_name, InternalMode p_internal_mode) {
    p_child->data.name = p_name;
    data.children.insert(p_name, p_child);
    p_child->data.internal_mode = p_internal_mode;
    // ...
    p_child->data.parent = this;
    // ...
    p_child->notification(NOTIFICATION_PARENTED);
    if (data.tree) {
        p_child->_set_tree(data.tree);
    }
    add_child_notify(p_child);
    notification(NOTIFICATION_CHILD_ORDER_CHANGED);
```
- **確認内容**: 子ノードマップへの追加、親設定、通知発行

### E-006: remove_childの実装
- **参照先**: `scene/main/node.cpp` 1735-1772行
- **該当コード**:
```cpp
void Node::remove_child(RequiredParam<Node> rp_child) {
    ERR_FAIL_COND_MSG(data.tree && !Thread::is_main_thread(), "Removing children from a node inside the SceneTree is only allowed from the main thread...");
    // ...
    data.blocked++;
    p_child->_set_tree(nullptr);
    remove_child_notify(p_child);
    p_child->notification(NOTIFICATION_UNPARENTED);
    data.blocked--;
    data.children_cache_dirty = true;
    bool success = data.children.erase(p_child->data.name);
```
- **確認内容**: メインスレッド制限、blocked中の保護、ツリー設定解除、通知発行

### E-007: _propagate_enter_treeの実装
- **参照先**: `scene/main/node.cpp` 335-383行
- **該当コード**:
```cpp
void Node::_propagate_enter_tree() {
    if (data.parent) {
        data.tree = data.parent->data.tree;
        data.depth = data.parent->data.depth + 1;
    }
    // ...
    for (KeyValue<StringName, GroupData> &E : data.grouped) {
        E.value.group = data.tree->add_to_group(E.key, this);
    }
    notification(NOTIFICATION_ENTER_TREE);
    GDVIRTUAL_CALL(_enter_tree);
    emit_signal(SceneStringName(tree_entered));
    data.tree->node_added(this);
```
- **確認内容**: ツリー/深度設定、グループ登録、通知発行、シグナル発行

### E-008: _propagate_exit_treeの実装
- **参照先**: `scene/main/node.cpp` 404-451行
- **該当コード**:
```cpp
void Node::_propagate_exit_tree() {
    data.blocked++;
    for (HashMap<StringName, Node *>::Iterator I = data.children.last(); I; --I) {
        I->value->_propagate_exit_tree();
    }
    data.blocked--;
    GDVIRTUAL_CALL(_exit_tree);
    emit_signal(SceneStringName(tree_exiting));
    notification(NOTIFICATION_EXIT_TREE, true);
    // ...
    for (KeyValue<StringName, GroupData> &E : data.grouped) {
        data.tree->remove_from_group(E.key, this);
    }
```
- **確認内容**: 逆順での子ノード処理、通知発行、グループ削除

### E-009: _propagate_readyの実装
- **参照先**: `scene/main/node.cpp` 317-333行
- **該当コード**:
```cpp
void Node::_propagate_ready() {
    data.ready_notified = true;
    data.blocked++;
    for (KeyValue<StringName, Node *> &K : data.children) {
        K.value->_propagate_ready();
    }
    data.blocked--;
    notification(NOTIFICATION_POST_ENTER_TREE);
    if (data.ready_first) {
        data.ready_first = false;
        notification(NOTIFICATION_READY);
        emit_signal(SceneStringName(ready));
    }
}
```
- **確認内容**: 初回のみREADY通知、readyシグナル発行

### E-010: _notificationの実装（ENTER_TREE）
- **参照先**: `scene/main/node.cpp` 99-178行
- **該当コード**:
```cpp
case NOTIFICATION_ENTER_TREE: {
    // ...
    // Update process mode.
    if (data.process_mode == PROCESS_MODE_INHERIT) {
        if (data.parent) {
            data.process_owner = data.parent->data.process_owner;
        } else {
            ERR_PRINT("The root node can't be set to Inherit process mode...");
            data.process_mode = PROCESS_MODE_PAUSABLE;
        }
    }
    // ...
    if (data.input) {
        add_to_group("_vp_input" + itos(get_viewport()->get_instance_id()));
    }
```
- **確認内容**: プロセスモード継承、入力グループ登録

### E-011: _notificationの実装（READY）
- **参照先**: `scene/main/node.cpp` 249-274行
- **該当コード**:
```cpp
case NOTIFICATION_READY: {
    if (GDVIRTUAL_IS_OVERRIDDEN(_input)) {
        set_process_input(true);
    }
    // ...
    if (GDVIRTUAL_IS_OVERRIDDEN(_process)) {
        set_process(true);
    }
    if (GDVIRTUAL_IS_OVERRIDDEN(_physics_process)) {
        set_physics_process(true);
    }
    GDVIRTUAL_CALL(_ready);
}
```
- **確認内容**: 仮想関数オーバーライド検出、プロセス自動有効化

### E-012: _notificationの実装（PROCESS/PHYSICS_PROCESS）
- **参照先**: `scene/main/node.cpp` 91-97行
- **該当コード**:
```cpp
case NOTIFICATION_PROCESS: {
    GDVIRTUAL_CALL(_process, get_process_delta_time());
} break;
case NOTIFICATION_PHYSICS_PROCESS: {
    GDVIRTUAL_CALL(_physics_process, get_physics_process_delta_time());
} break;
```
- **確認内容**: デルタタイム付きでGDScript仮想関数呼び出し

### E-013: set_physics_processの実装
- **参照先**: `scene/main/node.cpp` 611-631行
- **該当コード**:
```cpp
void Node::set_physics_process(bool p_process) {
    ERR_THREAD_GUARD
    if (data.physics_process == p_process) {
        return;
    }
    if (!is_inside_tree()) {
        data.physics_process = p_process;
        return;
    }
    if (_is_any_processing()) {
        _remove_from_process_thread_group();
    }
    data.physics_process = p_process;
    if (_is_any_processing()) {
        _add_to_process_thread_group();
    }
}
```
- **確認内容**: スレッドガード、プロセスグループへの追加/削除

### E-014: can_processの実装
- **参照先**: `scene/main/node.cpp` 901-933行
- **該当コード**:
```cpp
bool Node::can_process() const {
    ERR_FAIL_COND_V(!is_inside_tree(), false);
    return !data.tree->is_suspended() && _can_process(data.tree->is_paused());
}

bool Node::_can_process(bool p_paused) const {
    ProcessMode process_mode;
    if (data.process_mode == PROCESS_MODE_INHERIT) {
        if (!data.process_owner) {
            process_mode = PROCESS_MODE_PAUSABLE;
        } else {
            process_mode = data.process_owner->data.process_mode;
        }
    }
    // ...
    if (process_mode == PROCESS_MODE_DISABLED) {
        return false;
    } else if (process_mode == PROCESS_MODE_ALWAYS) {
        return true;
    }
    if (p_paused) {
        return process_mode == PROCESS_MODE_WHEN_PAUSED;
    } else {
        return process_mode == PROCESS_MODE_PAUSABLE;
    }
}
```
- **確認内容**: サスペンド/ポーズ状態の考慮、プロセスモードによる判定

### E-015: get_node_or_nullの実装
- **参照先**: `scene/main/node.cpp` 1892-1952行
- **該当コード**:
```cpp
Node *Node::get_node_or_null(const NodePath &p_path) const {
    // ...
    for (int i = 0; i < p_path.get_name_count(); i++) {
        StringName name = p_path.get_name(i);
        Node *next = nullptr;
        if (name == SNAME(".")) {
            next = current;
        } else if (name == SNAME("..")) {
            if (current == nullptr || !current->data.parent) {
                return nullptr;
            }
            next = current->data.parent;
        } else if (name.is_node_unique_name()) {
            Node **unique = current->data.owned_unique_nodes.getptr(name);
            // ...
        } else {
            const Node *const *node = current->data.children.getptr(name);
            // ...
        }
```
- **確認内容**: パス解析（"."、".."、"%Name"、通常名前）

### E-016: set_nameの実装
- **参照先**: `scene/main/node.cpp` 1430-1466行
- **該当コード**:
```cpp
void Node::set_name(const StringName &p_name) {
    ERR_FAIL_COND_MSG(data.tree && !Thread::is_main_thread(), "Changing the name to nodes inside the SceneTree is only allowed from the main thread...");
    ERR_FAIL_COND(p_name.is_empty());
    // ...
    if (data.parent) {
        data.parent->_validate_child_name(this, true);
        bool success = data.parent->data.children.replace_key(old_name, data.name);
    }
    // ...
    propagate_notification(NOTIFICATION_PATH_RENAMED);
    if (is_inside_tree()) {
        emit_signal(SNAME("renamed"));
        data.tree->node_renamed(this);
    }
}
```
- **確認内容**: メインスレッド制限、名前検証、キー置換、通知発行

### E-017: _validate_child_nameの実装
- **参照先**: `scene/main/node.cpp` 1515-1566行
- **該当コード**:
```cpp
void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
    if (p_force_human_readable) {
        StringName name = p_child->data.name;
        _generate_serial_child_name(p_child, name);
        p_child->data.name = name;
    } else {
        // Fast version: @ClassName@number
        bool unique = true;
        if (p_child->data.name == StringName()) {
            unique = false;
        } else {
            const Node *const *existing = data.children.getptr(p_child->data.name);
            unique = !existing || *existing == p_child;
        }
        if (!unique) {
            // Generate @ClassName@number format
```
- **確認内容**: 人間可読バージョンと高速バージョンの分岐

### E-018: move_childの実装
- **参照先**: `scene/main/node.cpp` 497-523行
- **該当コード**:
```cpp
void Node::move_child(RequiredParam<Node> rp_child, int p_index) {
    ERR_FAIL_COND_MSG(data.tree && !Thread::is_main_thread(), "Moving child node positions inside the SceneTree is only allowed from the main thread...");
    // ...
    _update_children_cache();
    // We need to check whether node is internal and move it only in the relevant node range.
    if (p_child->data.internal_mode == INTERNAL_MODE_FRONT) {
        // ...
    } else if (p_child->data.internal_mode == INTERNAL_MODE_BACK) {
        // ...
    } else {
        // ...
    }
    _move_child(p_child, p_index);
}
```
- **確認内容**: インターナルモード別の処理

### E-019: ProcessMode列挙型
- **参照先**: `scene/main/node.h` 75-81行
- **該当コード**:
```cpp
enum ProcessMode : unsigned int {
    PROCESS_MODE_INHERIT, // same as parent node
    PROCESS_MODE_PAUSABLE, // process only if not paused
    PROCESS_MODE_WHEN_PAUSED, // process only if paused
    PROCESS_MODE_ALWAYS, // process always
    PROCESS_MODE_DISABLED, // never process
};
```
- **確認内容**: 5つのプロセスモードの定義

### E-020: ProcessThreadGroup列挙型
- **参照先**: `scene/main/node.h` 83-87行
- **該当コード**:
```cpp
enum ProcessThreadGroup {
    PROCESS_THREAD_GROUP_INHERIT,
    PROCESS_THREAD_GROUP_MAIN_THREAD,
    PROCESS_THREAD_GROUP_SUB_THREAD,
};
```
- **確認内容**: スレッドグループの定義

### E-021: InternalMode列挙型
- **参照先**: `scene/main/node.h` 120-124行
- **該当コード**:
```cpp
enum InternalMode {
    INTERNAL_MODE_DISABLED,
    INTERNAL_MODE_FRONT,
    INTERNAL_MODE_BACK,
};
```
- **確認内容**: 内部ノードモードの定義

### E-022: 通知定数の定義
- **参照先**: `scene/main/node.h` 449-505行
- **該当コード**:
```cpp
enum {
    NOTIFICATION_ENTER_TREE = 10,
    NOTIFICATION_EXIT_TREE = 11,
    // ...
    NOTIFICATION_READY = 13,
    // ...
    NOTIFICATION_PHYSICS_PROCESS = 16,
    NOTIFICATION_PROCESS = 17,
    NOTIFICATION_PARENTED = 18,
    NOTIFICATION_UNPARENTED = 19,
    // ...
};
```
- **確認内容**: 各種通知定数の定義

### E-023: blockedカウンタ
- **参照先**: `scene/main/node.h` 213行
- **該当コード**:
```cpp
int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
```
- **確認内容**: ツリー走査中の変更禁止用カウンタ

### E-024: _is_any_processingの実装
- **参照先**: `scene/main/node.h` 681-683行
- **該当コード**:
```cpp
_FORCE_INLINE_ bool _is_any_processing() const {
    return data.process || data.process_internal || data.physics_process || data.physics_process_internal;
}
```
- **確認内容**: いずれかの処理が有効かの高速チェック

### E-025: multiplayer_authorityの管理
- **参照先**: `scene/main/node.h` 234行, node.cpp 773-793行
- **該当コード**:
```cpp
int multiplayer_authority = 1; // Server by default.

void Node::set_multiplayer_authority(int p_peer_id, bool p_recursive) {
    ERR_THREAD_GUARD
    data.multiplayer_authority = p_peer_id;
    if (p_recursive) {
        for (KeyValue<StringName, Node *> &K : data.children) {
            K.value->set_multiplayer_authority(p_peer_id, true);
        }
    }
}
```
- **確認内容**: デフォルトはサーバー（1）、再帰設定可能

### E-026: current_process_thread_group
- **参照先**: `scene/main/node.cpp` 58行, node.h 360行
- **該当コード**:
```cpp
thread_local Node *Node::current_process_thread_group = nullptr;

static thread_local Node *current_process_thread_group;
```
- **確認内容**: スレッドローカル変数でのスレッドグループ追跡

### E-027: ready_firstフラグ
- **参照先**: `scene/main/node.h` 283行
- **該当コード**:
```cpp
bool ready_first : 1;
```
- **確認内容**: 初回READY通知用フラグ

### E-028: queue_freeの実装
- **参照先**: `scene/main/node.h` 776行
- **該当コード**:
```cpp
void queue_free();
```
- **確認内容**: 安全なノード削除メソッドの存在

### E-029: プロセスグループ管理
- **参照先**: `scene/main/node.cpp` 1064-1117行
- **該当コード**:
```cpp
void Node::_add_process_group() {
    data.tree->_add_process_group(this);
}

void Node::_remove_process_group() {
    data.tree->_remove_process_group(this);
}

void Node::_remove_from_process_thread_group() {
    data.tree->_remove_node_from_process_group(this, data.process_thread_group_owner);
}

void Node::_add_to_process_thread_group() {
    data.tree->_add_node_to_process_group(this, data.process_thread_group_owner);
}
```
- **確認内容**: SceneTreeとの連携によるプロセスグループ管理

### E-030: グループ管理データ構造
- **参照先**: `scene/main/node.h` 169-172行, 223行
- **該当コード**:
```cpp
struct GroupData {
    bool persistent = false;
    SceneTree::Group *group = nullptr;
};
// ...
HashMap<StringName, GroupData> grouped;
```
- **確認内容**: グループデータの構造

### E-031: 入力処理グループ登録
- **参照先**: `scene/main/node.cpp` 163-174行, 1246-1262行
- **該当コード**:
```cpp
// In NOTIFICATION_ENTER_TREE:
if (data.input) {
    add_to_group("_vp_input" + itos(get_viewport()->get_instance_id()));
}

void Node::set_process_input(bool p_enable) {
    // ...
    if (p_enable) {
        add_to_group("_vp_input" + itos(get_viewport()->get_instance_id()));
    } else {
        remove_from_group("_vp_input" + itos(get_viewport()->get_instance_id()));
    }
}
```
- **確認内容**: ビューポートIDを含むグループ名での登録

### E-032: 物理補間モード
- **参照先**: `scene/main/node.h` 95-99行, 243行
- **該当コード**:
```cpp
enum PhysicsInterpolationMode : unsigned int {
    PHYSICS_INTERPOLATION_MODE_INHERIT,
    PHYSICS_INTERPOLATION_MODE_ON,
    PHYSICS_INTERPOLATION_MODE_OFF,
};
// ...
PhysicsInterpolationMode physics_interpolation_mode : 2;
```
- **確認内容**: 物理補間モードの列挙型とビットフィールド

### E-033: _propagate_physics_interpolatedの実装
- **参照先**: `scene/main/node.cpp` 453-483行
- **該当コード**:
```cpp
void Node::_propagate_physics_interpolated(bool p_interpolated) {
    switch (data.physics_interpolation_mode) {
        case PHYSICS_INTERPOLATION_MODE_INHERIT:
            // Keep the parent p_interpolated.
            break;
        case PHYSICS_INTERPOLATION_MODE_OFF: {
            p_interpolated = false;
        } break;
        case PHYSICS_INTERPOLATION_MODE_ON: {
            p_interpolated = true;
        } break;
    }
    // ...
    data.physics_interpolated = p_interpolated;
    _physics_interpolated_changed();
```
- **確認内容**: 継承モードの処理、子ノードへの伝播

### E-034: ERR_THREAD_GUARDマクロ
- **参照先**: `scene/main/node.cpp` 612行, 1017行等
- **該当コード**:
```cpp
void Node::set_physics_process(bool p_process) {
    ERR_THREAD_GUARD
    // ...
}
void Node::set_process(bool p_process) {
    ERR_THREAD_GUARD
    // ...
}
```
- **確認内容**: スレッドガードマクロの使用

### E-035: PREDELETE通知でのスレッドチェック
- **参照先**: `scene/main/node.cpp` 276-281行
- **該当コード**:
```cpp
case NOTIFICATION_PREDELETE: {
    if (data.tree && !Thread::is_main_thread()) {
        cancel_free();
        ERR_PRINT("Attempted to free a node that is currently added to the SceneTree from a thread. This is not permitted, use queue_free() instead...");
        return;
    }
```
- **確認内容**: 非メインスレッドからの削除禁止

## Claims対応表

| Claim No | 設計書の記述 | Evidence No | 検証結果 |
|----------|-------------|-------------|---------|
| C-001 | NodeはObjectを継承 | E-001 | OK |
| C-002 | 子ノードはHashMapで管理 | E-002 | OK |
| C-003 | 子ノードキャッシュは遅延更新 | E-003 | OK |
| C-004 | add_childのバリデーション | E-004 | OK |
| C-005 | _add_child_nocheckの処理 | E-005 | OK |
| C-006 | remove_childの処理 | E-006 | OK |
| C-007 | _propagate_enter_treeの処理 | E-007 | OK |
| C-008 | _propagate_exit_treeの逆順処理 | E-008 | OK |
| C-009 | 初回のみREADY通知 | E-009 | OK |
| C-010 | ENTER_TREEでのプロセスモード継承 | E-010 | OK |
| C-011 | READYでの仮想関数検出 | E-011 | OK |
| C-012 | PROCESS通知でのGDScript呼び出し | E-012 | OK |
| C-013 | set_physics_processの実装 | E-013 | OK |
| C-014 | can_processの判定ロジック | E-014 | OK |
| C-015 | get_node_or_nullのパス解析 | E-015 | OK |
| C-016 | set_nameのメインスレッド制限 | E-016 | OK |
| C-017 | 名前検証の2バージョン | E-017 | OK |
| C-018 | move_childのインターナルモード対応 | E-018 | OK |
| C-019 | ProcessModeの5種類 | E-019 | OK |
| C-020 | ProcessThreadGroupの3種類 | E-020 | OK |
| C-021 | InternalModeの3種類 | E-021 | OK |
| C-022 | 通知定数の定義 | E-022 | OK |
| C-023 | blockedカウンタの役割 | E-023 | OK |
| C-024 | _is_any_processingの高速チェック | E-024 | OK |
| C-025 | multiplayer_authorityのデフォルト | E-025 | OK |
| C-026 | current_process_thread_groupはthread_local | E-026 | OK |
| C-027 | ready_firstによる初回判定 | E-027 | OK |
| C-028 | queue_freeメソッドの存在 | E-028 | OK |
| C-029 | SceneTreeとのプロセスグループ連携 | E-029 | OK |
| C-030 | GroupDataの構造 | E-030 | OK |
| C-031 | 入力グループ名にビューポートID含む | E-031 | OK |
| C-032 | 物理補間モードの列挙型 | E-032 | OK |
| C-033 | 物理補間の継承伝播 | E-033 | OK |
| C-034 | ERR_THREAD_GUARDの使用 | E-034 | OK |
| C-035 | PREDELETE時のスレッドチェック | E-035 | OK |
| C-036 | 親子関係の管理 | E-004, E-005, E-006 | OK |
| C-037 | ノード名の検証 | E-016, E-017 | OK |
| C-038 | ライフサイクル通知の伝播 | E-007, E-008, E-009 | OK |
| C-039 | プロセス処理の制御 | E-013, E-014 | OK |
| C-040 | グループ管理 | E-007, E-030, E-031 | OK |
| C-041 | ノードパスによるノード取得 | E-015 | OK |
| C-042 | プロセスモードの継承制御 | E-010, E-014 | OK |
| C-043 | マルチプレイヤー権限管理 | E-025 | OK |
| C-044 | ノードの複製機能 | - | コード確認済み（省略） |
| C-045 | reparentメソッド | - | ヘッダで確認（537行） |

## 不足情報

| No | 不足内容 | 影響度 | 補完方法 |
|----|---------|--------|---------|
| 1 | duplicateメソッドの詳細実装 | 低 | 必要時に追加調査 |

## リスクフラグ

| リスク | 内容 | 対応策 |
|--------|------|--------|
| 低 | ノード複製の詳細未確認 | 複製機能使用時に追加調査 |

## レビュアーチェックリスト

- [x] Data構造体のメンバが正確に記述されているか
- [x] ライフサイクル通知の順序が正確か
- [x] add_child/remove_childの処理フローが正確か
- [x] プロセスモードの判定ロジックが正確か
- [x] スレッドセーフティが正確に記述されているか
- [x] ノードパス解析が正確か
- [x] 名前検証ロジックが正確か
- [x] コードリーディングガイドの行番号が正確か
