Skip to content

Skip overlap zones between nodes in different worlds - #25

Merged
jehanazad merged 1 commit into
mainfrom
feat/world-gate-overlap-zones
Sep 6, 2026
Merged

jehanazad merged 1 commit into
mainfrom
feat/world-gate-overlap-zones

Conversation

@jehanazad

@jehanazad jehanazad commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

What

register_node and rebuild_zones_for no longer build an overlap zone for a
node pair whose two nodes are in known, different worlds, and drop one that
already exists. New counter assoc_world_skipped_pairs counts the refusals.

Why

PR #23 gated ADS-B seeding on node_world_provider, but bottom-up pairing was
untouched — 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 of
156 synthetic dark solver records over a 7-minute window.

Measured live via /api/radar/association/status (read-only, no deploy):

pairs
overlap zones today 1653 (= C(58,2), all pairs)
sim/real cross-world pairs 400 (50 synthetic × 8 hardware)
...of those with a non-empty grid (a real adjacency edge) 39
zones left after the gate 1253 (1225 sim/sim + 28 real/real)

How

  • _worlds_compatible(a, b) — the fail-open rule the seed gate already
    applied, 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_pair helpers; both zone-building paths drop the pair
    rather 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_tests with the other counters.

Verified

tests/test_world_overlap_gate.py (9 tests): cross-world → no zone, no
adjacency, 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

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
jehanazad marked this pull request as ready for review September 6, 2026 02:25
@jehanazad
jehanazad merged commit 7d10869 into main Sep 6, 2026
1 check passed
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.

2 participants