"""Attribute aggregation — pure maths, no models.""" from behavision.attributes import aggregate def test_median_age_ignores_one_wild_frame(): samples = [{"age": 47}, {"age": 51}, {"age": 12}] # 12 = a bad frame out = aggregate(samples) assert out["age"] == 47 # median, not mean (mean would be 36) assert out["age_spread"] == 39 # and the disagreement is reported def test_majority_gender_wins_over_a_single_flip(): out = aggregate([ {"gender": "Male", "gender_confidence": 0.9}, {"gender": "Male", "gender_confidence": 0.8}, {"gender": "Female", "gender_confidence": 0.99}, ]) assert out["gender"] == "Male" assert out["gender_confidence"] == 0.85 # mean over the winning frames only def test_empty_and_partial_inputs(): assert aggregate([]) == {} assert aggregate([{}, None]) == {} assert aggregate([{"gender": "Female", "gender_confidence": 0.7}]) == { "gender": "Female", "gender_confidence": 0.7} def test_caffe_age_range_is_aggregated_too(): out = aggregate([{"age_range": "38-43"}, {"age_range": "38-43"}, {"age_range": "25-32"}]) assert out["age_range"] == "38-43" def test_person_event_reports_the_quality_the_gate_actually_used(): """The enrollment gate runs on track.best_quality. Reporting this frame's track.quality instead made events look like they had passed a threshold they were below (observed: quality=0.586 logged against a 0.65 gate).""" import threading import numpy as np from behavision.config import Config from behavision.engine import CameraWorker from behavision.gallery.service import Resolution from behavision.faces import FaceOutbox from behavision.tracking import Track cfg = Config() published = [] class Enc: size = 112 def encode_chip(self, chip): v = np.ones(512, np.float32) return v / np.linalg.norm(v) class Gal: def resolve(self, mean, quality, cam, ts, attributes=None, rcfg=None): self.seen_quality = quality self.seen_rcfg = rcfg return Resolution(kind="new", identity_id=1, label="Visitor 1", similarity=0.1, new_sighting=True) w = object.__new__(CameraWorker) w.cfg, w.encoder, w.attrs = cfg, Enc(), None w.rcfg = cfg.recognition.merged(None) # no per-camera overrides here w.commission = None # no placement check running w.gallery = Gal() w.cam_cfg = type("C", (), {"id": "cam1"})() w.bus = type("B", (), {"publish": staticmethod(published.append)})() # Images are off, the product default. A real FaceOutbox rather than a # mock, so a worker built this way runs the same disabled path # production does when store_faces is unset. w.faces = FaceOutbox(cfg.app.data_dir, enabled=False) kps = np.array([[130, 100], [190, 100], [160, 130], [135, 165], [185, 165]], np.float32) track = Track(id=1, box=(100, 60, 220, 200), kps=kps, score=0.9, quality=0.40, best_quality=0.80, hits=10) frame = np.zeros((240, 320, 3), np.uint8) ts = 1000.0 for _ in range(cfg.tracking.min_embeddings_for_id): ts += 0.04 w._identify(track, frame, ts) assert published, "no event published" data = published[0].data assert w.gallery.seen_quality == 0.80 # the gate saw best_quality assert data["quality"] == 0.80 # and so does the event assert data["frame_quality"] == 0.40 # this frame, kept for context