No fabricated identity or altitude for unassociated single-node tracks - #253
Conversation
Clutter promotions were rendering as plausible low-level aircraft. A radar-only track got a synthetic PR#### callsign, tar1090 category, and alt_baro straight from the single-node LM solve — but single-node bistatic geometry is underdetermined in altitude, so that number is essentially free: observed live 2026-08-26 from 165 ft to 50,768 ft on one node, with 48 unassociated pr* tracks in 8.5 min (none matching any ground truth, lifetimes quantized at the 15 s display TTL), 25 of them "below 6,000 ft". On the map they read as periodic low-altitude ghost aircraft. - track_entry publishes alt_baro/alt_geom only when some ADS-B identity vouches for them: a fresh fix directly, or the solver fallback for an ADS-B-hexed track with a stale/partial fix (the behaviour test_fresh_adsb_fallback pins). A track with no ADS-B identity ships null altitude — every consumer already null-guards (list shows "—"). - The synthetic PR#### callsign is gone; an empty flight falls back to the hex everywhere downstream. - The map draws no plane icon for unassociated solver_single_node tracks (the arc-less frame of the same single-node geometry) — the precedent set for arc-midpoint tracks, whose lat/lon convention already gets no marker. They stay in the list as Solver·1N rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @jehanazad's task in 4m 39s —— View job Claude finished the review
|

Summary
Confirmed live 2026-08-26: periodic "low-altitude ghost aircraft" and orphan noise arcs are one phenomenon — waves of unassociated single-node detections promoted to
pr*tracks. Each got a fabricated identity (syntheticPR####callsign, category A3) and an altitude straight from the single-node LM solve, which is underdetermined in altitude (observed 165 ft to 50,768 ft on one node; 48 ghosts in 8.5 min, none matching any ground truth, lifetimes quantized at the 15 s display TTL). This PR stops publishing what the geometry cannot know, so clutter reads as an unidentified detection instead of a plausible aircraft on the deck.Changes
services/track_gates.py—track_entrypublishesalt_baro/alt_geomonly when some ADS-B identity vouches for them: a fresh fix directly, or the solver fallback for an ADS-B-hexed track with a stale/partial fix (test_fresh_adsb_fallbackpins that fallback and still passes). A track with no ADS-B identity ships null altitude. The syntheticPR####callsign is gone; an emptyflightfalls back to the hex everywhere downstream.frontend/src/components/LiveAircraftMap.tsx— no plane icon for unassociatedsolver_single_nodetracks (the arc-less frame of the same single-node geometry), extending the precedent Three-lane map icon colors, immediate icon handoff, drift-based icon hiding #243 set for arc-midpoint tracks. They stay in the list as Solver·1N rows; error-line and detail-panel handling is unchanged.Test coverage
TestUnassociatedEntryHonestyintests/test_track_gates.py: unassociated track publishes null altitude and empty callsign; ADS-B-backed track keeps both.tsc --noEmit,vite build, and vitest (121 passed) in the node:20 container. Pre-commit gate clean.Review notes
solver_single_nodeicon removes the only map presence of an arc-less unassociated track (arc-midpoint tracks at least keep their arc). In the measured window these were 100% clutter (zero ground-truth matches), and their drawn position is a weakly-determined solve — but a real dark target caught by exactly one node with no buildable arc would now appear only in the list.min_snr=4.0in retina-tracker) — a sensitivity trade-off that deserves its own change.🤖 Generated with Claude Code