Skip to content
codebiy
CODEBIY / THE WRITING DESK

Notes from
a curious mind.

Bugs we hit, decisions we made and what we learned while building our own products. Each article comes from one product and one real event.

15 articles
01
Product & Design

TikTok Direct Post audit: why public posts failed after app review

TikTok approved our app and every public post still failed with an unaudited_client error. The API has a second approval, the Direct Post audit, and it reviews the screen a person uses, not only the requests.

9 min read
02
Mobile

App Store Connect's salesReports endpoint said “no sales” too early

At 04:24 Pacific, Apple answered “There were no sales” for a day whose report it published within ninety minutes. A tracker that stores the first answer hides that day, so ours waits until the report is due.

10 min read
03
AI

Checking AI agents' front-end work: green build, wrong page

Three front-end bugs on codebiy.com got past lint, types and the build; a browser script caught two, and all three were fixed before release. A fourth was live for about ten days, because its check had not run.

10 min read
04
Games

Puzzle-game bug in Swift: the lock that refused the right code

A flag the player could not see had become a second lock on a puzzle, with a copy in the save validator. A build went to App Review with both. A person playing the game found the bug within minutes. The fix and its tests.

10 min read
05
Web Development

npm ci rejected a valid lockfile in Docker: npm 10 vs npm 12

Three deploys of codebiy.com failed at npm ci on a lockfile that was fine: npm 12 had written it, and the image ran npm 10. The fix is one line. For the eight months before, the image had not read the lockfile at all.

10 min read
06
AI

Twenty OpenAI calls behind one button, and a deadline for each

One tap in Moonhush sets off twenty OpenAI requests. Our first live story was ready in 24 seconds and answered in 57, because one narration call hung. This is what code checks, and how each call got a deadline.

11 min read
07
Games

Balancing a game economy with six bots and Swift assertions

The first balance report for our market-stall game said no bot could pay off the starting debt. The cause was the bots: they bought too little and paid the asking price. Stock ended up dearer.

11 min read
08
AI

What a prompt cannot guarantee: three LLM rules we enforce in code

Field lengths that must pass a save schema, an #ad label that must be on every sponsored caption, and a public demo that must not invent claims. None could be left to a prompt. This is where each one is enforced now.

9 min read
09
Mobile

On iOS, an empty UserDefaults read is not a first launch

Before the first unlock, UserDefaults cannot be read and reports no error. One of our fixes could have taken that for a new install and deleted the user's API key. A review caught it before any phone ran it.

10 min read
10
Web Development

Remotion in the Next.js process: five failures, then a Postgres queue

Rendering inside the web process cost no per-render fee and no extra container. Then a poller, a retry, our own SSRF guard, a crash and a deploy each broke it. The fix was one worker and a Postgres table.

10 min read
11
Product & Design

Selling a Pro license with no accounts and no license server

An Arvlin Pro license is one Ed25519-signed line of text, issued without a database and checked offline. On launch day Polar's webhook deliveries were rejected with 403; the other delivery path does not use the webhook.

7 min read
12
Web Development

AdSense, Consent Mode v2 and a CSP without wildcards on static Next.js

The ad library is in every prerendered page and stores nothing before a decision: a defaults file, pauseAdRequests and a policy listing each origin. A live visit found one frame blocked; the slots serve no ads yet.

11 min read
13
Games

Adaptive music with AVAudioPlayer: three loops on one clock

Every mood change in our hotel game replayed a music loop’s opening hit. Now three loops start on one device clock and a change only moves volumes. Measured in a model; a listening test on a phone is still missing.

10 min read
14
Mobile

An Expo OTA update crashed older builds: a lazy import was not enough

New JavaScript asked older binaries for native modules they did not contain, in two apps three days apart. Once loading is over, Metro reports that failure as fatal and no catch sees it. Probe the binary, then import.

10 min read
15
Web Development

One URL, two languages in Next.js: the half crawlers could not see

codebiy.com kept two languages at one address and chose between them with a cookie, so crawlers only ever got English. Moving the locale into the URL fixed that, and listing every URL turned up four more faults.

10 min read