# ADR-002: Event Bus & Cross-Layer Communication Pattern **Status**: Accepted **Date**: 2026-04-27 **Engine**: Unity 2022.3.62f3c1 **GDD Requirements Addressed**: All L0→L1 communication from systems-index.md --- ## Context Architecture requires L0 to never call L1 or L2. All upward communication must go through an event mechanism. Need to choose: C# built-in `event` vs. a dedicated EventBus class. This decision affects every L0 module's interface design and memory safety. ## Decision **Use C# built-in `event` + `Action`. No dedicated EventBus class.** Rationale: - L0 has a fixed set of 10 modules — direct `event` declarations are manageable without a central registry - C# `event` provides compile-time type safety; parameter mismatches are caught at build time, not runtime - Zero external dependencies — no third-party messaging library - Each L0 module's events are part of its public API contract, visible and self-documenting for external developers **Subscription lifecycle**: ``` L1/L2 subscribe to L0 events in OnEnable() L1/L2 unsubscribe in OnDisable() (NOT OnDestroy — avoids lost subscriptions on disable/re-enable cycles) ``` **Naming convention**: `On[What]` — e.g., `OnFormChanged`, `OnEnergyChanged`, `OnWaveStart` **Parameter convention**: Use lightweight structs or primitive types. Never pass mutable L0 internal object references to subscribers (prevents L1 from mutating L0 state). **Hot path exception**: Attack resolution and damage calculation use per-frame method calls (`CombatLogic.ResolveAttacks()`), not events. Events are reserved for low-frequency state transition notifications. ## Consequences - Each L0 module's event surface is explicitly visible, making inter-system communication self-documenting - No centralized message registry reduces coupling - L1 developers MUST follow OnEnable/OnDisable subscription discipline — leaks or null refs otherwise - If system count grows beyond ~20, a refactor to a dedicated EventBus may be warranted