diff --git a/tests/test_bluetooth_aggregator.py b/tests/test_bluetooth_aggregator.py index 43f4a00..c7820d5 100644 --- a/tests/test_bluetooth_aggregator.py +++ b/tests/test_bluetooth_aggregator.py @@ -568,10 +568,12 @@ class TestTrackerDetectionOptimization: with patch.object( aggregator._tracker_engine, "detect_tracker", wraps=aggregator._tracker_engine.detect_tracker ) as mock_detect: - aggregator.ingest(sample_observation) + device = aggregator.ingest(sample_observation) assert mock_detect.call_count == 0, ( "detect_tracker should not be called when the device payload fingerprint is unchanged" ) + # Tracker fields from first ingest must be preserved on skip + assert device.payload_fingerprint_id is not None def test_tracker_detection_runs_when_payload_changes(self, aggregator, sample_observation): """detect_tracker must be called again when the device's manufacturer data changes.""" diff --git a/utils/bluetooth/aggregator.py b/utils/bluetooth/aggregator.py index 774f18f..142c1ac 100644 --- a/utils/bluetooth/aggregator.py +++ b/utils/bluetooth/aggregator.py @@ -334,6 +334,9 @@ class DeviceAggregator: # Record sighting for persistence tracking. self._tracker_engine.record_sighting(fingerprint.fingerprint_id) + # Always update stability (can change as device fields are filled in). + device.payload_fingerprint_stability = fingerprint.stability_confidence + # Only re-run the expensive signature scan when the payload has changed. if fingerprint.fingerprint_id == device.payload_fingerprint_id: return @@ -356,7 +359,6 @@ class DeviceAggregator: device.tracker_confidence_score = result.confidence_score device.tracker_evidence = result.evidence device.payload_fingerprint_id = fingerprint.fingerprint_id - device.payload_fingerprint_stability = fingerprint.stability_confidence def _update_risk_analysis(self, device: BTDeviceAggregate) -> None: """Evaluate suspicious presence heuristics for a device."""