Most of the tools in this ad-production suite learned their engineering standards the hard way — a 400-line file cap earned by splitting god files after the fact, deploy verification earned by chasing a stale build for a week, dead-code audits earned by tripping over five PRs of code nothing called. The endcard conversion tool — a small service that turns AppLovin MRAID HTML endcards into MP4 and back — is the first one to start with those lessons already applied, in its very first PR, rather than paying to relearn them.
The cheapest way to fix a class of bug is to never let a new codebase repeat it. That only works if day one remembers what day two hundred learned.
Measuring the endcard instead of guessing at its length
PR #1 is the tool's actual first feature, and it's a good one to lead with because it replaces a guess with a measurement. Converting an endcard to video used to mean typing a duration and hoping it lined up with the page's own animation loop. The new panel offers four real options instead: One play — one cycle of the biggest repeating element, usually the background video, with anything smaller that doesn't divide evenly into it cut where it lands and the UI naming exactly what got cut and where; Seamless loop — the shortest duration at which every animated element is simultaneously back at its starting position, so the loop point is invisible; Until it settles — render until nothing on the page is still moving; or a fixed number of seconds, for when an editor genuinely wants a specific length regardless of what the page is doing.
On the two real endcards used to validate this, the measured lengths were 5.000s and 7.000s — not the flat 10s a typed guess would have produced for either. That's the difference between a video that ends where the page's own motion actually resolves and one that just stops mid-loop because a human picked a round number.
Standards adopted, not rediscovered
The same PR's title says the quiet part out loud: it adopts the sibling repos' engineering standards as part of the initial build, not as a retrofit. That means the file-size discipline earned the hard way on the main video-generation service — the one that eventually needed an explicit 400-line cap enforced at lint time after files had grown past 15,000 lines — shows up here from commit one, when the codebase is still small enough that following it costs nothing.
A changelog script that flagged its own example as real work
PR #2 is a small bug with a genuinely funny cause: the automated changelog-stamping tool, ported from a sibling repo, refused to run on this repo's own changelog — one hour after being ported in. The reason was that CHANGELOG.md's own documentation includes a fenced code example showing what an ## Unreleased heading looks like, and the stamper's parser couldn't tell a worked example living inside a code fence from a real pending section waiting to be stamped. It saw two candidates where there was exactly one. The fix shipped with a new test file that pins down the fence case specifically — watched failing against the old logic first, so the test actually proves something — plus cases for the grouping rules that must not read as accumulation, genuine accumulation, and the empty case. Worth noting: every refusal in this script exits 0 on purpose, so a broken changelog stamper can never fail a merge — which is exactly why a bug in it can sit invisible until someone happens to look.
Closing the gaps flagged at merge time
PR #3 closes three things explicitly flagged as follow-ups when PR #1 merged, rather than left to rot as someday-maybe items. A GET /api/version endpoint reports which commit is actually answering — and, more importantly, where that answer came from, because on this host the deploy platform's variable list carries no git metadata by default, so the Dockerfile also bakes the commit sha in as a build argument and the endpoint reports which source won. unknown is a distinct, honest answer for "a deployment that can't identify itself," which is a different failure than simply reporting the wrong build with false confidence. A GET /api/queue endpoint answers whether a redeploy right now would lose in-flight work — the job table lives in the container's own memory, with nothing durable behind it, so a merge landing mid-conversion silently drops it. And the endcard's call-to-action hook, previously empty, got filled in.
A documentation bug caught by checking the platform, not assuming it
PRs #4 and #5 are a small, honest pair worth reading together. PR #4 discovered — by actually querying the deploy platform's API rather than trusting what the README claimed — that this service had received exactly one deployment ever, covering every merge made since. Merging to main was doing nothing; only a manual deploy command actually shipped anything. The root cause was a permissions gap: the deploy platform's GitHub App had never been granted access to this specific repository under the org, so the auto-deploy connection that every sibling tool takes for granted silently didn't exist here. The doc got corrected to say so, with the exact command and the exact place to grant access.
PR #5, same day, corrects the correction: once the GitHub App was actually granted access, deploys started working again, verified against the platform's own reported commit sha rather than assumed from the README changing. The stopgap ENDCARD_BUILD_SHA variable that had been covering for the missing auto-deploy got deleted once the real mechanism was confirmed live. Two documentation PRs in one day, each one checking a claim against the platform's actual state before writing it down, is a small thing — but it's the same discipline that, applied at scale on the main pipeline, is what turned "the docs said X" from a source of truth into something that has to earn trust every time.
Meanwhile, on the render-batch builder tool
A short update on the sibling tool this one shares engineering lineage with, already covered in an earlier post on fixing its instance-repeat semantics. A finished ad naming two clips instead of one exposed a classification hazard: an automated "migrate misclassified files" job moved anything matching a simple SOP-naming pattern out of the shared source library and into Full Ads — and a short lead clip named SL872 matched that pattern purely by containing the substring L8. Measured against the live library, 15 of 196 visible clips were real short leads that had been silently reclassified and moved out of the library the builders actually read from — a namespace collision doing real data-model damage, caught by checking the actual library contents rather than trusting the classifier's logic in isolation.
Two more fixes rounded out the update: editors were seeing a bare unauthorized error — a string this repo doesn't even produce internally, traced to the shared hub proxy rejecting the session on its fast path — which was also killing in-progress exports outright rather than degrading gracefully, alongside a separately-discovered ffmpeg flag that had been removed and needed restoring. And the product dropdown moved from a hardcoded list to reading export_products live from the shared Supabase project the whole tool family now shares — the render-batch tool is a read-only consumer of a catalog owned and edited once, centrally, so a new product ships to every tool that reads it without a single per-tool PR.
The pattern: cheap lessons the first time, free the second
None of the standards this new tool adopted were invented for it. The file-size cap, the deploy-verification discipline, the habit of checking a platform's actual state before documenting a claim about it — all of them were paid for, expensively, by other tools in this family over the preceding months. The only thing that made them free here was writing them into the very first PR instead of waiting for the codebase to grow large enough to need them the hard way. A lesson that isn't carried forward gets paid for again, in full, by the next tool.