diff --git a/app.py b/app.py index 82bbcea..02f4f31 100644 --- a/app.py +++ b/app.py @@ -895,13 +895,20 @@ def no_candidate_detail(seen: int, stats: "collections.Counter", def exhausted_detail(tried: list[dict], attempts: int) -> str: - """Summarise the whole ladder instead of overwriting it with the last error.""" + """Summarise the whole ladder instead of overwriting it with the last error. + + Counts `tried`, not `attempts`. They agree for anything this version + enqueued, but a row carried over from before the ladder existed has + attempts=0 with a real failure recorded against it, which rendered as the + nonsense "tried 0 peers: 1x no bytes in 20m". The list is the evidence. + """ if not tried: return "no candidate could be enqueued" + n_peers = len({t.get("username") for t in tried if t.get("username")}) or len(tried) reasons = collections.Counter(t["reason"].split(":")[0] for t in tried) - plural = "" if attempts == 1 else "s" + plural = "" if n_peers == 1 else "s" joined = ", ".join(f"{n}x {r}" for r, n in reasons.most_common(3)) - return f"tried {attempts} peer{plural}: {joined}" + return f"tried {n_peers} peer{plural}: {joined}" async def try_next_candidate(job_id: str, artist: str, title: str, diff --git a/tests/test_acquisition.py b/tests/test_acquisition.py index 6375225..d3b9ab1 100644 --- a/tests/test_acquisition.py +++ b/tests/test_acquisition.py @@ -195,6 +195,13 @@ def main() -> int: check("only fails once the ladder is exhausted", r["state"] == "failed", r["detail"]) check("failure names every attempt, not just the last", "tried 3 peers" in (r["detail"] or ""), r["detail"]) + # A row carried over from before the ladder has attempts=0 but a real + # failure recorded, which must not render as "tried 0 peers: 1x ...". + check("a migrated row counts its evidence, not its counter", + app.exhausted_detail( + [{"username": "u1", "reason": "no bytes in 20m"}], 0) + == "tried 1 peer: 1x no bytes in 20m", + app.exhausted_detail([{"username": "u1", "reason": "no bytes in 20m"}], 0)) print("\nattempt cap") fake2 = FakeSlskd(per_query={"Creep": [