Skip to content

Carry the pool's measurements on the solver input - #30

Merged
jehanazad merged 1 commit into
mainfrom
feat/pool-measurements
Sep 7, 2026
Merged

jehanazad merged 1 commit into
mainfrom
feat/pool-measurements

Conversation

@jehanazad

Copy link
Copy Markdown
Contributor

What

format_track_pairs_for_solver already stamps pool_n_nodes / pool_node_ids — the node set of the input's shared-track component, i.e. the widest solve the round could have produced for that aircraft. This adds the other half: pool_measurements, one {node_id, track_id, delay_us, doppler_hz, snr, t_s} per pool node that is not already in the input's measurements, plus pool_conflicts.

Why

Measured live tonight: 72% of published dark solves are narrower than their pool (mean shortfall 2.27 nodes). Published n=2 with pool>=3: 28 of 45. Published n=3 with pool>=4: 125 of 169. And 390 of 481 rejected n2_unconfirmed candidates had pool>=3 — a third node was available in the same round, and an n=3 candidate publishes 81% of the time against 6% for n=2.

Widening the position merge radius is not the fix (a 6 km sweep raised cross-aircraft contamination from 25% to 32%). The fix is for the solver worker to adopt a pool node only when the solve itself vouches for it — predict what that node should measure at the solved position/velocity and check it agrees. That needs the missing node's actual numbers, and once the clustering declines to merge a pairing those numbers are unreachable downstream. This makes them reachable; it decides nothing.

How

  • _shared_track_pools now returns (node_ids_by_pair, measurements_by_pair). The measurement map is built in the union-find pass it was already making, keyed per component as node_id → track_id → measurement, so it costs one dict per pairing side.
  • _solver_input takes the pool's measurements and emits only the spare part — pool nodes absent from the cluster. A node the component reached on two different tracks is genuinely ambiguous (one of them is another aircraft): the highest SNR wins and pool_conflicts counts how many nodes needed that tiebreak, so the coin-flip rate is visible instead of silent.
  • None rather than [] when there was no round to take a pool from, matching pool_n_nodes' "not measured".

Tests

Three new cases in TestSharedTrackPool: the missing node's delay/Doppler travels with the narrow input (and the wide sibling has nothing spare); a pool node seen on two tracks takes the strongest and sets pool_conflicts; an input built with no round reports None.

pytest tests --ignore=tests/test_empirical_coverage_fixes.py (shapely not installed in this env): 416 passed. ruff check / ruff format --check clean.

🤖 Generated with Claude Code

pool_n_nodes told the solver worker that a round had more nodes for an
aircraft than the input it was handed uses, and nothing more.  Measured
live tonight, 72% of published dark solves are narrower than their pool
(mean shortfall 2.27 nodes), and 390 of 481 rejected n=2 candidates had
a pool of 3 or more — a third node existed in the same round and would
have made an n=3 candidate, which publishes 81% of the time against 6%
for n=2.  Acting on that requires the missing node's numbers, not just
its id: once the position clustering declines to merge a pairing, the
delay and Doppler it carried are unreachable downstream.

So the shared-track component now also collects its measurements, and
each input stamps pool_measurements: one {node_id, track_id, delay_us,
doppler_hz, snr, t_s} per pool node that is NOT already in the input.
A node the component reached on two different tracks is ambiguous by
construction (one of them is another aircraft), so the strongest SNR
wins and pool_conflicts counts how many nodes needed that tiebreak —
the rate at which a consumer's adoption gate is being handed a coin
flip, rather than a silent guess.

Nothing here decides whether widening is correct: that judgement needs
a solved position to predict against, and this stage has none.  It only
makes the material reachable.  Cost is one dict per pairing side in the
union-find pass already being made, and None (not []) whenever there is
no round to take a pool from, matching pool_n_nodes' "not measured".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jehanazad
jehanazad merged commit 06a90f4 into main Sep 7, 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.

1 participant