render qc · canary run

Director Title Cards

Per-phase gpt-image-2 title cards composited via Remotion, tested against 4 real, already-rendered Gymshark product ads spanning Reels, Stories, Feed and PMax landscape. Flag ADGEN_DIRECTOR_TITLE_CARDS stays off pending the fixes below.

2 defects · not ready to ship
$0.39
real spend
4
ads tested
9
cards generated
4
formats covered

Takes

4 ads · real veo masters, read-only fetch
6a9c65e6…50c8
reels9:16
Running High Neck Long Sleeve Top · Gymshark
hook frame0:01.9hook
proof frame0:05.2proof
close frame0:07.2close
bug

All 3 timestamps render the hook card. The proof/close cards were generated and billed but never appear — at 7.2s the close frame still reads “The top for your run and your coffee run” instead of the product name + benefits, and it now sits directly over the shark logo.

6a9c65e8…50f5
stories9:16
Running High Neck Long Sleeve Top · Gymshark
hook frame0:01.2hook
close frame0:05.7close
bug

Same sequencing defect as Reels — the close-phase timestamp still shows the hook headline. Confirms this isn’t a Reels-specific quirk; it reproduces on every 3-phase vertical format tested.

6a9c65ea…5113
square1:1
Running High Neck Long Sleeve Top · Gymshark
only framesingle cardmain
pass

Single-phase format has nothing to sequence. Clean two-weight typesetting, correctly inset to the square safe zone, no collision with the logo mark. This is the case the feature already gets right.

6a9c65e5…50b2
landscapeYt16:9
Running High Neck Long Sleeve Top · Gymshark
phase 1 frame0:00.8phase 1
phase 2 frame0:08.3phase 2
bug

Cards do switch here — but phase 1 renders as a dithered, washed-out ghost instead of crisp text (an alpha-compositing artifact), and phase 2’s benefits copy overflows past the bottom of frame while still double-exposed against phase 1’s residue.

Findings

3 issues · ranked by severity
high

Multi-card sequencing never advances past the hook card

On both 3-phase vertical ads (Reels, Stories), proof/close cards are generated and billed via a real gpt-image-2 call, then never displayed — the composite holds the hook card’s image for the full render regardless of the sampled timestamp. Paid content silently never reaches the viewer on the two most common ad formats. The 2-phase landscape case does advance, so the defect is specific to how 3+ sequential phases wire into the composite, not the fade/timing envelope itself.

repro: ad 6a9c65e6…50c8 & 6a9c65e8…50f5, timestamps 5.2s / 7.2s & 5.7s
high

Alpha-ghosting and bottom-frame overflow on multi-card landscape

First card composites as a dithered, checkerboard-alpha ghost instead of opaque text. Second card’s benefits copy runs past the bottom edge of frame and shows a visible double-exposure against the first card’s fade-out.

repro: ad 6a9c65e5…50b2, frames at 0.8s & 8.3s
medium

Title text can collide with the brand’s own logo

A tight crop on the Reels close-phase frame shows generated title copy sitting directly over the stitched Gymshark logo. The card is generated blind to the actual video frame, so this class of collision is a structural risk of the approach rather than a one-off render.

repro: ad 6a9c65e6…50c8, frame at 7.2s
shipped

Burned-in safe zones — already fixed, unrelated to this canary

Reels/Stories safe zones were split from one collapsed vertical entry, the keep-out band gap is closed, and safeZoneKey now flows through the CJS plate-scan path in production (adgen #59 / backend #335). The one loose end is a stale line in session.d/KNOWN-OPEN.md still describing it as open — code disagrees with the doc, not the other way around.

Spend ledger

stage: director_title_card · CostLog
AdFormatCardsSpendResult
6a9c65e6…50c8Reels 9:163$0.1806sequencing bug
6a9c65e8…50f5Stories 9:163$0.1304sequencing bug
6a9c65ea…5113Feed 1:11$0.0100pass
6a9c65e5…50b2PMax 16:92$0.0702composite artifact
Total$0.3912
Method: a standalone canary (scripts/renderDirectorTitleCardsPreview.js) drives the real directorTitleCardService + directorTitleCardGenerate + Remotion TitleCardSlot stack against each ad’s existing untitled master (veoVideoUrl), read-only against the production database — Ad-collection writes are blocked at both the driver and model level, and adId is omitted from every generate call so no spend receipt lands on the ad. Videos and stills here are re-encoded for file size; visual defects reproduce at source resolution.