Update for the week ending on Friday, Jul 24, 2026
Refactoring English
- Published Why I Stopped “Creating Content”
- Made it to HN front page
- Backported into the ebook improvements to the design doc section I made when I excerpted it for a web version
- Deleted the section on design reviews from the book
- It felt too outside the scope of the book
- It’s still available as a blog post
- Trimmed low-value text from passive voice chapter
- Started editing project for a reader
- Updated book release version to 0.9.9
- Ended early access discount
- Fixed some missing countries / incorrect calculations in PPP pricing
Feedback app
- Add chart-based analytics
- Screenshot
- Excluded the admin user (me) from analytics
- Fix book’s internal chapter list to sort in the same order as the book based on book’s “next chapter” navigation links
- Fixed subtle bugs where chapters have tricky links that look like navigation links but aren’t
- Tried to do bluegreen deployment
- Turns out it can’t work because the SQLite database sits on a volume, and each volume is bound to a single machine, so I can’t have the new machine take ownership of the SQLite database because it’s on another machine’s volume
Scraper bot attack
- Dealt with a scraper bot sending 50k/requests/day to the HN popularity contest
- Fortunately, they’re super easy to spot because they rotate through thousands of IPs but use the exact same rare user agent everywhere
- Unfortunately, Netlify doesn’t allow blocking by user agent without an edge function, so I’d pay for every edge function execution
- I tried throttling in Bunny to 1 KB/s based on user agent, which slowed the attack down but didn’t solve the problem
- I tried faking results in Bunny to trick the attacker into thinking there’s less to scrape, but that didn’t make much difference
- Made a custom script that generates IP blocklists based on bunny access logs
HN Popularity Contest
- Updated processing code to Python 3.14.4
- Added more unit tests
- Updated metadata and excluded a bunch more ineligible domains
- The fewer the supported domains, the less there is for a scraper bot to scrape
- Modified my plausible config to record the domain for single-domain views
- I didn’t realize the Plausible drops URL query params by default for privacy
- Took a lot longer than I expected because it turned out that Plausible changed the JS include but didn’t notify me, so I was using the outdated JS include that didn’t support their documented way to include query params
Little Moments
Little Moments is an open-source web app I’m working on to replace the current family photo sharing app (TinyBeans) I used (which I strongly dislike).
- Simplified the e2e test fixture so that I could actually understand the SQLite database management logic
- And added a clearer comment
- Fixed ESLint config to also lint inline scripts in template files
- Trimmed unused go test scripts and made the flag parsing stricter
- Ported improvements from go-app-starter
- Adjust capitalization in logInAsAdmin e2e test helper
- Reformatted the e2e test part of flake.nix
Weekly Snippets
- Ported git repo from GitHub to Codeberg
- I had to delete a bunch of large images that bloated the repo beyond
- Ported CI from CircleCI to NixCI
keeperfx-zig
- I vibe-coded a Zig build of KeeperFX, the open-source reimplementation of Dungeon Keeper.
- Works under Linux, but so does the real KeeperFX now.
- Was mainly just curious if it would work and what it looks like to do LLM-translation of C modules to Zig.
NixOS config
- Updated my laptop to NixOS 25.11
- Figured out why all my USB devices stopped working
- I at some point added a hardening step to disable auto-loading kernel modules, and I didn’t realize that disabled kernel modules for all my USB devices.
- I made this change a couple of months ago, so I must not use USB devices often.
Misc
- Experimented more with self-hosted git
- Tried self-hosted CI with Gradient but I think it’s too complicated to self-host