6.25.1 - A pump that produced nothing says so
Drop-in from 6.25.0. One arm added on the loopback VOD path, no API change.
A pump that produced nothing now says so, whatever killed it
isFatalVODPumpExit decides that a non-live pump exit with nothing ever produced (no packets written, empty segment cache) is a dead source: the playlist exists, no segment will ever land, and AVPlayer parks in waitingToPlay forever unless it surfaces. That reasoning, from #126, is entirely about what the pump produced. The guard on it also required case .readError, which does not follow from it, and in the meantime nothing called the predicate at all: the read-error arm had grown its own inline copy of the same decision, leaving the tested predicate as dead code.
So a source that reaches EOF having written nothing fell through every arm on the way out. Measured on such a file: reason=eof packetsRead=322 packetsWritten=0 cacheCount=0, then 404 init.mp4 empty from the provider, and the host reporting state=playing phase=rebuffering for the whole session, with nothing in it to act on. It now reports state=error("Source produced no playable media (code -5)") in about a second.
The gate-starvation re-anchor (#169 round 3) reports whether it actually re-anchored, so a spent budget or a keyframe that maps to no plan segment falls through to that same surface instead of ending on a bare return. That is the third arm of this shape found in this file after 6.25.0, and the pattern is worth naming: an exhausted recovery that returns silently leaves a session no one can distinguish from a slow one.
What keeps this safe is the produced-nothing condition rather than the exit reason. An ordinary EOF after real playback carries packets and segments and is untouched (the control fixture still reaches state=ended), teardown is excluded, and every reason that owns its own recovery arm returns before this decision is reached.
How it was found
While checking whether #365 needed an AVC counterpart. It does not: matroskadec.c routes every video codec except HEVC through libavformat's parser, so an H.264 file whose config record and packets disagree cannot be demuxed at all, with or without the 6.25.0 framing repair, and there is nothing left for an engine-side fix to act on. That file is, however, exactly the shape above: demuxable enough to open, incapable of yielding a keyframed packet, and previously silent about it.
1827 swift-testing plus 504 XCTest green, tvOS build clean.