Skip to content

Repository files navigation

Unit Mismatch Lab

One metric name. Two rulers. Four different versions of reality.

This interactive lab shows how compatible but conflicting metric units corrupt an aggregate. The default incident has eight producers declaring duration unit s; one actually reports milliseconds. Only 12.5% of the batch drifts, yet a name-only merge inflates fleet p95 from 132 milliseconds to 121.5 seconds—roughly 920×.

The measurement contract is an executable Protocol Buffers schema. A dependency-free Node.js service generates text-format messages, compiles them to protobuf wire bytes with protoc, decodes the binary, applies four policies, renders the result, and exposes correlated OTLP-shaped metrics, logs, and traces.

The failure

In the OpenTelemetry metrics data model, unit is an identifying property of a metric stream. Conflicting units such as ms and s are a semantic error. A producer may convert compatible units; otherwise it should report the conflict and pass both streams through. See the OpenTelemetry metrics data model.

OpenTelemetry’s general metric conventions say duration instruments should use seconds. Prometheus likewise recommends base units and requires a metric to represent one unit rather than mixing seconds and milliseconds. See the OpenTelemetry metric semantic conventions and Prometheus metric naming practices.

The lab compares four policies:

Policy Default result Failure mode
Name-only merge 121.5 s The fleet appears to have a massive latency incident
Plausibility filter 0.132 s The affected producer silently disappears; coverage falls to 87.5%
Split by resource eight panels The broken source is visible, but the fleet view fragments
Normalize + signal 0.132 s + alert The latency is corrected and the unit conflict remains observable

Why telemetry.sh helps

The lab emits the evidence needed to separate workload latency from measurement integrity:

  • lab.http.server.request.duration.p95 shows each policy’s displayed result;
  • telemetry.metric.unit_conflict.count identifies conflicting samples;
  • telemetry.input.coverage shows which policies remove data;
  • telemetry.unit.scale_factor distinguishes a 1,000× error from a 1,000,000× error;
  • warning and error logs preserve declared unit, actual unit, producer, and scale;
  • query spans record policy, coverage, conflict count, and dashboard state.

The operational pattern is:

  1. make the producer’s source unit explicit at a trusted boundary;
  2. normalize compatible values into the stream’s canonical unit;
  3. emit a conflict signal rather than silently repairing or discarding the evidence.

Run locally

Requirements:

  • Protocol Buffers compiler (protoc)
  • GNU Make
  • Node.js 20 or newer
npm ci
make check
make run

Open http://127.0.0.1:3000.

Useful endpoints:

GET /api/simulate
GET /api/telemetry
GET /healthz

Every UI control is also a query parameter:

/api/simulate?badUnit=MICROSECOND&producers=12&samples=30&driftProducer=9&driftRate=60&baselineMs=180&thresholdMs=500

Run with Docker

docker compose up --build

Then open http://127.0.0.1:3000.

Executable model

model/measurement.proto defines the complete wire contract:

message Sample {
  string producer = 1;
  string metric_name = 2;
  double value = 3;
  string declared_unit = 4;
  DurationUnit actual_unit = 5;
  uint32 sequence = 6;
  uint64 timestamp_unix_nano = 7;
}

The service creates text protobuf, then performs a real wire round trip:

protoc --proto_path=model --encode=unitlab.Batch model/measurement.proto
protoc --proto_path=model --decode=unitlab.Batch model/measurement.proto

The aggregation code operates only on the decoded records. The browser does not reimplement the protobuf contract or fabricate policy outputs.

Architecture

browser controls
      │
      ▼
Node.js service ── textproto ──▶ protoc encode ──▶ wire bytes
      ▲                                              │
      └── policies + OTLP evidence ◀── decoded batch ◀┘

No database, framework, credentials, CDN, or third-party JavaScript dependency is required.

Safety

This is a deterministic educational simulation. It sends no external traffic and exports no telemetry.

License

MIT

About

Interactive Protocol Buffers lab exposing latency incidents fabricated by conflicting metric units.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages