# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Build & Test ```bash # Build cargo build -p velo-events # Run all tests cargo test -p velo-events # Run a single test cargo test -p velo-events # Check (no codegen) cargo check -p velo-events ``` ## Architecture `velo-events` is a generational event system for coordinating async awaiters with minimal overhead. Events can be triggered (success) or poisoned (error), and entries are recycled across generations. ### Core types (`event.rs`, `manager.rs`) - **`Event`** — concrete RAII guard for a single event. Dropping without calling `trigger(self)` or `poison(self, ...)` auto-poisons the event. `into_handle(self)` disarms the guard and returns the bare handle. `trigger` and `poison` consume `self`, preventing double-completion at compile time. - **`EventManager`** — concrete struct that manages a collection of events: `new_event`, `awaiter`, `poll`, `trigger`, `poison`, `merge_events`, `force_shutdown`. Create with `EventManager::local()` for local use or `EventManager::new(base, backend)` for distributed setups. - **`EventBackend`** — public trait with 3 methods (`trigger`, `poison`, `awaiter`) that serves as the routing customization point. `EventSystemBase` implements this for the local path; distributed backends implement it to add network routing. ### Base implementation (`base/`) - **`EventSystemBase`** — the core event storage, allocation, and recycling engine. Uses `DashMap` for concurrent event storage with a free-list for entry recycling. Implements `EventBackend` for local trigger/poison/awaiter routing. Constructors: `EventSystemBase::local()` (random system_id, local flag set) and `EventSystemBase::distributed(system_id)` (explicit id, no local flag). Public `_inner` methods (`trigger_inner`, `poison_inner`, `awaiter_inner`) allow distributed backends to delegate local operations. ### Handle encoding (`handle.rs`) `EventHandle` packs identity into a single `u128`: `[system_id: 64][local_index: 32][generation: 32]`. Bit 31 of `local_index` distinguishes local (bit set) from distributed (bit clear) handles. Both local and distributed systems have unique non-zero `system_id` values. `EventSystemBase` validates that handles belong to the system that created them. ### Slot machinery (`slot/`) Single-lock synchronization primitives. See [docs/slot-state-machine.md](docs/slot-state-machine.md) for invariants. Any change to `slot/` must preserve all invariants (I1-I6) and update the document. Key types: - **`EventEntry`** — per-index state machine with a single `ParkingMutex` protecting generation tracking, waker registration, and poison history. - **`EventAwaiter`** — `Future` impl that resolves to `Result<()>`. Supports both immediate (already-complete) and pending modes. Delegates poll to `EventEntry::poll_waiter`. - **`CompletionKind`** — `Triggered` | `Poisoned(Arc)`. ### Factory (`factory.rs`) `DistributedEventFactory` creates an `EventManager` pre-configured with a `system_id` for distributed (Nova-managed) deployments. ## Key Design Decisions - `Event` is an RAII guard by default — dropping without triggering auto-poisons. `into_handle()` is the explicit opt-out for manager-level operations. `Clone` is intentionally not implemented; each event is a unique ownership token. - `EventManager` is a concrete `Clone` struct holding `Arc` (lifecycle) + `Arc` (routing). `EventManager::local()` creates both from the same `EventSystemBase`. `EventManager::new(base, backend)` accepts a custom backend for distributed routing. - `EventBackend` is the public routing trait (3 methods) that enables distributed routing without touching the core event lifecycle. Distributed backends call `EventSystemBase::trigger_inner` / `poison_inner` / `awaiter_inner` for local handles and route remote handles over the network. - Slot entries track a `BTreeMap` for poison history, allowing past-generation poison queries. - Generation overflow causes entry retirement and a new entry allocation (transparent retry loop in `new_event_with_backend`). - `force_shutdown` poisons all pending events and rejects future allocations via an `AtomicBool` flag.