simulacra 0.1.0

A deterministic discrete-event simulation engine for message flow across large computer networks
Documentation
# AGENTS.md

Guidelines for AI agents working in this Rust codebase.

## Project Overview

**Simulacra** - A deterministic discrete-event simulation engine for modeling message flow across large computer networks, with pluggable latency, jitter, and failure models.

See `DESIGN.md` for architecture and roadmap.

## Commands

```bash
# Build
cargo build

# Build release
cargo build --release

# Run example
cargo run

# Test
cargo test

# Test with serde/JSON support
cargo test --features serde

# Check (fast compile check without producing binary)
cargo check

# Format code
cargo fmt

# Lint
cargo clippy

# Format check (CI-friendly, fails if unformatted)
cargo fmt -- --check
```

## Project Structure

```
src/
├── lib.rs           # Library root, public API exports
├── main.rs          # Example: async gossip protocol simulation
├── time.rs          # Time and Duration types
├── queue.rs         # EventQueue with deterministic ordering
├── sim.rs           # Core simulation engine and run loop
├── rng.rs           # Seeded deterministic RNG (SimRng)
├── trace.rs         # Event tracing and replay validation
├── task.rs          # Async task facade (sleep/recv/send.await)
└── net/
    ├── mod.rs       # Network simulation (Network, NetEvent, Message)
    ├── node.rs      # NodeId, MessageId types
    ├── topology.rs  # Topology, TopologyBuilder, routing
    ├── latency.rs   # Latency models (FixedLatency, UniformJitter, etc.)
    └── traced.rs    # TracedNetwork for recording simulation traces

Cargo.toml           # Project manifest
DESIGN.md            # Architecture and roadmap
```

## Features

- **default**: Core simulation without JSON support
- **serde**: Enables JSON import/export for traces (`Trace::to_json()`, `Trace::from_json()`)

## Core Concepts

### Time Model
- `Time` - A point in simulated time (nanoseconds from start)
- `Duration` - A span of simulated time
- Both are integer-based (no floats) for determinism

### Event System
- `Scheduled<E>` - Event with time and sequence number for tie-breaking
- `EventQueue<E>` - Priority queue with deterministic ordering
- Events at same time are ordered by insertion sequence

### Simulation
- `Simulation<E>` - Core engine with `run()`, `run_until()`, `step()` methods
- Handlers can schedule new events via `schedule()` or `schedule_in()`
- `SimulationStats` returned after completion

### Randomness
- `SimRng` - ChaCha8-based deterministic RNG
- `fork()` creates independent child streams
- Helpers: `jitter()`, `duration_with_jitter()`, `choice()`, `shuffle()`

### Network Layer
- `NodeId` - Node identifiers (u32-based)
- `Topology` - Graph of nodes with weighted links (latency)
- `TopologyBuilder` - Fluent API for common patterns (ring, star, mesh, line)
- `Network<P, L>` - High-level network simulation with message delivery
- `NetEvent<P>` - Deliver or Drop events with user payload
- `RunContext` - Handler context with `now()`, `send()`, `topology()`, `rng()`
- Latency models: `FixedLatency`, `UniformJitter`, `PercentageJitter`, `OverheadPlusJitter`

### Async Task Model
- `TaskSimBuilder<M>` - Builder for task-based simulations
- `TaskSim<M>` - Executor that runs async node functions
- `NodeContext<M>` - Context for async node code with:
  - `sleep(duration).await` - Suspend for simulated time
  - `recv().await` - Wait for incoming message
  - `send(dst, payload).await` - Send message to another node
  - `now()` - Current simulation time
  - `id()` - This node's ID
- `Envelope<M>` - Received message with src, dst, payload, timestamps
- `TaskSimStats` - Statistics from task simulation run

### Tracing & Observability
- `Trace<E>` - Complete trace of a simulation run with seed, events, final time
- `TraceEvent<E>` - Single event with timestamp, sequence, and data
- `TraceRecorder<E>` - Builder for recording traces during simulation
- `TracedNetwork<P, L>` - Network wrapper that automatically records traces
- `NetTraceEvent` - Simplified trace event for network simulations (serializable)
- `Trace::compare()` - Compare two traces for equality
- `Trace::validate_replay()` - Verify deterministic replay
- JSON export/import with `serde` feature: `to_json()`, `from_json()`, `write_json()`, `read_json()`

