Category

Automation Pipeline

Build logs for video, content, and asset pipelines that turn small scripts into repeatable systems.

All posts

71
Left: a channel-setup script taking country and language as arguments. Right: a hook-data grid with only three apps and two languages filled.
Automation Pipeline3 min read

The Channel Was One Script. The Hooks Were One File Per App Per Language.

One commit added a channel-setup script and hook translation data. The channel side takes country and language as arguments and scales for free. The content side needs a hand-filled entry per app per language before the renderer has anything to overlay. A note on how deep 'multi-language support' actually goes.

#localization#youtube#oauth#shorts
Two-panel diagram: on the left, a native-app branch attaching Korean base hashtags to an English Short; on the right, both the web and native branches reading per-language basetags
Automation Pipeline3 min read

My English Shorts Were Carrying Korean Hashtags

My YouTube uploader already localized hashtags for web-app videos. The native-app branch still attached a single Korean base-tag set to every language. This post covers a fix that had landed in only one of two branches, the 20-line change that closed the gap, and what I still don't know.

#youtube-shorts#hashtags#i18n#localization
Flow diagram of 27 blog posts converted into video scripts one by one, with generation stopping at the end
Automation Pipeline4 min read

My script generator was built to run out at 27

I added a daily job that turns blog posts into video scripts and queues them before publishing. On purpose, its only source is the 27 blog posts I actually wrote, so it stops on its own once they are used up. Where to stop the automation turned out to be the real decision.

#automation#launchd#llm#video-pipeline
Left: a Reel whose cover is a solid-color intro screen. Right: a Reel whose cover is set to an app-screen frame.
Automation Pipeline3 min read

My Reels cover was selling a blank intro, not my app

I auto-crossposted my short videos to Instagram Reels, and the cover came out as the solid-color intro screen. The offset parameters were ignored for Reels, so I switched to extracting the cover image myself, hosting it, and passing its URL.

#instagram#reels#thumbnail#ffmpeg
Left: different apps sharing one hashtag set. Right: separate generated and cached hashtag lists per app.
Automation Pipeline3 min read

My Sleep App and My K-pop Quiz Were Wearing the Same Hashtags

My Instagram crosspost pipeline put the same default hashtags on every app. Nothing errored, because the pipeline only checked that tags were attached, never that they fit the app. This post covers generating tags once per app, caching them, keeping the defaults only as a fallback, and what I still don't know.

#instagram#hashtags#claude-cli#automation
Diagram of four promotion channels where only the Instagram app cards still read the web app manifest
Automation Pipeline6 min read

My Instagram App Cards Were Still Selling Web Apps

Told to promote only store apps, I audited four channels and found just one still pushing web apps. Swapping its content pool wasn't enough. Language, price claims, and tone all came along with it, and a running experiment window had to be reopened.

#instagram#localization#itunes-lookup#automation
A launchd job shown as loaded with zero runs, next to the Day key that makes it monthly
Automation Pipeline3 min read

The job that grounded my posts had never run

The launchd job that refreshes the store-listing file, the only grounding source for my auto-published Threads and Facebook posts, had zero runs since it was loaded. The cause was one plist key: Day=1. No errors, not even a log file, so nobody noticed.

#launchd#macos#scheduling#monitoring
Two-panel diagram: left, a web app Shorts description with App Store copy; right, an uploader that branches by manifest schema
Automation Pipeline3 min read

My web app Shorts were pointing to the App Store

My uploader only understood one manifest schema, so web app videos could still get App Store and iPhone app copy. On top of that, links in Shorts descriptions and comments can't be clicked. This post covers the schema support, profile CTA, and dry-run I added.

#youtube-shorts#upload-automation#metadata#dry-run
A diagram contrasting a pipeline with one Korean queue against one branching into per-language fonts, tokens, and queues
Automation Pipeline4 min read

My Scheduled Job Widens Its Reach the Moment a File Appears

Adding en/ja to a video pipeline taught me that language is not a parameter you add to the queue. Fonts, metadata, tokens, and the scheduler all demanded it, and what I ended up with is a system where a token file on disk, not the code, decides how far I publish.

#automation#i18n#oauth#fonts
Left: auth status knowable only through the upload button. Right: a short script printing the connected channel with no upload.
Automation Pipeline3 min read

The Only Way to Test My Auth Was to Upload a Video

In my brand-channel upload pipeline, the only way to know whether the token was still alive was to publish something. The act of checking was itself an irreversible public act. I split out a 22-line script that re-authenticates and prints the connected channel without uploading anything.

#oauth#automation#data-api#publishing
Left: a vertical video frame with only an app icon. Right: the same frame with a real app screen inside a phone mockup
Automation Pipeline5 min read

My Shorts Were Showing an Icon, Not the App

I built a pipeline that generates promo shorts for my apps. The first version ran cleanly, but what filled the frame was the app icon, not the app. I redesigned it around real screens, and one step still needs a human hand.

