Blog
Notes on what I've been figuring out, and what tripped me up.
How Much Does Working Memory Hold, and Can You Train It?
Why the real figure is four rather than seven, what a chunk actually is, and where the evidence for brain training runs out.
Every Page Got the Same Canonical URL: Next.js Metadata Inherits Downward
An alternates block in the layout landed on every page, so the whole site claimed to be a duplicate of the home page. Plus the second trap that hits bilingual trees.
Next.js Static Export on Cloudflare Pages: trailingSlash, _redirects, and What Breaks
What output: export takes away, how trailingSlash quietly breaks your sitemap, and why opengraph-image is unusable here.
What the App Store Needs From Your Website: Support URL and Privacy Policy
The two URLs the submission form won't let you skip, what belongs on a support page, and how an external form changes your policy.
Generating Number Pyramids: Uniqueness, and Difficulty You Can Measure
Why randomly blanked pyramids break, how a rank check guarantees a unique answer, and why row count is the wrong difficulty dial.
Docker Aliases That Stuck, and the Ones I Removed
Trimming ps output, a shell-in function that survives Alpine, and why the cleanup aliases are the ones to be careful with.
Implementing JWT Authentication in ASP.NET Core
From project setup to a working protected endpoint, including the .NET 8 template change and the ClockSkew default that catches people out.
Limiting Concurrent Devices with JWT: One Device Per Licence
Device fingerprinting plus active-token tracking to hold logins to one device — including the race, the signature check, and what caching breaks.
Docker vs Virtual Machines: Why Containers Won, and the Commands to Start With
A VM ships a whole guest OS; a container shares the kernel. What that difference bought, and what run / ps / exec / logs are actually doing.
Running Kubernetes Locally with Kind
With Docker installed you get a disposable cluster in minutes. Up to running Nginx, plus the LoadBalancer gotcha everyone hits.
Why You Get "no matching host key type found": Moving from ssh-rsa to Ed25519
What OpenSSH 8.8 disabled and why, the stopgap flag that just hides it, and moving to Ed25519 and FIDO2 keys.
Django 6.0: Background Tasks Move Into Core
Work that used to mean adding Celery now has an answer in the box. Including whether it is worth migrating.
docker compose watch, profiles and include: Five Features That Changed How I Write Compose Files
Replacing bind mounts with watch, splitting off debug services with profiles, breaking up files with include — and why depends_on doesn't wait.
Ubuntu vs Fedora vs Arch vs NixOS vs AlmaLinux: Choosing by What Each One Optimizes For
Search results, freshness, reproducibility, support window. Five distributions sorted by what each trades away.
Why This Site Uses CSS Modules
How build-time scoping removes naming collisions, and where it stops helping.