The Generate button was refusing every click, and nothing said so
Nobody generated a video here between 5 and 7 September. Two separate faults, neither of which produced an error anywhere. Both are now pinned by tests, and a refused prompt finally leaves a trace, a reason and a deadline.
Nobody generated a video on this site between 2026-09-05 18:15 and 2026-09-07. Two faults, running at the same time, neither of which showed up as an error in any log.
One: the challenge script was blocked, so the button refused every click
The Content Security Policy was narrowed from https: to a host list, and
challenges.cloudflare.com was not on it. The script tag rendered, the browser
refused to run it, window.turnstile stayed undefined, the widget never drew —
and the click handler still refused to run a trial clip without a token.
So every signed-in free account pressed the one button the site had sold them and got "Please complete the verification first" next to an empty space.
Zero generation attempts in the two days it was live — which is exactly the silence a healthy free lane produces on low traffic. That is why it survived. The widget now says so when it cannot draw itself.
Two: an empty prompt box disabled the button instead of answering
Every generator passed !prompt.trim() into the button's disabled, which is
the one state that cannot explain itself. Somebody who had just signed up for a
free clip landed on a panel whose only button was grey and inert —
indistinguishable from a broken page — and the thing it wanted was one sentence
in the box directly above it.
Ten of the first twelve accounts never started a generation at all.
Only an in-flight run takes the button away now. An empty prompt is answered on the click, by name, with the cursor put where the answer goes.
A refused prompt now leaves a record
A content refusal used to record nothing: no task row, no bucket, no timestamp. An account could sit on six strikes and a one-day ban with nothing anywhere saying what it had done.
Three changes:
- A refusal gets a row. It is the only status with no upstream task id, because no provider was called, and it is hidden from My Creations — a card for a clip that was never made helps nobody.
- A strike is charged per distinct prompt per minute, not per request. The refusal path is the fast one, so a button that re-enables on the response could be pressed four times before the toast finished appearing. Production had exactly that: four identical requests inside two seconds, four strikes against a limit of three, from one press as the person experienced it.
- The refusal says when it lifts. The timestamp was being held and thrown away, which is why the old copy said "try again later" and one account re-submitted 34 times in seven minutes.
And the free clip comes back when the scanner is wrong
One account was holding a moderation strike, a lifetime trial counter reading 1, and no task row between the two. Every other refusal on that route already refunds; this one path returned without handing the unit back.
Keeping the increment is right for a rate limit and wrong here, because the only counters held at that point are the lifetime trial keys. Holding those costs an abuser nothing and permanently ends the free tier for anyone the scanner gets wrong, plus everyone behind their IP.
The welcome dialog says a clip that fails never costs it. This is the change that makes that sentence true.