Skip to content

Publish a synthetic node's declared cone as its detection area (#32 onto main) - #33

Merged
jehanazad merged 2 commits into
mainfrom
feat/evidence-only-coverage
Sep 15, 2026
Merged

jehanazad merged 2 commits into
mainfrom
feat/evidence-only-coverage

Conversation

@jehanazad

Copy link
Copy Markdown
Contributor

Lands #32 on main. #32 was merged into its stacked base branch feat/evidence-only-coverage rather than retargeted to main first (the repo does not delete branches on merge, so GitHub did not retarget it). This PR carries only #32's two commits; #28 is already on main via its merge commit.

Merged with a merge commit so the head 6df7c3d that offworldlabs/retina-server#367 pins as the libs/retina-analytics submodule stays reachable from main.

🤖 Generated with Claude Code

jehanazad and others added 2 commits September 13, 2026 20:57
get_node_summary publishes to_polygon(evidence_only=True) for every node.
That is right for real hardware — a real node's beam_azimuth_deg and
beam_width_deg are unsurveyed configuration, so drawing them would claim
coverage nobody measured — but it is wrong for a simulator node.  The
simulator emits a detection only for an aircraft inside the node's declared
cone (retina_simulation/world.py::_aircraft_in_detection_cone), so for those
nodes the cone IS the detection area by definition, and the evidence is the
unreliable half: the calibration points come from ADS-B hexes bound to tracks
and roughly a third of those binds are to the wrong aircraft.

Measured on test 2026-09-13, synth-GVL-SCAT-0032 (42 deg beam) held 3,037
calibration points of which 47% lay outside its wedge (34% ignoring the two
edge bins), 55 out-of-wedge bins had opened, and the published polygon covered
71 of 72 bearings.  Every synthetic node on the test map draws as a disc.

So: EmpiricalCoverageState.declared_wedge_polygon() draws the prior azimuth
and width at _reach_at on each bearing — already the bistatic ellipse when a
differential limit and the TX are known, else the circle, which is exactly the
simulator's own range rule — with no clamp, no bins and no min-points gate.
An omni prior gets a full ring; a directional one an apex-closed wedge with
both edges exact.

NodeAnalyticsManager.register_node grows a keyword-only
declared_geometry_is_truth flag (default False, asserted per registration, so
a re-registration without it drops the node again), and get_node_summary
publishes the declared wedge for a flagged node and the evidence-only shape
for everyone else.  The FOV diagnostics block is skipped for a flagged node —
it describes the learned wedge, which such a node does not publish — while
n_points/n_filled_bins stay in the payload: the evidence is still accumulated
and still worth reporting, it just is not drawn.  Every summary now names its
"polygon_source" (declared / evidence / learned) so the map can say which it
is showing rather than guess.

A flag change invalidates the 60 s summaries cache the same way a rebuilt
detection area does; retire_node, _reset_for_tests and the "cannot place this
node" path all clear it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Publish a synthetic node's declared cone as its detection area
@jehanazad
jehanazad merged commit 3586bfc into main Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant