Your dev environment passes because it has a property production doesn't
This post exists because of an audit of our own drafts folder. As always here, an AI agent did the digging; the confession below is about our own file.
There's a genre of tutorial that promises a free YouTube transcript tool in ten minutes: spin up a Cloudflare Worker, ask an AI for the code, paste a link, get a transcript. Free forever, no third-party service.
We had one of those drafted ourselves. Finished, polished, ~200 lines of code, and a confident "working code included" in the intro.
Then we went looking for the evidence. No project directory. No deploy log. No captured output. No config file anywhere on the machine that wrote it. The code may well work; it certainly looks right. But we could not prove it had ever run, and "looks right" is precisely the standard this blog exists to reject. Our own rule applied to our own draft: can't-run is not pass. Publishing untested code under a "working code included" banner would be the exact defect our first two posts convicted other people of.
So the code is gone. What survives is the part that doesn't need our code to be true, because it's about YouTube's behaviour, not ours. It also turns out to be a better post than the tutorial was.
The part every ten-minute tutorial skips
The Cloudflare half of the promise is real. Workers and Pages are genuinely free at personal scale and genuinely easy. That's not where the story is.
The story is that a Worker doesn't run from your home internet connection. It runs from a datacenter IP. And YouTube treats datacenter IPs as a different species:
- The bot wall. Datacenter IPs frequently get "Sign in to confirm you're not a bot" where a residential IP gets the video page. The classic symptom: it worked when I tested on my laptop, then returned nothing once deployed. That's not a bug in your code. Your laptop has a property the Worker doesn't.
- The empty 200. Since 2025, YouTube requires a cryptographic proof-of-origin token on many
caption tracks. Without it, the caption endpoint returns an empty
200 OK: a success code wrapped around nothing. If your gauge is the HTTP status, you shipped a tool that "works" and returns silence. - The ground moves. These endpoints change every few months. Whatever you verified in March is a claim about March.
For the record, since it deserves stating plainly rather than in fine print: fetching transcripts this way is against YouTube's Terms of Service. That's one of two reasons this post contains no how-to. The other is that we couldn't verify our own code, and that reason alone was sufficient.
The lie is structural, not a bug
Here's the part that transfers far beyond YouTube.
The tutorial genre's standard advice is: test locally with wrangler dev, see it work, then
deploy. But local dev runs the Worker from your residential IP. Deployed, it runs from a
datacenter IP. So the local test doesn't approximate production. It tests a different subject that
happens to share your code.
Ask the question we ask of every green light: if the deployed version were broken, would this local test look any different? No. It would pass identically. Which means it isn't evidence. It's a demo.
We keep meeting this exact shape in unrelated places. A scheduled job on a Mac fails for weeks while the same command, run by hand in a terminal, passes, because the terminal hands its child a network-privacy grant the scheduler never gets. A Windows scheduled task crashes on characters that print fine interactively, because the console hands its child an encoding the redirected log file doesn't. And a Cloudflare Worker fails in production while dev passes, because your ISP hands your laptop a reputation the datacenter never gets.
Three systems, three mechanisms, one rule: a check is only evidence if it runs in the subject's context. The grant, the encoding, the IP reputation: the property your environment donates to the test is invisible right up until it's the whole difference.
The empty 200 is the same lesson wearing different clothes
In the two-Spark posts we hit a request that returned
HTTP 200 with completely empty content: the model had spent its whole token budget on private
reasoning and none on the answer. The fix was a rule: discriminate on finish_reason, never on
HTTP status — truncation presents as a clean 200.
YouTube's token wall produces the identical artifact from the opposite direction: a 200 OK whose
body is empty because the server declined to fill it. Different system, different cause, same
trap. A success code is a claim about transport, not about content. Any tool whose health
check reads the status and not the payload will report a dead feature as a working one,
indefinitely.
What this cost us, honestly
A finished, publishable, on-voice tutorial, the most polished draft in the folder, reduced to this essay because nobody could produce the deploy log. If that feels like a harsh trade, it's the same trade we wrote about when a benchmark retraction took our best number away: the claims that survive scrutiny are smaller, and they're the only ones worth having.
The rules this one adds to the list
- A local pass is a claim about your environment until proven otherwise. Enumerate what dev donates to the test (IP reputation, grants, encodings, credentials) before reading a pass as evidence.
- A success code is a claim about transport, not content. Empty-but-200 is a failure mode, and it's common enough to deserve its own check.
- A verification is a statement about a moment. Against a moving target, date your claims, and re-verify before you republish them.
- "Working code included" is an evidence claim. If you can't produce the run, you can't make the claim. Including, it turns out, to yourself.
Rules 1–13 are in the two-Spark pair. The numbering continues because it's one list, and because the most useful thing about these rules is how little they care which system you're in when they fire.