Keep rejected training regressions from propagating
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 23:33:53 +02:00
parent b8e40ba7a8
commit a5b321fdb6
2 changed files with 60 additions and 2 deletions
+29 -2
View File
@@ -92,6 +92,25 @@ def calibration_failures(
return failures
def rejected_candidate_score(assessment: dict[str, Any]) -> tuple[float, ...]:
"""Rank rejected candidates by the weakest normalized release gate first."""
calibration = assessment["calibration"]
gates = assessment["gates"]
normalized: list[float] = [
calibration["aggregate"]["f1"] / gates["min_aggregate_f1"]
]
for metrics in calibration["regions"].values():
normalized.extend(
(
metrics["f1"] / gates["min_region_f1"],
metrics["precision"] / gates["min_region_precision"],
metrics["recall"] / gates["min_region_recall"],
)
)
normalized.sort()
return tuple(normalized)
def training_command(
yolo: str,
*,
@@ -430,7 +449,15 @@ def main() -> int:
"failures": decision["failures"],
}
state["iterations"].append(record)
state["next_model"] = str(candidate)
score = rejected_candidate_score(decision) if decision["status"] != "training_complete" else ()
incumbent_score = tuple(state.get("incumbent_rejected_score", ()))
if not incumbent_score or score > incumbent_score:
state["incumbent_rejected_model"] = str(candidate)
state["incumbent_rejected_score"] = list(score)
record["promoted_to_training_incumbent"] = True
else:
record["promoted_to_training_incumbent"] = False
state["next_model"] = state.get("incumbent_rejected_model", str(candidate))
if decision["status"] == "training_complete":
state["status"] = "training_complete"
state["completed_at"] = datetime.now(UTC).isoformat()
@@ -457,7 +484,7 @@ def main() -> int:
record["failure_driven_sampling_sha256"] = sha256(sampling_evidence)
record["next_train_yaml"] = str(next_train_yaml)
state["next_train_yaml"] = str(next_train_yaml)
model = candidate
model = Path(state["next_model"])
train_yaml = next_train_yaml
write_json(state_path, state)