Skip overlap zones between nodes in different worlds - #25
Merged
Merged
Conversation
The world gate added for ADS-B claiming and seeding stops a node verifying its tag against the other world's fix, but bottom-up pairing was untouched: register_node and rebuild_zones_for build a grid for every positioned pair, so a synthetic fleet sharing a footprint with real hardware keeps a zone for every sim/real pair. Two nodes in different worlds can never see the same echo, so those grids have no true pairing to find — every candidate they produce is a simulated tracklet matched against a real one. On the test droplet (50 synthetic nodes and 8 receivers over Greenville) that is 400 of 1653 zones, 39 of them with a real overlap, and real node ids duly appear in 48 of 156 synthetic dark solver records over a 7-minute window. Both zone-building paths now consult node_world_provider and skip the pair, under the same fail-open rule the seed gate uses: only two known, different worlds are refused, and an unknown world on either side (no provider, a node the provider does not know) still pairs with everything. The rule moves into _worlds_compatible so the two gates cannot drift apart; that also makes an empty tag read as unknown rather than as a third world matching nothing. Both paths drop rather than merely skip, because a node can change world after its grids were built — a late CONFIG handshake, a reused node id — and a rebuild is exactly where the grids it built against the world it left have to go. assoc_world_skipped_pairs counts the refusals, so a fleet whose pairs are being gated can be told apart from one whose pairs never overlapped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
jehanazad
pushed a commit
that referenced
this pull request
Sep 6, 2026
Stacks this PR on #25 and #26 so the three merge cleanly in order. association.py / test_track_association.py resolved as on the deploy/dark-solver-stack integration branch: candidates keep t_s_a/t_s_b and the candidate helper carries t_s through the cluster split. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
jehanazad
marked this pull request as ready for review
September 6, 2026 02:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
register_nodeandrebuild_zones_forno longer build an overlap zone for anode pair whose two nodes are in known, different worlds, and drop one that
already exists. New counter
assoc_world_skipped_pairscounts the refusals.Why
PR #23 gated ADS-B seeding on
node_world_provider, but bottom-up pairing wasuntouched — every positioned pair still got a grid. On the retina-test droplet
50 synthetic nodes and 8 real receivers sit over the same city, so the
associator holds a zone for every sim/real pair, and a pairing drawn from one
of those grids can only ever match a simulated tracklet against a real echo.
A read-only audit found real node ids (
retf1144fcd,ret7dd2cb0d) in 48 of156 synthetic dark solver records over a 7-minute window.
Measured live via
/api/radar/association/status(read-only, no deploy):How
_worlds_compatible(a, b)— the fail-open rule the seed gate alreadyapplied, now shared by both gates so they cannot drift: only two known and
different tags are refused; unknown (no provider, unknown node, untagged
state) or empty is compatible with everything.
_node_world/_drop_pairhelpers; both zone-building paths drop the pairrather than skipping it, so a node that changes world after its grids were
built (late CONFIG handshake, reused node id) sheds them on the next
registration or rebuild.
assoc_world_skipped_pairs, incremented per skipped pair and reset by_reset_for_testswith the other counters.Verified
tests/test_world_overlap_gate.py(9 tests): cross-world → no zone, noadjacency, counter bumped; same world → unchanged; one untagged → unchanged;
empty tag → unchanged; no provider → unchanged; world change dropping the zone
on rebuild and on re-registration; counter reset.
Full library suite:
420 passed(411 before, plus the 9 new).Consumed by the retina-server pin bump in offworldlabs/retina-server (draft PR
linked from there), which exposes the counter on
/api/radar/association/status.🤖 Generated with Claude Code