## Code Conventions

### Rust Edition
Uses Rust **2024 edition** - ensure your toolchain is up to date (`rustup update`).

### Style
- Follow standard Rust conventions (rustfmt defaults)
- Run `cargo fmt` before committing
- Run `cargo clippy` to catch common issues
- Extensive doc comments on public APIs
- Unit tests in `#[cfg(test)]` modules within each file

### Design Principles (from DESIGN.md)
- **Determinism first**: Same seed + inputs = same results
- **Simple kernel, rich layers**: Keep core small
- **Data-oriented**: Avoid needlessly object-heavy models
- **Observable by default**: Instrumentation is first-class
- **Ergonomic without hiding the model**: Pleasant API, explicit causality

### Dependencies
- `rand` and `rand_chacha` for deterministic RNG
- `serde` and `serde_json` (optional, with `serde` feature)
- Keep dependencies minimal per design philosophy

## Testing

Run the full test suite with `cargo test`. Current test coverage:
- Time arithmetic and ordering (5 tests)
- Event queue deterministic ordering (5 tests)
- Simulation run loop behavior (6 tests)
- RNG determinism and distribution (10 tests)
- Network topology and routing (10 tests)
- Latency models (6 tests)
- Network message delivery (6 tests)
- Trace recording and comparison (7 tests)
- TracedNetwork integration (3 tests)
- Async task model (12 tests)
- Doc tests (3 tests)

**Total: 74 unit tests + 3 doc tests** (with `--features serde`: 76 tests)

## Roadmap Status

**Phase 1 (Complete)**: Minimal kernel
- ✅ Time, Duration types
- ✅ Scheduled<E>, EventQueue
- ✅ Simulation loop
- ✅ Deterministic ordering
- ✅ Seeded RNG

**Phase 2 (Complete)**: Network domain
- ✅ NodeId, MessageId types
- ✅ Topology with adjacency list
- ✅ Dijkstra shortest-path routing with caching
- ✅ TopologyBuilder (ring, star, mesh, line patterns)
- ✅ Message delivery with NetEvent
- ✅ Latency models (fixed, uniform jitter, percentage jitter, overhead+jitter)
- ✅ Packet loss simulation

**Phase 3 (Complete)**: Reproducibility and traces
- ✅ Trace recording with TraceRecorder
- ✅ TracedNetwork for automatic tracing
- ✅ Trace comparison and replay validation
- ✅ JSON export/import (serde feature)
- ✅ RunContext.now() for time access in handlers

**Phase 4**: Ergonomics (skipped for now)
- Better scenario construction APIs
- Helper builders
- Docs and examples

**Phase 5 (Complete)**: Async/task facade
- `TaskSimBuilder` and `TaskSim` executor
-`NodeContext` with `sleep()`, `recv()`, `send()` futures
- ✅ Custom waker integration with event queue
- ✅ Deterministic task scheduling
- ✅ Message delivery via topology routing

**Phase 6 (Next)**: Scale exploration
- Profiling
- Allocation reduction
- Multi-run parallel execution

See `DESIGN.md` for full roadmap through Phase 7.

## Gotchas

- **Edition 2024**: Very recent edition. Requires nightly or latest stable.
- **No CI/CD yet**: Tests must be run manually.
- **Time overflow**: Operations panic on overflow; use `saturating_*` variants for safety.
- **Tie-breaking**: Events at identical times are processed in insertion order (FIFO).
- **Route caching**: Topology caches computed routes; call `clear_route_cache()` if links change after initial routing.
- **RunContext::send()**: Messages sent from handlers are scheduled after the handler returns, not immediately.
- **Trace serialization**: Requires `serde` feature; event types must implement `Serialize`/`Deserialize`.
- **Task futures**: Use custom no-op waker; real async runtimes (tokio, etc.) are not involved.
- **NodeContext::recv()**: Blocks the task until a message arrives; no timeout support yet.