Fix stale-partial reuse and n_chunks mismatch in analysis condor pipeline
CI / Lint (ruff check) (push) Successful in 30s
CI / Format (ruff format) (push) Failing after 29s
CI / Type check (ty) (push) Successful in 31s
CI / Sync project version with tag (push) Has been skipped
CI / Tests (push) Successful in 1m42s

- prep() now clears reduced_partial/ and reduced/ on every (re-)run.
  Partial files carry no record of what context (n_chunks, bin edges,
  group sets) they were computed under, so re-prepping the same run_dir
  with a different --chunks/--bins/--top-pdg (or after the rollout was
  regenerated) previously left old partials on disk that merge_one
  would silently merge against the new shared.json — producing a
  wrong-but-plausible reduced/*.json with no error.
- write_submit() now checks SubmitConfig.n_chunks against the run
  directory's own RunMeta.n_chunks (fixed at prep time, and what
  rows_per_chunk is sized against) and raises a clear error on
  mismatch, instead of an uncaught IndexError deep in _job_walltimes.

Each fix has a regression test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 13:48:43 +02:00
parent ad0341a9d4
commit ad1b8e7835
2 changed files with 61 additions and 0 deletions
+34
View File
@@ -121,6 +121,26 @@ def test_prep_splits_rows_per_chunk(tmp_path: Path):
assert sum(meta.rows_per_chunk) == meta.total_rows == 8
def test_reprep_clears_stale_partials_from_a_different_chunk_count(tmp_path: Path):
"""Re-prepping with a different n_chunks must not leave old chunk
partials on disk for merge_one to silently merge against the new
context (they'd be keyed/sized for the old n_chunks)."""
yaml_path = _write_inputs(tmp_path)
run_dir = _prep(yaml_path, chunks=2)
compute_one("marginal_edep", run_dir, chunk_index=0)
compute_one("marginal_edep", run_dir, chunk_index=1)
stale = run_dir / "reduced_partial" / "marginal_edep__0.json"
assert stale.exists()
(run_dir / "reduced").mkdir(exist_ok=True)
(run_dir / "reduced" / "marginal_edep.json").write_text("{}")
_prep(yaml_path, run_dir, chunks=1)
assert not stale.exists()
assert not (run_dir / "reduced" / "marginal_edep.json").exists()
assert (run_dir / "shared.json").exists() # prep's own fresh output untouched
def test_compute_one_from_run_dir(tmp_path: Path):
run_dir = _prep(_write_inputs(tmp_path))
out = compute_one("marginal_edep", run_dir)
@@ -237,6 +257,20 @@ def test_write_submit_chunks_respect_chunkable(tmp_path: Path):
assert counts["router_gating"] == 1 # chunkable=False, ignores n_chunks
def test_write_submit_rejects_n_chunks_mismatch_with_run_meta(tmp_path: Path):
"""cfg.n_chunks must match the n_chunks the run_dir was actually prepped
with — RunMeta.rows_per_chunk is sized to the prepped value, so a
mismatch would otherwise surface as a confusing IndexError deep inside
_job_walltimes instead of a clear error here."""
run_dir = _prep(_write_inputs(tmp_path), chunks=2)
_fake_venv(tmp_path)
cfg = SubmitConfig(
run_dir=run_dir, accounting_group="cms", repo_dir=tmp_path, n_chunks=4
)
with pytest.raises(ValueError, match="n_chunks"):
write_submit(cfg)
def test_estimate_runtime_s_scales_with_rows_and_margin():
from giant.analysis import RUNTIME_SAFETY_MARGIN, estimate_runtime_s
from giant.analysis.runtime_estimate import _FIXED_OVERHEAD_S