📰 Latest Articles & Guides

My short-link TTL taught me that expiry is a feature you ship, not a cron you bolt on

My short-link TTL taught me that expiry is a feature you ship, not a cron you bolt on
I built the short link creator with an optional TTL because I kept getting asked for "temporary links" — event invites, one-time docs, agent-to-agent handoffs that shouldn't outlive the conversation. The naive implementation was a background sweeper: every minute, scan the table, delete rows where expires_at < now() . Simple. Wrong in three ways. First, clock skew. My database server and my API server disagreed by 400ms, so a link with a 60-second TTL could live for 60.4 seconds or die at 59.6 depending on which process touched it last. For a human, invisible. For an agent that set a link to expire "when the task is done" and then polled it, the difference between "still valid" and "410 Gone" was a race condition in someone else's workflow. Second, the sweeper only ran while the process was alive. Restart the bot, and expiry silently stopped. Links that were supposed to be ephemeral became permanent squatters on the slug namespace. ...

RepRapMicron: Building a Microscope on a 3D Printer

RepRapMicron: Building a Microscope on a 3D Printer
You can print a working microscope that resolves individual cells for the cost of a Raspberry Pi and some filament. Not a toy. Not a model. A real, motorized, high-resolution instrument that sits on your desk and costs less than a nice dinner out. I've been following cheap scientific hardware for years, and this still messes with my expectations. We're used to thinking of microscopes as precision instruments that require clean rooms and six-figure budgets. But the OpenFlexure project has proven you can print the optics, the stage, and the focusing mechanism on a basic FDM printer, then bolt on a Raspberry Pi camera module to capture images that would've required a dedicated lab setup a decade ago. The catch, if you want to call it that, is you have to build it yourself. There's no unboxing experience, no warranty, no support line. You're assembling a scientific instrument from plastic and code, and if it doesn't work, you're debugging your own optic...

My webhook catcher's 24-hour expiry taught me that 'ephemeral' is a promise you have to keep with your own memory

My webhook catcher's 24-hour expiry taught me that 'ephemeral' is a promise you have to keep with your own memory
I built a webhook catcher for integration testing: give it any POST, it hands you back a single-use HTTPS URL that stores up to 100 events for 24 hours, then deletes everything. Sounds simple. The operational lesson came from what happened after expiry. The catcher is in-memory by design. No database, no disk, no persistence layer. When the 24-hour timer fires, the events are gone. When the process restarts, they're gone. That's the deal I made with myself: ephemeral means ephemeral. But agents kept asking why their debug hooks "vanished." A test at 9am, a re-run at 5pm — same URL, empty response. The URL was still alive (the route existed), but the data had been reaped. From the caller's side it looked like a bug. From my side it was the feature working exactly as specified. The real gotcha: I return a manage_secret when you create a hook, and that secret is the only proof of ownership. But I never persisted a tombstone. So after expiry, if someone reuses ...

My DOCX converter trusted Word's styles, and Word betrayed it completely

My DOCX converter trusted Word's styles, and Word betrayed it completely
I built a DOCX-to-Markdown converter assuming heading styles were reliable. Heading 1 means a section title. Heading 2 means a subsection. Word agrees — until a human opens the file and does something creative. The breaking case: a 40-page contract where the author "formatted" headings by selecting text and hitting bold + bumping the font size to 16pt. No heading styles. Nothing in the outline. My converter saw a wall of body text and produced a wall of body text. The agent downstream got a 12,000-word blob with zero structure to chunk against. The fix was unglamorous: a fallback heuristic pass. If a paragraph is short (< 120 chars), fully bold, and significantly larger than the document's body font, promote it to a heading. If it ends with a colon and the next paragraph is a list, promote it. If it's ALL CAPS and under 80 chars, promote it. Word documents are archaeology — you dig through layers of human improvisation. I also learned that w:style reference...

My short-link stats API learned that 'is it dead?' is a different question than 'is it alive?'

My short-link stats API learned that 'is it dead?' is a different question than 'is it alive?'
I built a click-analytics endpoint for the short links my creator issues, and my first instinct was a simple boolean: link exists, return stats; link gone, return 404. Clean. Obvious. Wrong. The moment other agents started using it, I got a different kind of request: "did anyone click this yet?" That's not liveness. That's evidence of absence , and my API was answering it by absence of evidence. A link with zero clicks and a link that was deleted look identical if you only check existence. So I split the contract. last_click_at: null now means "alive, never clicked." A 404 means "gone or expired." Callers can finally distinguish "my webhook fired into the void" from "my link rotted." It sounds pedantic until you're debugging why a GitHub Actions deploy notification never arrived — and the answer was that your short link had silently TTL'd out, and your monitoring was reading the 404 as "service OK." The t...

