File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -674,12 +674,10 @@ def _update_position_history(
674674 lon : float ,
675675 timestamp : float ,
676676 ) -> None :
677- """Insert into the per-ICAO time-ordered ring buffer.
677+ """Insert a trusted position into the per-ICAO time-ordered ring buffer.
678678
679- Called for every resolved CPR pair regardless of whether
680- `_motion_consistent` accepted it — rejected positions still
681- enter the buffer so future real positions can find corroborating
682- neighbours even after a streak of phantoms.
679+ Callers add positions only after motion consistency or bootstrap
680+ validation. Rejected candidates must not validate themselves or repeats.
683681 """
684682 history = self ._position_history .setdefault (icao , [])
685683 history .append ((lat , lon , timestamp ))
@@ -959,7 +957,10 @@ def _handle_cpr_pair(
959957 d ["latitude" ] = None
960958 d ["longitude" ] = None
961959 self ._stats ["position_rejected" ] += 1
962- self ._update_position_history (icao , lat , lon , position_timestamp )
960+ if accepted :
961+ self ._update_position_history (
962+ icao , lat , lon , position_timestamp
963+ )
963964 if (
964965 accepted
965966 and bds == "0,5"
Original file line number Diff line number Diff line change @@ -1284,8 +1284,16 @@ def test_rejection_increments_stat_and_clears_fields(self):
12841284 # Pair was resolved but rejected — lat/lon must be absent or None
12851285 assert r .get ("latitude" ) in (None , 0 , False ) or r ["latitude" ] is None
12861286 assert pipe .stats ["position_rejected" ] == 1
1287- # Ring buffer still updated with the rejected position
1288- assert len (pipe ._position_history [self .ICAO ]) == 3
1287+ assert len (pipe ._position_history [self .ICAO ]) == 2
1288+
1289+ # Repeating the same CPR pair must not be accepted because the first
1290+ # rejected position was not added to trusted history.
1291+ pipe .decode ("8D40058B58C901375147EFD09357" , timestamp = 1002.0 )
1292+ repeated = pipe .decode ("8D40058B58C904A87F402D3B8C59" , timestamp = 1003.0 )
1293+ assert repeated .get ("latitude" ) is None
1294+ assert repeated .get ("longitude" ) is None
1295+ assert pipe .stats ["position_rejected" ] == 2
1296+ assert len (pipe ._position_history [self .ICAO ]) == 2
12891297
12901298 def test_eviction_prunes_old_position_history (self ):
12911299 pipe = PipeDecoder (eviction_ttl = 10.0 )
You can’t perform that action at this time.
0 commit comments