π What Dean saw (demo, v5.8.0, 2026-09-11)
Built spots in the wizard and clicked Approve without a preview. Came back later: the spots looked un-handled, as if the approve had not taken β "I need to approve it again it would seem".
π What actually happened
Approve worked on the server every time: spots 20β31 are state=approved (14:09β14:33Z). What did NOT happen is the render β an approved spot is rendered by AdSpotWorker, and the worker renders one approved spot per tick (ClaimNextApprovedAsync, src/GenWave.Ads/AdSpotWorker.cs:408) on a 10-minute cadence:
14:11:36 Ad spot 18 rendered and is ready to air
14:22:47 Ad spot 19 rendered and is ready to air
Twelve approved spots = a two-hour queue, and nothing on the Approved tab says "waiting for the station to render this". The wizard's Approve as heard path is fast because it promotes the already-rendered preview (ClaimForPromotionAsync) β the slow path is exactly the no-preview approve.
π§ Proposals
- Drain, don't sip: the worker renders every claimable approved spot per tick (loop until
ClaimNextApprovedAsync returns null), keeping the one-generation-per-tick rule for LLM stock as is.
- Say so in the UI: an
approved row (Ads page + the wizard's closing toast) reads "Approved β the station will render it within N minutes", N from Ads:WorkerIntervalMinutes.
- Optional:
POST /api/ads/{id}/approve without a preview enqueues a render job on AdSpotJobService immediately, the way the wizard's preview does, instead of waiting for the tick.
Related: #718 (why there was no bed to pick, so the preview was skipped in the first place).
π What Dean saw (demo, v5.8.0, 2026-09-11)
Built spots in the wizard and clicked Approve without a preview. Came back later: the spots looked un-handled, as if the approve had not taken β "I need to approve it again it would seem".
π What actually happened
Approve worked on the server every time: spots 20β31 are
state=approved(14:09β14:33Z). What did NOT happen is the render β an approved spot is rendered byAdSpotWorker, and the worker renders one approved spot per tick (ClaimNextApprovedAsync,src/GenWave.Ads/AdSpotWorker.cs:408) on a 10-minute cadence:Twelve approved spots = a two-hour queue, and nothing on the Approved tab says "waiting for the station to render this". The wizard's Approve as heard path is fast because it promotes the already-rendered preview (
ClaimForPromotionAsync) β the slow path is exactly the no-preview approve.π§ Proposals
ClaimNextApprovedAsyncreturns null), keeping the one-generation-per-tick rule for LLM stock as is.approvedrow (Ads page + the wizard's closing toast) reads "Approved β the station will render it within N minutes", N fromAds:WorkerIntervalMinutes.POST /api/ads/{id}/approvewithout a preview enqueues arenderjob onAdSpotJobServiceimmediately, the way the wizard's preview does, instead of waiting for the tick.Related: #718 (why there was no bed to pick, so the preview was skipped in the first place).