A random failure is hard to review.

The telemetry publisher begins with a clean list of envelopes. A fault plan transforms it into release instructions: reverse each configured window, add a fixed delay to named sequences, and insert a second delivery with the original event identity at a known offset.

There is no random number generator in that path. Given the same input and plan, a test can assert the exact release order and the exact duplicate identity.

duplicate every:  5
reorder window:   4
delay:            sequence 8 by 600 ms

clean:   01 02 03 04 | 05 06 07 08
release: 04 03 02 01 | 07 06 05 ... 08
duplicate identity: evt-005 appears twice

The point is not realism at any cost. It is control over the variable being investigated.

Use two layers of tests.

Decision tests

Fast xUnit tests pin the schedule, database uniqueness, replay cursor and counters. They explain which decision failed without requiring infrastructure.

Boundary test

The integration suite uses a real RabbitMQ service. It starts the .NET worker, publishes a faulted schedule through AMQP, and polls SQL until every delivery has a recorded outcome. Each run creates unique topology names and a temporary database, so parallel or repeated runs do not share state.

A mocked broker can prove the callback. It cannot prove the exchange, queue, routing, acknowledgement or serialisation boundary.

Make the local path match CI.

Build.ps1 restores, checks formatting, builds in Release and runs the unit suite. Test-Integration.ps1 starts RabbitMQ and enables the broker-backed test. Run-Demo.ps1 builds the containers, runs a named replay, waits for processing and prints the SQL summary.

The GitHub Actions workflow uses the same solution and commands. RabbitMQ runs as a service container with a health check; the job does not race an unopened broker port.

The report belongs to storage.

The publisher knows how many deliveries it attempted. It does not decide what persisted. The report reads transactionally maintained SQL counters:

{
  "deliveries": 28,
  "inserted": 24,
  "duplicates": 4,
  "outOfOrder": 18
}

Those numbers are useful because their owner is clear. They still need context: reversed four-event windows deliberately make many sequences late, and the count should not be presented as a production reliability metric.

Leave the limits next to the result.

The README states what the lab does not cover: broker clusters, dead-letter operations, distributed transactions, load or soak testing, safety certification and domain-specific state-estimation policy. This is not modesty theatre. It makes the evidence usable.