From 35bdb79aca944a736f174b6c409390582196c5d8 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Thu, 24 Sep 2026 21:22:18 +0000 Subject: [PATCH] Promote a creative to ready when its revision publishes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every streaming break fell through to the house ad. Selection only considers creatives whose status is "ready", and all 185 video creatives were sitting at "generating" with validated, published media behind them. The row is created as "generating" so that nothing serves a creative with no bytes yet, and that is right. What was missing is that publishing the revision IS the moment it gains them, and the status was never moved. So the render pipeline worked end to end — snapshot, encode, validate, upload, publish — and nothing it produced could ever be selected. Done in the same write as published_revision, deliberately. Two statements could leave a creative servable by status with no published revision, or the reverse, and the compare-and-swap that protects the revision protects the status with it. Co-Authored-By: Claude Opus 5 (1M context) --- worker/video.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/worker/video.ts b/worker/video.ts index 8cc5b79..a78596f 100644 --- a/worker/video.ts +++ b/worker/video.ts @@ -41,7 +41,22 @@ async function publishRevision( ): Promise { const { data } = await supabase .from("ad_creatives") - .update({ published_revision: args.revision }) + .update({ + published_revision: args.revision, + // Promoted out of "generating" in the same write. + // + // The row is created as "generating" so nothing serves a creative that + // has no bytes yet, and publishing the revision IS the moment it gains + // them — but the status was never moved, so all 185 video creatives sat + // at "generating" with validated media behind them. Selection only + // considers "ready", so every streaming break fell through to the house + // ad: the whole pipeline worked and nothing could ever be served. + // + // Same write as published_revision deliberately. Two statements could + // leave a creative servable-by-status with no published revision, or the + // reverse, and the compare-and-swap below protects both together. + status: "ready", + }) .eq("id", args.creativeId) .eq("requested_revision", args.revision) .select("id");