#shorts#ffmpeg#edge-tts#youtube
Left: three instruments built in a day with passing tests. Right: what each one actually looked like the next morning — dead on first run, wrong values, zero events, and a green dashboard
Automation Pipeline4 min read

I Shipped Three Meters. By Morning, All Three Were Dead

A follower time series, a follow ledger, one new action. Tests passed, everything committed. Twenty-four hours later: one died on its first run, one was recording wrong values, one had done nothing at all. The dashboard stayed green the whole time.

#monitoring#automation#verification#reality-check
Left: a file fixed and committed two days ago. Right: a resident process booted three days ago still serving the old rules, and the three false readings it produced
Automation Pipeline4 min read

I Fixed It Two Days Ago. My Control Board Hadn't Heard

The dashboard watching 53 bots was serving three-day-old code. The file was fixed and the tests passed. What was wrong wasn't the code but when it got loaded into memory — and three healthy bots were showing red because of it.

#monitoring#automation#reality-check#gotchas
Concept diagram: the error says the session expired while the credential file at the same moment still has eight hours left
Automation Pipeline4 min read

The Token Had Eight Hours Left When It Said 'Session Expired'

Two unattended jobs died on an auth error for three weeks. Re-login didn't survive the same evening. When I finally captured the credential file at the moment of failure, the token was perfectly valid — the culprit wasn't expiry, it was a stale write-back.

#automation#debugging#oauth#verification
Left: building the watch list from a hand-written list plus a naming rule leaves five packages that broke the convention outside the candidate set. Right: a badge nobody touched was correct because it hits the actual store on every render
Automation Pipeline6 min read

My Monitor Was Guessing the App Package Names

25 apps were live on the store; my monitor was watching 22. What the missing five had in common wasn't a bug — it was naming. They broke a convention I invented, so they never made it into the candidate list, and nothing ever said so.

#monitoring#automation-pipeline#reality-check#gotchas
Left: on the same propagation delay the read call is guarded while the write call is bare, so it takes a 409. Right: both forks carry only the read half, so diffing them against each other shows nothing
Automation Pipeline6 min read

I Guarded Against Propagation Delay — On the Read Path Only

In August I fixed the 404 you get when you list a playlist you just created. Four months later the same spot killed a run with a 409. Same cause, different call: the guard was attached to 'the read', not to 'before propagation finishes' — and both forks were carrying the exact same half.

#automation-pipeline#youtube#gotchas#api
Left: insert playlist returns an id, then listing its items immediately returns 404 playlistNotFound. Right: the crash lands before the state file is saved, so next week the bot creates the same playlist again.
Automation Pipeline4 min read

I Queried the Playlist I Had Just Created — It Did Not Exist

Create a YouTube playlist via the API and list its items in the same breath: 404. The real accident comes next — the crash landed before the state save, so the bot was one week away from creating the same playlist again, every week. The fix wasn't a retry. It was not reading at all.

#automation-pipeline#youtube#gotchas#api
Two-panel diagram. Left shows the real ledger state: 922 entries permanently excluded, of which only 8 had a recorded rejection reason and 4 became published long-form videos, leaving roughly 900 burned without any verdict. Right shows the fixed structure: fetch failures and screening-call failures are not written to the ledger and return as candidates next run, while only reasoned rejections are excluded permanently.
Automation Pipeline5 min read

The Ledger Held 922 Topics. I Had Published Four.

A ledger recorded which topics the bot had already covered. It held 922 entries and the bot had shipped four videos. The other 900 had never been judged — most were excluded because a wiki request failed once.

#automation#failure-handling#inventory#honesty
Two-panel diagram. Left: a log line reading ensure_home failed, app reset, retry, read as harmless recovery, printed 240 times across 220 switches. Right: a list where every row carries a small x button, with a pointer tapping eight times, the screen unchanged, and back pressed zero times.
Automation Pipeline7 min read

The 'Reset and Retry' Line Wasn't Recovery — It Was the Cause

A bot driving a physical Android phone failed 8–19% of its account switches for three weeks. I fixed three real defects and the rate didn't move. The actual culprit was a line printed in every log — the bot was tapping a list row's Dismiss button eight times instead of backing out of the screen.

#automation#android#adb#debugging
Left: a hand-typed list of 21 apps inside the monitor with an exit 0 log. Right: the 44 apps actually on the account, 23 of them watched by nobody
Automation Pipeline4 min read

My review monitor was watching 21 of 44 apps

The bot ran on schedule every two hours, exited 0, and reported 'no changes' — all of it true. What was wrong wasn't the verdict but the watch list: 21 hand-typed lines that had stopped halfway through the account.

#monitoring#automation#reality-check#gotchas
Concept diagram: the token column held four different meanings - path, verdict band, card slug, share token - so counting distinct tokens counted content variety. Making token always the visitor id and moving the share token to a src label fixes it.
Automation Pipeline6 min read

My dashboard was counting card names, not people

