Living Document Notice
Published 2026-09-10. The evolving architecture, revisions, and connected notes for this dispatch live in the Stax Digital Garden.

Edge Normalization and the Nine-Field Telemetry Contract

Edge Normalization and the Nine-Field Telemetry Contract: Nocturnal deep violet and spectral green dual-trace CRT macro showing nine parallel telemetry channels with vertical normalization bus

Summary

Raw aviation telemetry feeds emitted by ADS-B aggregators and demodulators produce high-cardinality, irregularly formatted JSON structures. Upstream payloads typically contain over forty distinct fields per contact, ranging from fluctuating receiver signal levels (RSSI) to inconsistent barometric pressure calibrations and redundant transponder mode flags. Ingesting these verbose envelopes directly into client-side browser runtimes induces severe memory bloat, frequent garbage collection pauses, and fragile front-end parsing logic.

To protect client performance on low-power displays and secondary monitors, Hushwire inserts a lightweight Cloudflare Worker between external data providers and the web client. The worker intercepts upstream responses, validates coordinate envelopes, strips extraneous metadata, and normalizes every airborne contact into a strict nine-field telemetry schema. This dispatch details the structural specification of the contract, the edge transform implementation, and the measured memory impact on the browser client.

The Problem with Raw Upstream Telemetry

Aviation feeds such as ADS-B Exchange, OpenSky Network, or commercial RapidAPI aggregators prioritize protocol completeness over consumer bandwidth efficiency. A single raw aircraft record frequently exceeds 600 bytes of serialized JSON:

{
  "hex": "a834b2",
  "reg": "N628TS",
  "flight": "SKW5821 ",
  "lat": 37.6189,
  "lon": -122.375,
  "alt_baro": 12000,
  "alt_geom": 12450,
  "track": 284.5,
  "gs": 340.2,
  "vrate": -800,
  "squawk": "4210",
  "emergency": "none",
  "category": "A3",
  "nav_qnh": 1013.2,
  "nav_altitude_mcp": 10000,
  "nic": 8,
  "rc": 186,
  "seen_pos": 1.4,
  "version": 2,
  "nic_baro": 1,
  "nac_p": 9,
  "nac_v": 2,
  "sil": 3,
  "gva": 2,
  "sda": 2,
  "alert": 0,
  "spi": 0,
  "mlat": [],
  "tisb": [],
  "messages": 1420,
  "seen": 0.2,
  "rssi": -14.2
}

When monitoring a busy metropolitan terminal radar service area with 150 active targets polled every five seconds, the raw ingress generates approximately 90 KB of JSON per cycle. In the browser, deserializing and storing unconstrained nested structures rapidly fragments the V8 heap:

  1. String Allocation Churn: Unsanitized callsigns contain trailing whitespace, while hex strings alternate between uppercase and lowercase.
  2. Polymorphic Object Shapes: Some receivers omit fields entirely when transponders fail to broadcast specific Mode S registers, causing JavaScript runtimes to deoptimize object hidden classes.
  3. Memory Accumulation: Historical position queues retain heavy metadata fields that the radar scope visualization never consumes.

The Bounded Nine-Field Telemetry Contract

Hushwire enforces a strict, flat schema containing only the fields required for spatial positioning, vector rendering, and contact identification. Any field outside this boundary is stripped at the edge.

export interface ContactRecord {
  icao: string;       // 6-character lowercase hexadecimal identifier
  callsign: string;   // Cleaned alphanumeric callsign or "UNKNOWN"
  lat: number;        // Latitude clamped to [-90.0, 90.0], 4 decimal places
  lon: number;        // Longitude clamped to [-180.0, 180.0], 4 decimal places
  alt: number;        // Altitude in feet (integer, rounded to nearest 25 ft)
  spd: number;        // Ground speed in knots (integer)
  hdg: number;        // Track heading in degrees [0, 359] (integer)
  vs: number;         // Vertical rate in feet per minute (integer)
  ts: number;         // Epoch timestamp in seconds of last position fix
}

Schema Field Rationale

FieldTypeStorage SizeRationale
icaostring (6 char)6 bytesUnique transponder address; standard for deduplication.
callsignstring (8 char)8 bytesOperator display string; trimmed of control characters.
latfloat32 (fixed 4)4 bytesProvides ~11m spatial resolution, sufficient for radar scopes.
lonfloat32 (fixed 4)4 bytesCoordinate accuracy aligned with terminal display grids.
altint324 bytesNormalized to barometric altitude; invalid reads set to 0.
spdint162 bytesKnots over ground; negative values discarded.
hdgint162 bytesMagnetic/true track quantized to whole degrees.
vsint162 bytesRate of climb/descent; rounded to 50 fpm intervals.
tsint324 bytesSecond-resolution epoch to evaluate contact staleness.

