A run that exhausts the queries it was given writes its own. The caller asks for a number of leads, not for a number of queries, but a YouTube search stops at roughly 500 creators per axis, so a selective filter set could spend every page of every query and still finish short — sixty queries yielded 16,890 creators and 786 leads, ninety yielded 25,228 and 711. When all three axes of every query are spent, the run now builds further queries from the channel keywords of the creators it has actually kept — the source's own words for the niche the caller is really after — and those queries then get the same treatment: further pages, the view-count axis, the video axis. The run reports how many it wrote in candidateSupply.queriesWritten.
Nothing but the cost ceiling limits how large a run may grow. Two counters did, and neither guarded anything. The replacement-round allowance was half a round per requested lead, so a run for 1,000 leads stopped at 500 of 500 rounds having examined 20,373 creators and saved 548, while 63 of its searches still held unread pages. The candidate allowance was capped at 40 creators examined per requested lead, and a selective search — emailOnly over a subscriber band, measured at 2.7% kept — needs 37, so the cap sat exactly where such a run had to work. Both are gone: a round ends by itself when discovery returns nothing, and the allowance now follows the run's own keep rate with no ceiling.
Adding queries no longer kills the run inside its own search. Searching pays for itself, but the credit only arrived once the searches were over — while they ran, the opening $0.008 had to cover them. Sixty queries put $0.0055 on the wire and fitted; ninety cost $0.0083 and did not, so a 90-query run stopped at cost_limit fifty seconds in, having saved nothing, with all 89 searches still holding pages. Adding queries is the one real answer to a shortfall, and it was the one thing guaranteed to produce one. The credit now extends as the searching happens, still bounded, and only what the searches put on the wire is credited — waiting buys nothing.
Topping up counts as work, not as idling. The same guard that killed a run during its opening search also killed it during a replacement round: a run stopped at no_progress_limit with 152 leads saved, six freshly written queries in flight and ten searches still holding pages. The idle clock now stops while any search runs and restarts when it returns.
A wide search is no longer mistaken for a stalled run. The no-progress guard counts candidates finished, and nothing reports the creators discovery is finding, so a run whose searches took longer than a minute — sixty queries, or any search slowed by retries — was killed the moment it started working, with zero leads saved. Measured: the same sixty queries took 19 s on a quiet source and 64 s under load. The idle clock now starts at the first candidate; during discovery the searches are bounded by their own cost credit and the run deadline.
A spent query set now says so, instead of blaming a limit. When the searches answer a replacement round with only creators the run has already examined, top-up ends — and it used to end by setting the round counter to its budget, so the run reported having used all 100,000 of its replacement rounds and sent the buyer looking for a limit to raise. It now reports what actually happened: the searches still list further pages, but those pages repeat channels already seen, so the query set is spent and the answer is more queries or looser filters. sourceExhausted counts that case as exhausted, with pagesLeftButRepeating to tell it apart from a source with no pages left at all.
A run may take up to six hours. The Actor's own time guard already scaled with the candidates a run was allowed to examine, but the platform stopped every run at three hours regardless. Rows are written as they are found, so a run that is stopped keeps everything it had saved.