Skip to content

fix(pi-backend): one failed inference request kills the driver while the accounting identity holds #1009

Description

@drewstone

One failed inference request kills the driver, even when the accounting identity holds

pi.ts throws pi inference traffic did not match its recorded usage whenever
inferenceTraffic.failedRequests > 0, regardless of whether the generation/receipt identity it
names in the message actually failed.

// src/backends/pi.ts:838
const accountingMatched = inferenceTraffic.generationRequests === usageCost.receipts
  && inferenceTraffic.rejectedRequests === 0
  && inferenceTraffic.failedRequests === 0
  && inferenceTraffic.inFlightRequests === 0

Measured cost

Eleven cells died to this on 2026-08-23 in one fleet. In every one of the eleven, the stated
identity held exactly
, and the only anomaly was a single failed request:

cell runtime lost generations receipts failed
osctemp-pendigits-lstm-gap-r1 80 min 48 48 1
tourney-nonkuramoto-core-r1 60 min 1 1 1
r46-nfree-residual-lp36-r1 60 min 13 13 1
un0-critical-sparsity-grid-r2 49 min 1 1 1
oscnp-3sat-success-rate-r1 41 min 27 27 1
un0-z40-decoupling-topology-r1 21 min 35 35 1
splaw-holdout-freeze-r1 20 min 16 16 1
eq-sym-violation-structure-4-r1 6 min 14 14 1
berbet-bits-per-cell-pareto-r1 2 min 5 5 1
mitten-circuit-ler-freeze-r1 <1 min 1 1 1
driftloss-cheaper-at-equal-score-r1 <1 min 1 1 1

Total 5 h 39 min of driver time. Four cells died in under three minutes. Each ended
no-winner, traversals:N after a single driver attempt, so the run reads afterwards as failed
research rather than as one dropped HTTP response.

Why the two conditions are different

traffic.generationRequests += 1 (pi-inference-transport.ts:1013) runs BEFORE the request is
attempted. So a generation that fails while piping its response (line 1081) is already counted as
a generation with no receipt, and the identity generations === receipts catches it on its own.

The failedRequests === 0 clause therefore adds only the cases the identity cannot see: a
credential-refresh failure at line 961, which increments failedRequests before the generation
counter, and any failed AUXILIARY request. The first is worth refusing on. The second is not, and
neither is a transient generation failure the identity already accounts for.

Suggested shape

Separate the two facts the check currently conflates. Refuse when the accounting identity is
violated, or when a request was rejected or left in flight. For a failed request whose identity
still balances, surface it on the receipt (it already is) and let the driver retry, rather than
throwing a terminal error whose message describes a mismatch that did not occur.

At minimum, the error text should not claim the traffic "did not match its recorded usage" when
the printed numbers in that same message show it matched: 14 generation request(s), 14 Pi usage receipt(s), 0 auxiliary, 0 rejected, 1 failed, 0 still in flight. A reader debugging this spends
the first hour looking for an accounting bug that is not there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions