Support multi-sample promotion evidence
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-07-09 14:52:06 +02:00
parent f4af3b9eb0
commit 006819ca51
5 changed files with 142 additions and 17 deletions
@@ -252,3 +252,100 @@ def test_detection_model_promotion_report_uses_portfolio_and_tile_defaults(
report = json.loads((output_dir / "detection_model_promotion_report.json").read_text(encoding="utf-8"))
assert report["recommended_candidate"]["candidate_key"] == "candidate-from-portfolio|640|64|0.25"
def test_detection_model_promotion_report_accepts_multi_sample_quality_summary(
tmp_path: Path,
) -> None:
script_path = ROOT / "scripts" / "build_detection_model_promotion_report.py"
positive_path = tmp_path / "multi_sample_quality_summary.json"
positive_path.write_text(
json.dumps(
{
"items": [
{
"sample_slug": "geel",
"model_asset_id": "candidate-multi",
"tile_size": 512,
"tile_overlap": 64,
"threshold": 0.15,
"precision": 0.2,
"recall": 0.1,
"f1": 0.1333333333,
},
{
"sample_slug": "retie",
"model_asset_id": "candidate-multi",
"tile_size": 512,
"tile_overlap": 64,
"threshold": 0.15,
"precision": 0.3,
"recall": 0.2,
"f1_score": 0.24,
},
]
}
),
encoding="utf-8",
)
background_path = tmp_path / "hard_negative_matrix_summary.json"
background_path.write_text(
json.dumps(
{
"items": [
{
"sample_slug": "postel_bos",
"model_asset_id": "candidate-multi",
"tile_size": 512,
"tile_overlap": 64,
"threshold": 0.15,
"detection_count": 0,
},
{
"sample_slug": "lommel_heide",
"model_asset_id": "candidate-multi",
"tile_size": 512,
"tile_overlap": 64,
"threshold": 0.15,
"detection_count": 0,
},
]
}
),
encoding="utf-8",
)
output_dir = tmp_path / "promotion-report"
subprocess.run(
[
"python",
str(script_path),
"--positive-portfolio",
str(positive_path),
"--hard-negative-summary",
str(background_path),
"--output-dir",
str(output_dir),
"--min-positive-samples",
"2",
"--min-background-samples",
"2",
"--min-mean-f1",
"0.1",
"--max-background-detections-per-sample",
"0",
],
cwd=ROOT,
check=True,
text=True,
capture_output=True,
)
report = json.loads((output_dir / "detection_model_promotion_report.json").read_text(encoding="utf-8"))
decision = report["candidate_decisions"][0]
assert decision["candidate_key"] == "candidate-multi|512|64|0.15"
assert decision["positive_sample_count"] == 2
assert decision["mean_f1"] > 0.18
assert decision["promotion_status"] == "promote_candidate"