I was sizing up whether to add a tip button. Pulling the numbers, I found the gate's denominator wasn't people at all. The token column held paths, verdict bands, card slugs and share tokens depending on the app - and the culprit was two question marks that let callers overwrite the visitor id.

#analytics#instrumentation#first-principles#reality-check
Diagram: the same experiment fetched from the list endpoint and the detail endpoint, with startDate null on one and a real timestamp on the other
Automation Pipeline6 min read

The List Endpoint Said "Not Started." It Had Been Running Since Yesterday.

My watcher script reported four experiments as needing a start, tried to start them, and got 409 on all four. The list endpoint always returns startDate as null — and the platform starts these experiments automatically anyway. Three different errors were telling me the same fact, and I never tried the third one.

#automation#api#app-store-connect#data-quality
One of 28 analytics instances carries a backfill starting 21 April, so a column labelled 28 days actually summed 118. Without cutting on the row's own Date the app shows 50,141 impressions at 1.7% page-view rate; with the cut, 1,036 at 7.3%
Automation Pipeline9 min read

The Column Said 28 Days. It Was Summing 118.

Two weeks ago I wrote that my numbers were inflated 3x but the ratios had survived. For most apps that was true. For one app the impression count was off by 48x — and I was picking A/B test candidates on top of it.

#app-store#analytics#data-quality#reality-check
Diagram: what the 7,531 landing events actually were, and the difference between counting loads and counting stored tokens
Automation Pipeline9 min read

The Visitors That Passed My Gate Were My Own Screenshots

Two weeks ago I wrote a post bragging about a headless Chrome pipeline that captures app screens automatically. That pipeline had been crediting itself as a visitor every evening. Here is how I caught it in a table that stores no user-agent and no IP, and why I changed what I count instead of writing better filters.

#analytics#data-quality#reality-check#gotchas
Concept diagram: one signup branching into 20 app schemas each getting +1, with per-app new-user counts all reading 264 below.
Automation Pipeline5 min read

Every app had exactly 264 new users

Twenty-odd apps share one Supabase project. I counted new signups per app and every app returned 264. An auth trigger was fanning a single signup out into every app schema — and I had already made decisions on that denominator.

#supabase#analytics#postgres#reality-check
Concept diagram: on the left the shipped read-back check with synthetic tests passing 3/3, on the right the live drill revealing read-after-write lag and a false alarm
Automation Pipeline5 min read

I Added Verification, and the Verification Lied

I shipped write-then-read-back checks across six bots and the synthetic tests passed. Not trusting that, I ran a real write against a live channel — and the read right after the write returned the old value. My checker was ready to report healthy writes as failures.

#gotchas#verification#automation#alerting
Concept diagram: processingDate instances re-load the prior 3 days, so summing triples the counts. Ratios stay correct (both numerator and denominator ×3), only absolute values inflate, and accurate-source ÷ 3×-source makes a plausible false metric.
Automation Pipeline6 min read

I judged two months on numbers inflated 3×

I'd been pulling app funnels from ASC analytics for months. Cross-checking revenue for the first time, payment counts were off by 6×. The cause was a report that restates the prior three days on every run, and I was summing all of it. The ratios were fine — but one metric that mixed two sources was rotten.

#app-store#analytics#first-principles#reality-check
Concept diagram: left shows a false alert with a [shorts] prefix accumulating one per day in the log; right shows the real outage happened only once
Automation Pipeline6 min read

My error monitor kept reporting an outage that had ended three days earlier

I traced a 'same-time-every-day 500 error' alert. The real outage happened exactly once. The rest was the monitor writing its own alerts into the log it scans, then re-scanning them. The same day, a dashboard also contradicted itself: 4/4 but 'waiting'. A field guide to the two ways observability lies to you.

#monitoring#observability#feedback-loop#reality-check
Concept diagram: at the verify stage of a deploy pipeline stands a Cloudflare shield. curl gets a 200 but a 5.4KB challenge page and bounces off; only SSH md5 comparison bypasses the shield to reach the server disk.
Automation Pipeline4 min read

What got deployed was a different app

Four policy/support pages for one app were another app's stub for four days. Nobody could tell. The domain sits behind Cloudflare, which serves a challenge page with a 200 to non-browser requests — so curl couldn't verify a deploy. The only authoritative check was comparing file hashes over SSH.

#deployment#cloudflare#shipping-infra#gotchas
Concept diagram: with no sample gate, tiny-sample scores mistake luck for skill
Automation Pipeline2 min read

My self-improving loop was learning noise

A loop that feeds view performance back into app order, category weights, and retention curves was counting scores from tiny, two-digit-view samples. One minimum-sample gate cut off the noise overfitting.

#automation#feedback-loop#statistics#overfitting
Concept diagram: ffmpeg gotchas
Automation Pipeline3 min read

ffmpeg gotchas that cost me hours

Four ffmpeg and toolchain traps from building a video pipeline: overlay has no alpha, drawtext breaks on non-ASCII font paths, a silently broken system binary, and why a static ffmpeg wins on a recent Python.

#ffmpeg#python#video#debugging