fix: always update fingerprint stability; assert tracker fields preserved on skip

- Move fingerprint stability update before early return so it updates even when payload hash matches
- Remove duplicate stability assignment from detect_tracker result block
- Add assertion in test to verify tracker fields are preserved when detection is skipped

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
James Smith
2026-05-19 14:49:51 +01:00
parent 5852e05339
commit fca4bda48c
2 changed files with 6 additions and 2 deletions
+3 -1
View File
@@ -568,10 +568,12 @@ class TestTrackerDetectionOptimization:
with patch.object( with patch.object(
aggregator._tracker_engine, "detect_tracker", wraps=aggregator._tracker_engine.detect_tracker aggregator._tracker_engine, "detect_tracker", wraps=aggregator._tracker_engine.detect_tracker
) as mock_detect: ) as mock_detect:
aggregator.ingest(sample_observation) device = aggregator.ingest(sample_observation)
assert mock_detect.call_count == 0, ( assert mock_detect.call_count == 0, (
"detect_tracker should not be called when the device payload fingerprint is unchanged" "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): 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.""" """detect_tracker must be called again when the device's manufacturer data changes."""
+3 -1
View File
@@ -334,6 +334,9 @@ class DeviceAggregator:
# Record sighting for persistence tracking. # Record sighting for persistence tracking.
self._tracker_engine.record_sighting(fingerprint.fingerprint_id) 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. # Only re-run the expensive signature scan when the payload has changed.
if fingerprint.fingerprint_id == device.payload_fingerprint_id: if fingerprint.fingerprint_id == device.payload_fingerprint_id:
return return
@@ -356,7 +359,6 @@ class DeviceAggregator:
device.tracker_confidence_score = result.confidence_score device.tracker_confidence_score = result.confidence_score
device.tracker_evidence = result.evidence device.tracker_evidence = result.evidence
device.payload_fingerprint_id = fingerprint.fingerprint_id device.payload_fingerprint_id = fingerprint.fingerprint_id
device.payload_fingerprint_stability = fingerprint.stability_confidence
def _update_risk_analysis(self, device: BTDeviceAggregate) -> None: def _update_risk_analysis(self, device: BTDeviceAggregate) -> None:
"""Evaluate suspicious presence heuristics for a device.""" """Evaluate suspicious presence heuristics for a device."""