fix(prepare): tell a slow document server apart from a hung one
The first real bench — four government and corporate PDF URLs — lost three
of them before a single page reached Iris, and none of the three deserved to
be lost. The flat 120s download deadline was the cause: 35 MB at 40 KB/s is
a fifteen-minute download that is working perfectly, and document servers
are exactly that. A corpus assembled under that deadline is silently biased
toward small files on fast hosts, which is the one bias that would quietly
invalidate every number this harness exists to produce.
So the deadline becomes two clocks. STALL — no bytes at all for 45s — is the
real failure detector, re-armed on every chunk, so progress however slow is
never a failure. TOTAL is only a backstop against a server that dribbles
forever. Both are flags, because the right budget depends on the corpus.
Three things fell out of doing this against real URLs:
* TLS gets its own class. www.hr.uic.edu serves an incomplete certificate
chain, which browsers paper over by fetching the missing intermediate
and Node does not. It read as a bare "fetch failed" — indistinguishable
from a dead host, when the fix is a trust-store flag.
* The body is streamed, not buffered whole, so a file that lies about its
content-length is stopped at the cap instead of after it has been held
in memory.
* A fetch failure has to be retryable. Every one of these classes is
recoverable by changing a setting, but prepared.jsonl is append-only and
a recorded URL was skipped forever — so the advice to "raise it and
re-run" did nothing. `--retry` re-attempts exactly the fetch failures
and leaves settled verdicts alone, and both prepare and report now count
only a URL's most recent attempt, or one URL that failed and then
succeeded would be tallied as both and appear twice in the corpus.
Verdicts on those four URLs now: the UIC policy is not_pdf (it 302s to the
HR homepage — the file is gone), the Meta report prepares into 4 chunks of
94 pages, and the two slowest hosts stall mid-transfer and say where.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>