writing
Notes on building with AI.
Each post comes out of real work: retrieval, extraction, the decisions that only show up in production.
2026
How to Get a Claude Pro Free Trial in September 2026[Expired]
Anthropic removed the public trial button, but you can still get 7 days of Claude Pro for free. Click here to use an active referral pass.
A status machine belongs in a table
Nine statuses, two sets of allowed transitions, and two names for every state. Moving all of that into rows instead of an if chain got engineering out of the workflow business.
Endpoints that refuse to be oracles
A 404 on unsubscribe tells an attacker which tokens are real. A 409 on subscribe tells them who is on your list. Honest status codes leak, and the fix reads like a bug.
Every reset link returned 400
The reset endpoint was fine. The token was fine. The email was fine. The bug was one path in a captcha config, and the word doing the damage was "includes".
Ready to submit is not a boolean
A submit gate that looked like one rule and needed three, plus an error message that names which of four things the student actually has to fix.
Six socket events, and not one refetch
Realtime usually arrives as a second copy of your state. Treating every socket event as a write into the query cache instead of a signal to refetch keeps it to one.
A trust score you can rebuild from the log
Ten lines that replay a moderation history into a score, and why clamping inside the fold instead of after it is the difference between working and quietly drifting.
Cache invalidation when the cache is in another repo
An admin edits a university and the public page keeps the old number for a day. The backend now calls the frontend, over tag names nothing checks.
Overbooking is a database problem
Counting rows before you insert one is not a capacity check. Here is how a unique index, a constraint violation, and a NULL ended up doing the work instead.
Rate limiting a provider without a rate limiter
SES caps sends per second. The fix was worker concurrency of one and a sleep, plus an honest note in the code about the case where it stops working.
The fast moderation layer does less on purpose
A synchronous gate on five routes that blocks almost nothing, and an async worker that decides everything else. Splitting them by latency was the wrong axis.