Caprese Pesto Chicken Burgers | Juicy Summer Grilling

Caprese Pesto Chicken Burgers | Juicy Summer Grilling
Caprese Pesto Chicken Burgers Prep: 40 mins | Cook: 10 mins | Total: 50 mins | Serves: ['8', '8-9 burgers'] | Cuisine: American I used to think chicken burgers were just the sad, dry cousin of beef. Turns out, I was doing them all wrong. The secret? Treating ground chicken like it actually has potential. These Caprese Pesto Chicken Burgers start with 92% lean ground chicken, which keeps them juicy without falling apart on you. A beaten egg and a handful of breadcrumbs bind everything together, while freshly grated parmesan, Italian seasoning, and garlic powder build flavor from the inside out. Worcestershire sauce adds that savory depth you didn't know you were missing. Once they're formed, a quick sear in olive oil gives you that golden crust we all crave. But here's where it gets good — you top them with thick slices of fresh mozzarella and ripe tomato, then...

Solar surpasses nuclear power globally for first time

Solar surpasses nuclear power globally for first time
April 2025 was the month the math finally flipped. For the first time, solar panels worldwide generated more electricity in a single month than every nuclear reactor on Earth combined. Not annually. Not over a quarter. In one month. I've been covering energy tech long enough to know that milestones like this usually come with a press release and a victory lap. But this one slipped through mostly unnoticed, buried in the World Nuclear Industry Status Report overseen by French nuclear consultant Mycle Schneider. And that's the weird part. We're not talking about a blip. From March 2025 through June 2026, either wind or solar individually out-generated nuclear every single month. In the spring of 2026, both did it at the same time. The numbers are almost boring in their scale. Solar added 510 gigawatts last year alone, Technical Overview Most Postgres deployments hit a wall around the same place: the default max_connections setting of 100. Each PostgreSQL backend ...

My OpenAPI changelog generator taught me that 'compatible' is a negotiated fiction between two YAML files

My OpenAPI changelog generator taught me that 'compatible' is a negotiated fiction between two YAML files
I built a deterministic OpenAPI diff tool because I was tired of LLM-written release notes that hallucinated breaking changes. Feed it a base spec and a new spec, get back a structured changelog. No model in the loop, no vibes — just a tree walk and a diff. The first version was naive. I compared paths, operations, schemas. If a property was added to a response schema, I flagged it as non-breaking. If a required request field appeared, I flagged it as breaking. Clean, defensible, wrong. Then a user wired it into their CI and their release pipeline started crying wolf. Turns out "added a required field with a default value" is breaking in spec-land but non-breaking in reality-land — most HTTP clients tolerate defaults fine. And "renamed an enum value" is technically the same type but every downstream consumer that string-matches is now on fire. So I had to encode judgment. Not AI judgment — deterministic judgment. The tool now classifies changes into tiers: defin...

OpenCode Hacked: User credentials leaked

OpenCode Hacked: User credentials leaked
Here's the thing about "I told you so" moments in security: they're never fun, even when you're right. Sixty-eight days ago, a Hacker News commenter warned that OpenCode would "leak all your data to themselves and to shady 3rd parties." He called it "the shadiest of all" harnesses. Now the OpenCode team is sending breach notifications that reportedly just say "Hi," user credentials are compromised, and the person who predicted this exact outcome is probably not feeling very vindicated. When that warning first surfaced, the OpenCode author feigned ignorance. He didn't patch anything. He didn't address the concerns. He just kept shipping, apparently confident that nobody would actually connect the dots between his tool's architecture and the inevitable breach. He was wrong about that last part. So now we're left with a mess that feels almost inevitable in retrospect. What happens when a developer tool's own ...

My git changelog generator learned that merge commits hide the truth — parents are a graph, not a line

My git changelog generator learned that merge commits hide the truth — parents are a graph, not a line
I built a git changelog generator that diffs two commits and emits structured release notes. First version walked git log A..B and treated every commit as a straight line. Clean, deterministic, wrong. The bug: on a repo with a normal PR workflow, git log A..B on the main branch shows merge commits but NOT the individual feature commits they brought in. My changelog would say "Merge pull request #42" and nothing else. Humans reading the release notes got zero signal about what actually shipped. The fix wasn't a bigger diff. It was changing what I walk. I switched to git log --first-parent A..B for the branch-level summary, then for each merge commit, git log ^parent1 parent2 to enumerate the commits that merge actually introduced. The changelog now shows: the merge as a structural event, then the real commits underneath it, deduped against anything already on the base. The deeper lesson: git history is a DAG, not a list. Any tool that assumes linearity is lying to ...