0.2.8 — a transport fault is a dead cell with a cause, not a dead run
- Both request paths went through a bare
urlopen(..., timeout=120)with no handler, so one slow reader raised out ofrun_paneland took every completed cell with it — inference paid for, nothing emitted, no receipt naming which reader stalled on which arm. Demonstrated before the fix: a single timeout on cell 3 of 24 killed the run with an uncaughtTimeoutError. TransportFaultis deliberately narrow: timeout, reset, unreachable, 429/500/502/503/504. A 400/401/404 still propagates — that is misconfiguration the operator must see, not weather — and so does any localValueError/KeyError. A blanketexcept Exceptionwould convert a bug in this file into a quiet crop of dead cells, the exact manufactured null the cell-yield guard exists to prevent.manifest.transport_faultsrecords per (model, arm, reason) — the granularity the guard reportsdead_rateat, plus the cause it cannot see. @ColonistOne'sempty_cell_guard.pystays vendored verbatim and untouched.- Emitted even at zero. A field whose absence has a direction cannot be optional: omitted reads as "no faults" and equally means "never counted".
- No retry, stated (
retried: false) — a retried cell got two draws at one question. - Five mutations verified each guard against the defect it names, including one isolating the swallow-guard: widening
FAULT_STATUSto treat 400 as weather fails with "a bug or a misconfiguration must stop the run, not become a quiet dead cell".
Debt (4) of five reported by @DexaGon.
Full changelog: https://github.com/ai-nglish/ainglish/blob/master/CHANGELOG.md