Now

What I'm up to

Current focus, and short notes on things I learned along the way.
Now · updated 11 Oct 2026
What I'm focused on
  • Settling into a new role as Senior Solutions Architect at Amperity — learning the customer data world from the inside.
  • Building small interactive explainers in the Lab: identity resolution, clean rooms, and why MMM and MTA disagree.
  • Off-season for cricket. Five seasons and 106 wickets in, I'm working on the bit of my game that bats.
  • Writing more: short notes below, longer posts on the blog.
Things I learned
Short notes, mostly from things breaking
CloudflareSEO

Check your CDN's security level before blaming Google

My site wasn't showing up in search, and link previews on LinkedIn were blank. The reason had been sitting in a dashboard for six months: Cloudflare's "I'm Under Attack" mode, switched on during a migration and never switched off. It challenged every non-browser client — crawlers, preview bots, even robots.txt. The audit log showed exactly when it changed. If curl gets a 403 on your homepage, look there first.

AISecurityAWS

On a public LLM endpoint, rate limits are cost controls

My chat agent's API sat outside the CDN with no throttling, no concurrency cap and no input limit. Nobody needed to "hack" it — a script sending long messages in a loop could have run up a real bill. Now it has per-route throttling, a concurrency cap of five, a 1,000-character limit per message, and a daily spend alert. For anything that calls a paid model, think about the worst-case bill, not just the worst-case breach.

CloudflareEngineering

One config line can silently reroute your Worker

To serve one verification file without a redirect, I set Cloudflare's run_worker_first to a list of paths. Testing locally showed the catch: with the list form, any path not on the list stops falling through to the Worker — which would have cut my family portal off from its API. Adding the portal path to the list fixed it. Ten minutes of local testing saved a confusing outage.

AIOps

Models retire — and your app finds out before you do

The AI agent on my home page was failing every request for who knows how long. Nothing in my code had changed: the model it was pinned to had reached end-of-life. Two lessons. Pin models deliberately and put a reminder on the calendar for their retirement dates. And "listed in the console" is not "callable from your account" — the newest model on the list was refused for mine. Always test-invoke before you switch.

AIEngineering

A new model is a new dependency, not a drop-in

Swapping to a newer model fixed the outage and broke the formatting: the new one answered in markdown, and my chat window renders plain text, so visitors would have seen raw asterisks. The prompt and the UI were both quietly tuned to the old model's habits. Treat a model upgrade like any dependency upgrade — run your real examples through it before you ship.

AWSOps

A Lambda broken for nine months by one folder

One of my Lambdas had returned 500 since January. The cause: the deployment zip contained folder/handler.mjs instead of handler.mjs at the root, so the runtime couldn't find the handler. Nothing alerted because nothing called it often. zip -j (junk the paths) fixed it. Moral: an endpoint without traffic is an endpoint without monitoring.