first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
# `ChaosEngine`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Probabilistic failure injector for chaos testing. Each call to `step(nodes, edges)` rolls four independent dice (crash / partition / message-drop / transport-fault) using the simulator's seeded RNG, applies the relevant mutation, and appends a `ChaosEvent` to the engine's event log. Used to push the mesh past the predefined-scenario surface and surface bugs that only appear under noisy real-world conditions.
## Features
- Four configurable per-step probabilities — set any to `0` (or omit) to disable that chaos type.
- Crash and transport-fault both pick a random victim from the live `nodes` array; partition picks a random victim edge from the supplied edge list.
- Message-drop is decoupled from a specific message — it fires based on the per-step probability so callers can pair drops with arbitrary downstream traffic.
- Event log is per-engine and survives `step` calls so test assertions can read the full chaos history in one shot.
- Pure RNG via the simulator means deterministic chaos under a fixed seed.
## Usage: Basic Example
```ts
import {
ChaosEngine,
NetworkSimulator,
VirtualNode,
} from "@suaveplan/network-plugin-simulation";
const sim = new NetworkSimulator({ seed: 1 });
const nodes = [new VirtualNode({ id: "n1", tier: 0 }, sim)];
const chaos = new ChaosEngine(sim, { crashProbability: 0.5 });
const events = chaos.step(nodes, []);
console.log(events);
```
## Usage: Advanced Example
```ts
import {
ChaosEngine,
NetworkSimulator,
VirtualNode,
} from "@suaveplan/network-plugin-simulation";
const sim = new NetworkSimulator({ seed: 99 });
const nodes = Array.from(
{ length: 5 },
(_, i) => new VirtualNode({ id: `n${i}`, tier: i === 0 ? 0 : 1 }, sim)
);
const edges = nodes
.slice(1)
.map((n) => ({ from: "n0", to: n.id }));
const chaos = new ChaosEngine(sim, {
crashProbability: 0.05,
partitionProbability: 0.02,
messageDropProbability: 0.10,
transportFaultProbability: 0.01,
});
for (let tick = 0; tick < 100; tick += 1) {
sim.advanceBy(1);
chaos.step(nodes, edges);
}
console.log(chaos.eventLog().length);
```
## API Reference
- `class ChaosEngine(simulator, config?)`
- `update(config: ChaosConfig): void`.
- `step(nodes, edges): ReadonlyArray<ChaosEvent>` — events emitted this step.
- `eventLog(): ReadonlyArray<ChaosEvent>` — full log since construction.
- `reset(): void` — clears the event log.
- `interface ChaosConfig` — `{ crashProbability?, partitionProbability?, messageDropProbability?, transportFaultProbability? }`.
- `interface ChaosEvent` — `{ atMs, type, target?, target2? }`.
## Implementation Notes
- The engine never throws — chaos is intentionally noisy and the simulator should not abort because of an unlucky roll. Caller code that wants to refuse particular events should filter the event log post-hoc.
- Crash skips victims that are already not-running; transport-fault does not, because a transport fault on a downed node is still a meaningful test event for downstream dispatchers.
- `messageDropProbability` is not paired with a specific message because the engine does not know about message identities — pair it with a downstream layer that consults the event log for "should I drop the next outbound?" decisions.
- The four probabilities are independent — every step can emit between zero and four events.