"""Segmentation must honour the same post-processing configuration as detection. Segmentation reuses the detection suppressor but passed only the IoU threshold, so it silently fell back to the hardcoded containment constant while detection read a configured one. A deployment tuning containment for a promoted model changed detection behaviour and left segmentation on the old value. """ from __future__ import annotations import pytest from shapely.geometry import box from app.core.config import Settings def test_segmentation_has_its_own_containment_setting() -> None: settings = Settings(_env_file=None) assert settings.segmentation_containment_nms_threshold == pytest.approx(0.85) def test_the_setting_is_independent_of_the_detection_one() -> None: """Masks and boxes overlap differently; one value need not fit both.""" settings = Settings( _env_file=None, yolo_containment_nms_threshold=0.7, segmentation_containment_nms_threshold=0.95, ) assert settings.yolo_containment_nms_threshold == pytest.approx(0.7) assert settings.segmentation_containment_nms_threshold == pytest.approx(0.95) def test_the_configured_value_reaches_the_suppressor() -> None: from app.services.detection_service import DetectionService def candidate(name: str, geometry, confidence: float): return { "class_name": "building", "confidence": confidence, "geometry": geometry, "bbox": [0.0, 0.0, 1.0, 1.0], "source_tile_path": f"/tiles/{name}.tif", "properties": {"name": name}, } outer = candidate("outer", box(0, 0, 10, 10), 0.9) # Containment 0.9, IoU 0.09: only the containment rule can act on this pair. mostly_nested = candidate("mostly", box(8.2, 1, 10.2, 6), 0.5) strict = DetectionService._suppress_duplicate_candidates( [outer, mostly_nested], iou_threshold=0.5, containment_threshold=0.95 ) loose = DetectionService._suppress_duplicate_candidates( [outer, mostly_nested], iou_threshold=0.5, containment_threshold=0.7 ) assert len(strict) == 2 assert len(loose) == 1