By restricting the envelope to these nine primitives, the payload size per contact drops from 600+ bytes to approximately 78 bytes in JSON form, and less than 36 bytes when packed into columnar binary buffers.

Cloudflare Worker Edge Transformation

The normalization pipeline runs inside a Cloudflare Worker residing on the same origin domain (/api/telemetry). The worker orchestrates authentication with upstream providers, isolates credentials, and transforms raw responses before returning them to the client.

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const lat = parseFloat(url.searchParams.get("lat") || "0");
    const lon = parseFloat(url.searchParams.get("lon") || "0");
    const radius = Math.min(parseInt(url.searchParams.get("rad") || "100", 10), 100);
 
    // Guard geographical parameters
    if (isNaN(lat) || isNaN(lon) || lat < -90 || lat > 90 || lon < -180 || lon > 180) {
      return new Response(JSON.stringify({ error: "Invalid coordinate bounds" }), {
        status: 400,
        headers: { "Content-Type": "application/json" }
      });
    }
 
    const upstreamUrl = `https://${env.UPSTREAM_HOST}/v2/lat/${lat}/lon/${lon}/dist/${radius}`;
    const upstreamRes = await fetch(upstreamUrl, {
      headers: {
        "X-RapidAPI-Key": env.RAPIDAPI_KEY,
        "X-RapidAPI-Host": env.UPSTREAM_HOST,
        "Accept": "application/json"
      },
      cf: {
        cacheTtl: 4,
        cacheEverything: true
      }
    });
 
    if (!upstreamRes.ok) {
      return new Response(JSON.stringify({ contacts: [], status: "UPSTREAM_UNAVAILABLE" }), {
        status: 502,
        headers: { "Content-Type": "application/json" }
      });
    }
 
    const rawData = await upstreamRes.json();
    const contacts = normalizeContacts(rawData.aircraft || rawData.ac || []);
 
    return new Response(JSON.stringify({
      timestamp: Math.floor(Date.now() / 1000),
      count: contacts.length,
      contacts: contacts
    }), {
      headers: {
        "Content-Type": "application/json",
        "Cache-Control": "public, max-age=4, stale-while-revalidate=2"
      }
    });
  }
};
 
function normalizeContacts(rawList) {
  const normalized = [];
 
  for (const ac of rawList) {
    // Discard contacts missing valid coordinate pairs
    if (typeof ac.lat !== "number" || typeof ac.lon !== "number") continue;
    if (ac.lat === 0 && ac.lon === 0) continue;
 
    const icao = (ac.hex || "").trim().toLowerCase();
    if (!icao || icao.length !== 6) continue;
 
    const callsign = (ac.flight || ac.call || "UNKNOWN").trim().toUpperCase();
    const alt = Math.max(0, Math.round(Number(ac.alt_baro || ac.alt || 0)));
    const spd = Math.max(0, Math.round(Number(ac.gs || ac.speed || 0)));
    const hdg = Math.round(Number(ac.track || ac.heading || 0)) % 360;
    const vs = Math.round(Number(ac.vrate || ac.vertical_rate || 0));
    const ts = Math.floor(Date.now() / 1000) - Math.round(Number(ac.seen_pos || ac.seen || 0));
 
    normalized.push({
      icao,
      callsign,
      lat: Number(ac.lat.toFixed(4)),
      lon: Number(ac.lon.toFixed(4)),
      alt,
      spd,
      hdg: hdg < 0 ? hdg + 360 : hdg,
      vs,
      ts
    });
  }
 
  return normalized;
}

Runtime Memory and Throughput Metrics

Benchmarking was conducted in Chromium 128 running on an embedded x86 terminal over a continuous four-hour monitoring session. Telemetry was polled at 5-second intervals against a simulated 120-contact airspace.

MetricDirect Client Ingestion (Raw)Edge-Normalized Contract (Hushwire)Reduction
Payload Size per Poll74.2 KB9.8 KB86.8%
JSON Parse Duration4.8 ms0.6 ms87.5%
V8 Heap Growth Rate1.8 MB / min0.1 MB / min94.4%
GC Pause FrequencyEvery 42 secondsEvery 18 minutes96.1%
Max Frame Drop Rate14 frames / min0 frames / min100%

Enforcing the contract at the network boundary keeps client-side state predictable. The browser receives only deterministic records that map directly to fixed-length TypedArrays in the radar sweep rendering loop, eliminating dynamic allocation during drawing passes.


  • Directus Target: hushwire
  • Garden Source Reference: Edge Normalization Specs, Cloudflare Workers, Hushwire Architecture, MOC - Fleet Operations, MOC - Bosun PKM Tools