From 591f7b0b315b001c2deee77abdf13931d3302b0d Mon Sep 17 00:00:00 2001 From: jungfrau Date: Fri, 2 Oct 2026 07:32:48 +0200 Subject: [PATCH] train_run: a run that already has a gate verdict is not trained again without --force The exit code 2 of a failed gate made the cycle script retry and train 2026-10-01_v4-recipeA twice. Co-Authored-By: Claude Fable 5.1 --- tools/train_run.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/train_run.py b/tools/train_run.py index 0dac62b..f53e261 100644 --- a/tools/train_run.py +++ b/tools/train_run.py @@ -174,12 +174,18 @@ def main(argv=None) -> int: ap.add_argument("--baseline", default=None, help="gold report to gate against (default: the active model's)") ap.add_argument("--no-promote", action="store_true", help="gate, but leave production.json alone") ap.add_argument("--skip-train", action="store_true", help="reuse runs//ultralytics/train/weights/best.pt") + ap.add_argument("--force", action="store_true", help="train again a run that already has a gate verdict") ap.add_argument("--set", nargs="*", default=[], metavar="KEY=VALUE", help="override any Ultralytics train argument, e.g. fliplr=0 mask_ratio=1 overlap_mask=true; recorded in the ledger") args = ap.parse_args(argv) run = ledger.load(args.run_id) run_dir = ledger.run_path(args.run_id).parent + # A gate verdict is an outcome, not a crash: the exit code 2 of a failed gate must not make a + # wrapper's retry train the whole run a second time (cycle 4 lost two hours that way). + if run.get("status") in ("gate_failed", "gate_passed", "promoted", "deployed") and not (args.skip_train or args.force): + print(f"{args.run_id} is already {run['status']}: not training it again (--force to retrain, --skip-train to re-measure)") + return 0 ds = dataset_dir(run) data_yaml = resolved_yaml(run_dir, ds) names = [v for _, v in sorted(json.loads((ds / "source.json").read_text())["classes"].items(), key=lambda kv: int(kv[0]))] \