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
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:
- String Allocation Churn: Unsanitized callsigns contain trailing whitespace, while hex strings alternate between uppercase and lowercase.
- 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.
- 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
| Field | Type | Storage Size | Rationale |
|---|---|---|---|
icao | string (6 char) | 6 bytes | Unique transponder address; standard for deduplication. |
callsign | string (8 char) | 8 bytes | Operator display string; trimmed of control characters. |
lat | float32 (fixed 4) | 4 bytes | Provides ~11m spatial resolution, sufficient for radar scopes. |
lon | float32 (fixed 4) | 4 bytes | Coordinate accuracy aligned with terminal display grids. |
alt | int32 | 4 bytes | Normalized to barometric altitude; invalid reads set to 0. |
spd | int16 | 2 bytes | Knots over ground; negative values discarded. |
hdg | int16 | 2 bytes | Magnetic/true track quantized to whole degrees. |
vs | int16 | 2 bytes | Rate of climb/descent; rounded to 50 fpm intervals. |
ts | int32 | 4 bytes | Second-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.
| Metric | Direct Client Ingestion (Raw) | Edge-Normalized Contract (Hushwire) | Reduction |
|---|---|---|---|
| Payload Size per Poll | 74.2 KB | 9.8 KB | 86.8% |
| JSON Parse Duration | 4.8 ms | 0.6 ms | 87.5% |
| V8 Heap Growth Rate | 1.8 MB / min | 0.1 MB / min | 94.4% |
| GC Pause Frequency | Every 42 seconds | Every 18 minutes | 96.1% |
| Max Frame Drop Rate | 14 frames / min | 0 frames / min | 100% |
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