Show how much longer a rate limited batch has to run - #91
Merged
Conversation
A throttled row said only that it was waiting, so a batch that was working correctly but slowly was indistinguishable from one that had hung. On a wiki allowing 8 uploads a minute, 100 files take over twelve minutes, and that is the right outcome rather than a fault -- but only if the user is told. The figure is not a measurement. The gate hands out one slot per interval and already knows when the next is due, so this is arithmetic on a schedule the client is itself enforcing: the wait left on the current backoff, plus one interval for every file queued behind it. Nothing is sampled, so nothing needs smoothing. Shown only while the wiki is actually throttling, because that is the only time a schedule exists. Before the first refusal there is nothing to estimate, and guessing from the advertised hits would assume a fresh budget, which is the one thing the API does not report. Whole minutes, rounded up, and "about". The estimate excludes the transfer itself and can grow if the wiki refuses again, so a ticking countdown would claim a precision it does not have. Rounding is also what keeps the live region quiet: the text changes at most once a minute rather than on every refresh. Verified against a live wiki -- a 128 second batch produced two distinct strings, not 128. The count comes from the batch limit rather than the upload queue. A file being retried has left the queue and not yet rejoined it, so the queue undercounts by one per retrying file at exactly the moment a refusal is being handled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Several explained the mechanism the code already shows, or repeated a rationale that belonged in one place. What remains is the four notes that stop someone making a plausible wrong change: why the count does not come from the upload queue, why there is no smoothing, why the figure is rounded up to whole minutes, and why the DOM write is guarded. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Member
Author
Three tests looked like they covered the new code and did not. Verified by mutation: deleting the halted guard from schedule(), dropping nextReleaseAt from the wait it reports, and adding ful-estimate to the pruned classes all left the suite green. The nextReleaseAt one mattered most. Every schedule test read the gate before any file had passed it, so the term was only ever exercised on the openAt side -- yet once the first backoff expires it is the only thing holding the next file up, which is where a paced batch spends nearly all its life. Under that mutation the readout would have said "less than a minute" for an entire batch with nothing to catch it. The create, update and remove logic moves to estimateRow.js so it can be tested under jsdom the way resultRow.js already is. It was the riskiest part of the change and the only part with no tests, purely because of where it lived. While extracting it: role="status" was on the <li>, which replaces its listitem role, so the list announced one fewer item than it had. The live region is now a span inside the row, which keeps both semantics. Also stops claiming a wait for a single file that is released immediately, moves a docblock the earlier split left on the wrong function, and drops a padding declaration the rule above already sets. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Follows-up to #89
A throttled row said only that it was waiting, so a batch that was working correctly but slowly looked the same as one that had hung. On a wiki allowing 8 uploads a minute, 100 files take over twelve minutes — the right outcome, but only if the user is told.
A line above the result list now says how much longer the wiki's limit will hold the batch up:
It is a schedule, not a measurement
The gate hands out one upload slot per interval and already knows when the next is due, so the figure is arithmetic on a schedule the client is itself enforcing:
Nothing is sampled, so nothing needs smoothing. The exponential averaging and downward bias that upload UIs usually carry exist to tame a measured byte rate; there is no byte rate here.
It excludes the transfer time itself, which is additive and matters for large files, and it can grow if the wiki refuses again. Hence "about", and hence whole minutes rather than a countdown.
Shown only while throttled
Pacing begins on the first refusal and lapses after a quiet window, so that is exactly when a schedule exists. Before then there is nothing to estimate — and inferring one from the advertised
hitswould assume a fresh budget, which is the one thinguiprop=ratelimitsdoes not report. No placeholder, no "calculating…", and the line removes itself when the batch ends or the gate gives up.Rows are untouched: a row still says why it is stuck, and one line says how long. Per-file figures would be invented, since slots are handed out in promise-resolution order and a retry takes a fresh one.
Rounding is the accessibility fix
The line is a
role="status"live region and the DOM write is guarded on the text actually changing. Because it is whole minutes, the string changes at most once a minute. Verified against a live wiki: a 128 second batch produced two distinct strings, so two announcements rather than 128.The count comes from the batch limit, not the queue
batchLimit.active()spans admit-to-terminal.queue.running() + queue.waiting()looks equivalent and is not: a file being retried has left the queue and not yet rejoined it, so the queue undercounts by one per retrying file at exactly the momentonRateLimitedfires and the figure is refreshed.Verified
95 unit tests; PHPCS, PHPStan and PHPUnit green. Checked in a browser at 2 uploads per 40 seconds: no line before the first refusal, "About 2 minutes left" then "Less than a minute left" during, and no line once all seven files had landed.
Considered, omitted