Require tile quality evidence for training
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Jens
2026-07-29 17:37:55 +02:00
parent 037f875575
commit 21c464c715
5 changed files with 64 additions and 5 deletions
+38 -2
View File
@@ -98,6 +98,11 @@ def test_dry_run_can_gate_existing_checkpoint_without_training(tmp_path: Path) -
"status": "needs_human_review", "failures": [],
"manifest_immutable": True, "spatial_leakage_status": "ok",
}))
quality = tmp_path / "quality.json"
quality.write_text(json.dumps({
"status": "ok", "low_variance_positive_tile_count": 0,
"label_stats": {"invalid_label_count": 0, "missing_label_file_count": 0},
}))
result = subprocess.run(
[
sys.executable, str(SCRIPT),
@@ -105,6 +110,7 @@ def test_dry_run_can_gate_existing_checkpoint_without_training(tmp_path: Path) -
"--train-yaml", str(tmp_path / "dataset.yaml"),
"--train-summary", str(tmp_path / "train-summary.json"),
"--dataset-audit", str(audit),
"--train-quality-audit", str(quality),
"--calibration-summary", str(tmp_path / "cal.json"),
"--test-summary", str(tmp_path / "test.json"),
"--background-summary", str(tmp_path / "background.json"),
@@ -128,6 +134,11 @@ def test_existing_checkpoint_iteration_directory_can_be_created_without_yolo(tmp
def test_loop_refuses_failed_dataset_audit(tmp_path: Path) -> None:
audit = tmp_path / "audit.json"
audit.write_text(json.dumps({"status": "needs_attention", "low_variance_positive_tile_count": 4}))
quality = tmp_path / "quality.json"
quality.write_text(json.dumps({
"status": "ok", "low_variance_positive_tile_count": 0,
"label_stats": {"invalid_label_count": 0, "missing_label_file_count": 0},
}))
result = subprocess.run(
[
sys.executable,
@@ -140,6 +151,8 @@ def test_loop_refuses_failed_dataset_audit(tmp_path: Path) -> None:
str(tmp_path / "train-summary.json"),
"--dataset-audit",
str(audit),
"--train-quality-audit",
str(quality),
"--calibration-summary",
str(tmp_path / "cal.json"),
"--test-summary",
@@ -168,7 +181,11 @@ def test_pending_human_review_does_not_block_objective_training() -> None:
"low_variance_positive_tile_count": 0,
"review_complete": False,
}
assert MODULE.dataset_audit_failures(audit) == []
quality = {
"status": "ok", "low_variance_positive_tile_count": 0,
"label_stats": {"invalid_label_count": 0, "missing_label_file_count": 0},
}
assert MODULE.dataset_audit_failures(audit, quality) == []
def test_training_audit_still_fails_closed_on_automated_integrity_gates() -> None:
@@ -179,11 +196,30 @@ def test_training_audit_still_fails_closed_on_automated_integrity_gates() -> Non
"spatial_leakage_status": "failed",
"low_variance_positive_tile_count": 2,
}
failures = MODULE.dataset_audit_failures(audit)
quality = {
"status": "failed", "low_variance_positive_tile_count": 2,
"label_stats": {"invalid_label_count": 1, "missing_label_file_count": 1},
}
failures = MODULE.dataset_audit_failures(audit, quality)
assert "wallonia/test below minimum" in failures
assert "corpus manifest is not immutable" in failures
assert "spatial leakage audit is not ok" in failures
assert "dataset contains blank/low-variance positive tiles" in failures
assert "train tile quality audit is not ok" in failures
assert "train tile quality audit contains invalid labels" in failures
assert "train tile quality audit contains missing label files" in failures
def test_missing_tile_quality_evidence_fails_closed() -> None:
audit = {
"status": "needs_human_review", "failures": [],
"manifest_immutable": True, "spatial_leakage_status": "ok",
}
failures = MODULE.dataset_audit_failures(audit, {})
assert "train tile quality audit is not ok" in failures
assert "train tile quality audit contains invalid labels" in failures
assert "train tile quality audit contains missing label files" in failures
assert "dataset contains blank/low-variance positive tiles" in failures
def test_calibration_failure_blocks_protected_evaluation() -> None: