fix(batch): resume from run-meta.json, not from log-file existence - #329
Open
vaibhavdabas16 wants to merge 1 commit into
Open
fix(batch): resume from run-meta.json, not from log-file existence#329vaibhavdabas16 wants to merge 1 commit into
vaibhavdabas16 wants to merge 1 commit into
Conversation
--resume decided a job was done if batch-logs/<case>-<model>.log existed. That log is opened when a job *starts* (batch.py:320), so resume skipped every job that was ever attempted -- including the ones killed mid-run. That inverts the flag: after a network blip or an OOM takes out 20 of 130 tasks, --resume skips exactly those 20 and calls the batch complete. The second effect was worse, because it destroyed data rather than omitting it. write_summary_json rewrites batch-summary.json from the in-memory job list, and every carried-over job was marked "skipped" with duration 0. A resumed batch therefore reported none of the results it already had, in the artifact that the per-run stats and the HuggingFace upload consume. run-meta.json is the authoritative record: run.py writes one for any run that got far enough to have an outcome, failures included -- the invariant TIGER-AI-Lab#303, TIGER-AI-Lab#302 and TIGER-AI-Lab#314 each protect. load_recorded_runs() indexes those by (test_case, model) straight from the metadata, so a model name containing "/" matches despite the run directory sanitising it to "--", and the newest run wins when repeated resumes have left several directories for one pair. A truncated run-meta.json is treated as an unknown outcome and the job runs again rather than having a result invented for it (TIGER-AI-Lab#312/TIGER-AI-Lab#325 showed that file can be truncated). A carried-over job now keeps the recorded result -- passed / failed / error, with its real duration -- so the rewritten summary preserves the original tallies. Jobs are marked `resumed` so the scheduler still skips running them and a reader of batch-summary.json can tell a carried-over row from one this invocation produced. --retry-failed additionally re-runs jobs whose recorded outcome was an infra-class failure. It uses the scorer's own NON_MODEL_FAILURE_CATEGORIES -- infra_failure, api_or_credit, task_data, build_instruction -- which are exactly the categories excluded from adjusted scoring, so those runs carry no signal about the model and a re-run is the only way to get one. Genuine model failures are kept: the model was asked and it failed, and re-running buys the same answer at full cost. Say the word if you would rather the flag retry those too. tests/test_batch_resume.py covers the path, which had none: resume passed `resume=None` everywhere. Eight of its seventeen tests fail against the log-existence heuristic, checked by swapping that logic back in and holding the tests constant. Fixes TIGER-AI-Lab#297. Related: TIGER-AI-Lab#160 asks for exactly this path to be verified.
11 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes #297 — all three asks.
--resumedecided a job was finished ifbatch-logs/<case>-<model>.logexisted. That log is opened when a job starts (batch.py:320), so resume skipped every job that was ever attempted — including the ones killed mid-run. That inverts the flag: after a network blip or an OOM takes out 20 of 130 tasks,--resumeskips exactly those 20 and reports the batch complete.The second effect destroyed data rather than just omitting it.
write_summary_jsonrewritesbatch-summary.jsonfrom the in-memory job list, and every carried-over job was written asstatus: "skipped", duration_seconds: 0. A resumed batch reported none of the results it already had, in the artifact the per-run stats and the HuggingFace upload consume.Ask 1 — decide completion from
run-meta.jsonrun.pywritesrun-meta.jsonfor any run that got far enough to have an outcome, failures included — the invariant #303, #302 and #314 each protect.load_recorded_runs()indexes those by(test_case, model), read from the metadata rather than the path, so:/matches its job even though the run directory sanitises it to--;case × modelpair;run-meta.jsoncounts as an unknown outcome and the job runs again, rather than having a result invented for it. fix(batch): one truncated run-meta.json no longer discards the batch summary #312/Fix/303 write batch summary json before printing stats #325 established that this file can be truncated.A job with no recorded outcome stays pending and runs again. That is the whole fix for ask 1: "has a log" becomes "has a result".
Ask 2 —
--retry-failedRe-runs jobs whose recorded outcome was an infra-class failure, using the scorer's own
NON_MODEL_FAILURE_CATEGORIES(infra_failure,api_or_credit,task_data,build_instruction). Those are already the categories excluded from adjusted scoring, so such a run carries no signal about the model and a re-run is the only way to get one.One judgment call worth your eye: genuine model failures (
model_not_intercepted) are kept, not retried — the model was asked and it failed, so a re-run buys the same answer at full agent cost. The issue says "failure/infra error", which could be read either way. Say the word and I'll widen it to retry those too, or split it into two flags.Ask 3 — merge prior statuses into the summary
A carried-over job keeps its recorded result —
passed/failed/error— with its real duration, so the rewrittenbatch-summary.jsonpreserves the original tallies instead of zeroing them.Jobs are marked
resumed, which does two things: the scheduler still skips executing them (it previously keyed offstatus == "skipped", which is no longer what a carried-over job looks like), and a reader ofbatch-summary.jsoncan tell a carried-over row from one this invocation produced. That adds one key per job to the summary — flagging it since that file is consumed downstream, though it is additive and existing keys are unchanged.Corpus
Host-side batch driver; no task data involved.
Test plan
tests/test_batch_resume.py, 17 tests. This path had no coverage — every existing test passesresume=None, which batch --resume skips failed jobs (log-file heuristic) and overwrites batch-summary.json with 'skipped' rows #297 notes and test(resilience): verify resume works — auto-restart on abort + alerting #160 asks to fix.apply_resume, held the tests constant, and re-ran: 8 of the 17 fail, including the two that matter most — a started-but-unfinished job being skipped, and the summary losing its tallies.batch-summary.json(totalsstaypassed: 1, failed: 1rather than collapsing toskipped: 2); the outcome→status mapping; missing/unparsableduration_seconds;--retry-failedon and off; newest-run-wins; truncated metadata; a/in the model name; an empty or absent output directory.test_host_tasks.py::test_checked_task_json_files_parse_and_validate, which fails only on this Windows checkout — the task files are git symlinks (mode120000) checked out as text — and is green on CI.ruff checkreports the same 8 pre-existing findings onbatch.pyasmaindoes — no new ones.ruff format --checkclean.pyright --pythonplatform Linux(matching the ubuntu runner) 0 errors.batch.pymust stay importable without a container engine (test_batch_stays_importable_without_a_container_engine). The new import isrun_support.results, which does not pull inrun_support.config; verified, and that test still passes.mainand against all five of my other open PRs — including fix(runner): bound container wait so one wedged run can't stall a batch #316, which touches the same file.Not verified: no live batch run — I don't have Docker on this machine. The resume decision logic is exercised against real-shaped
run-meta.jsonfixtures on disk, not against an interrupted 130-task sweep.Related issues
Fixes #297. Related: #160 (resume/resilience testing) asks for exactly this path to be verified end-to-end; this adds the unit-level half.
docs/cli.md's--resumerow described skipping "finished runs", which was the intent but not the behaviour — updated to match what the code now does, plus a row for--retry-failed.