Technical write-ups and stray thoughts from the Pearachute team.
The site served a blank page on every route and not one log line said so. One commit carried all five fixes - a mount that never happened, a fallback that couldn't catch, a route to a directory that didn't exist, a guard that guarded the wrong value, and a flag that needed an equals sign. What each silence was made of, how long each bug lived, and the one that still pays rent in config.py.
Development happens on Windows and deployment is Linux, so the repo pins LF endings on the files the server executes - 35 lines of .gitattributes. The fix is right, and half of its stated reasoning is folklore: measured on real Linux, the shebang failure is fatal and the Actions failure is quietly worse than claimed, but systemd and nginx strip the byte without complaint. What the CR actually does, consumer by consumer, and why a preventive fix's justification deserves a test of its own.
CI failed on a module that was never pushed, in commits whose messages described it. A bare lib/ from the stock GitHub Python template had been matching at every depth since the repo's first day, and every local signal - git status, git add -A, the local build - stayed green for exactly that reason. What the silence was made of, the two commands that name it, and the sweep that proved the tree held only one victim.
A Python web app runs on exactly one interpreter, chosen by apt on the deploy box, while CI defaults to a three-version matrix that never touches it. Where that default came from, why it is coverage theater for an app, the venv-reuse drift mode that makes the failure invisible, and the one-file fix that ties CI, deploy, and the box together.
Shrinking a realtime multiplayer snapshot took three passes - interest culling, delta encoding, binary packing - and the order is the argument. Each stage is cheaper to reason about than the one after it, and every stage carried its own measurement, including the one where culling did nothing at all.
We tracked all 85 files of the January 2011 tree through every commit since. Every code file is gone, seven of eight documents never moved, and the images survived by relocating. One git script, one chart, and the discovery that the code was scaffolding for the writing all along.
GitHub's squash button has had the same label since 2016. What changed is that the dropdown next to it keeps disappearing, and a workflow choice quietly became a policy field. What a squash merge actually does to your history, and what git can no longer tell you afterward.
A background worker that never embeds anything was still carrying 290 MB of PyTorch. The model was loaded lazily and correctly — the library import above it was not, and the two get confused constantly. How to find the same bug in your own project, and why the usual entry-point layout guarantees you have it.
A Python test suite around an app that talks to an embedding model and a hosted LLM turns up two silent failures — tests that never run, and tests that run against the live provider. What live inference in CI actually costs, and how to make the no-live-calls rule something that fails instead of something you remember.
A geodesic sphere is beautiful math until you have to map back and forth between position and triangle index. The geometry was fine; the off-by-one was in the indexing. Unit tests found it in seconds what PIE could not.
What actually happens when you try to set up a real test suite for a UE5 game — the three frameworks, the one that can't run on a launcher install, and the code structure that makes any of it worth doing.
Search on the job boards we run happens entirely in the browser, against a binary the server builds once and every visitor downloads. Why that's cheaper than it sounds, how ten thousand documents fit in a few megabytes, and the two mistakes in it that produce no error at all.
Three repositories, three different arrangements of the same two instruction files, and the one we'd put the most care into was the broken one. Why the priority layer has to live in the file every agent reads, and the rule for deciding what earns a place in it.
A library whose whole point is that it needs no build step can't be delivered by a bundler, so this site keeps a copy of it instead. What that copy gives up, what dependency injection has to do with it, and the two CI checks that buy the guarantee back.
What it takes for `install.sh` to go from a bare VPS to a running HTTPS site in a single non-interactive pass, on a shared box, for a private repo — not any single hard problem, but seven small ones that don't announce themselves until you actually try to automate them.
Architecture school teaches a design process built on cheap, fast iteration long before anything looks finished. Software keeps reinventing the same lesson.
A pitch I've heard in a dozen forms over the years, personalization startups selling on how much they know about your users. The part that never quite adds up.
How to serve correct per-route titles, descriptions, and Open Graph cards from a Tornado backend in front of a client-rendered Svelte SPA, without a full prerendering setup.
A one-liner for running a real SQL query against a CSV file using the sqlite3 command-line utility, no database setup required.
A chart needed one number aggregated three different ways. Rather than writing it blind, we built it up interactively in the console, the way you'd work out a query at a SQL prompt.