Your sampler says 10%. The incident cohort says 0%.
This interactive lab demonstrates a subtle probability-sampling failure: deterministic sampling can hit its fleet-wide target exactly while retaining no representative traces for most cohorts. The sampler arithmetic is correct; the trace ID randomness is not.
The executable model is a GNU Bison grammar compiled to C. A dependency-free Node.js service runs that model, renders the experiment, and exposes OTLP-shaped metrics, logs, and traces for inspection.
Four strategies evaluate the same request population:
| Strategy | Randomness input | What happens |
|---|---|---|
| Tenant suffix | A cohort number encoded in the trailing trace-ID bits | Global rate can look perfect while only one cohort is sampled |
| Low counter | A monotonic value in the trailing bits | Every request can fall below the rejection threshold |
| Random trace ID | Uniform trailing randomness with the random flag set | Sampling is distributed across every cohort |
Explicit rv |
Randomness carried in OpenTelemetry tracestate |
Structured IDs can retain consistent probability semantics |
The default scenario deliberately produces the most dangerous result: the structured generator samples exactly 10% overall, but covers only 1 of 10 cohorts and misses every error in the incident cohort.
OpenTelemetry's probability-sampling model compares a 56-bit randomness value R with a rejection threshold T. That randomness normally comes from the trailing seven bytes of the trace ID or from an explicit rv value in tracestate. See the Tracing SDK specification and probability-sampling specification. The W3C Trace Context Level 2 specification defines the corresponding trace-ID randomness requirements.
A dashboard that only checks the achieved sample rate cannot diagnose this failure. The lab emits evidence that can be correlated:
trace.sampling.actualtrace.sampling.cohort.coveragetrace.sampling.error.recalltrace.sampling.adjusted_count.biastrace.sampling.error_estimate.bias- warning and error logs describing unconfirmed randomness
- sampler evaluation spans with the random flag and explicit-randomness provenance
The result is a queryable explanation of why the retained traces are not representative—not merely a count of how many survived.
Requirements:
- GNU Bison
- a C99 compiler
- GNU Make
- Node.js 20 or newer
npm ci
make check
make runOpen http://127.0.0.1:3000.
Useful endpoints:
GET /api/simulate
GET /api/telemetry
GET /healthz
All model inputs can be supplied as query parameters:
/api/simulate?cohorts=16&requests=1000&ratio=5&hot=7&hotError=35&seed=91
docker compose up --buildThen open http://127.0.0.1:3000.
The browser controls produce this compact scenario language:
COHORTS 10
REQUESTS 500
RATIO 10
HOT 3
HOT_ERROR 24
BASE_ERROR 1
SEED 73
RUN
The grammar lives in model/sampler.y. make build asks Bison to generate a parser and compiles the result into build/sampler-model. Generated sources and binaries are intentionally excluded from Git.
browser controls
│
▼
Node.js HTTP service ── scenario DSL ──▶ GNU Bison model
│ │
├── interactive cohort view ◀──────────┤
└── OTLP-shaped metrics/logs/spans ◀───┘
No database, framework, CDN, or third-party JavaScript package is required.
This is a deterministic educational simulation. It creates no external traffic and exports no telemetry. The OTLP-shaped payload is available locally so the signal design can be inspected without credentials.