Is this you? As a journalist, you can create a free Muck Rack account to customize your profile, list your contact preferences, and upload a portfolio of your best work.
Claim your profile
Articles by Harrison Guo
API Auth Bugs Are Usually State Bugs
Most API authorization bugs get written up as a missing check. The report says the endpoint forgot to verify ownership, as if there was one absent if statement and adding it closes the hole. That framing is comforting and it is usually wrong. The check was not missing because someone forgot a line. It was missing because the thing it was supposed to check was never modeled.
Use-After-Free Is a Lifetime Bug, Not a C Bug
Use-after-free gets taught as a C problem. The lesson lands as "C lets you touch freed memory, so C is dangerous, so use a safer language." That is true and it is also the wrong lesson, because it hides what the bug actually is and why it keeps showing up in places that are not C. The bug is not the free. The bug is a reference that outlived the thing it pointed to. Two lifetimes that were supposed to match, the object's and the pointer's, and nothing enforced that they did.
Webhook Security Is Distributed Systems Security
A webhook looks like the easiest thing in your system. A provider sends you a POST, you read the JSON, you do the thing. Three lines. It is one of the most dangerous. Not because the parsing is hard, but because a webhook is not really an HTTP request. It is a message from a queue you do not own, with no delivery guarantees, arriving at an address anyone on the internet can find. At-least-once, unordered, retried, and signed by a party outside your trust boundary.
Why Hidden Data Dies in Chat Apps: LSB vs a Robust Watermark, Measured
Every tutorial on hiding a message in a photo teaches the same method: least-significant-bit replacement. Take the payload bits, write them into the low bit of each colour byte, and the image looks identical. It is a genuinely elegant demonstration, and it is the right tool for a file that stays a file. Then somebody sends the photo through WhatsApp, and it stops working. This post measures exactly how badly, and what each step of fixing it costs.
Your Agent Session Is a Tree. Your Code Thinks It Is a List.
Codex made Item a wire type. Pi gave every session entry a parentId. Claude Code compresses the transcript in five progressive stages. Those are three answers to the same question, and it is a question most agent code never asks out loud: what is the durable unit of state here, and what happens to it when you run out of room? You find out which answer you picked at exactly one moment. Not while things are going well. At the moment the context window fills.
Store Load Reordering: x86 vs ARM64, and the Bug Intel Was Hiding
Here is a bug report that keeps recurring, in different words, every time a team moves to ARM: "the same code works on our Intel CI and on the developers' older MacBooks, but it corrupts data / deadlocks / returns impossible values on Graviton." No source change, no compiler change, no new code. The bug was always there. x86 was hiding it.
Same Model, 13.3% to 38.3%
Two API settings. Same model. Same benchmark. Same task set. 13.3% to 38.3%, using one sixth the output tokens. OpenAI published that result about GPT-5.6 Sol on ARC-AGI-3, and it is the cleanest natural experiment the field has produced on a question I have been arguing from first principles for a year. Nothing about the model changed. Everything that changed was around it.
eBPF on Linux — kprobe vs fentry: Hooking Internals & What Production Observability Misses
There are two common ways to attach an eBPF program to a kernel function: kprobe and fentry. Most tutorials treat them as interchangeable — pick one, attach, read your data. They are not interchangeable. They install into the kernel by different mechanisms, they hand you the function's arguments in different forms, and on a hot path they cost different amounts of CPU per call.
Three Agent Harnesses, One Loop
Claude Code's agent loop is 1,729 lines of TypeScript. Codex's is 983 lines of Rust. Pi's is 794 lines of TypeScript. Three teams. Three languages. No shared code, no shared lineage, and in Pi's case an explicit design goal of being the small one. The loop lands in the same place anyway. That convergence is the least interesting thing about these three systems, and almost every comparison I have read stops there. The interesting part is what does not converge.
Agent Architecture Is a Compute Allocation Problem: The Advisor Strategy, Cost-Curve Frame Recursed
In April 2026, Anthropic published a blog post called "The advisor strategy: Give agents an intelligence boost", naming a pattern they had been A/B-testing in production: a cheaper model runs the agent loop end-to-end, an expensive model is consulted only when the cheap one hits a decision it can't solve. They reported concrete numbers — Haiku + Opus advisor on BrowseComp at 41.2% (Haiku alone: 19.7%) at 15% of the cost of running Sonnet through the whole task.
Agent Retrieval Above the Crossover: A First-Principles Read of CodeGraph
The prior post in this series, Agent Retrieval Is a Cost Curve Problem, argued that a viable LLM-symbol-graph would need to satisfy six specific conditions — and that no existing tool had hit all six. The post went live on 2026-05-25; seven days earlier, CodeGraph had hit GitHub trending with exactly those six properties satisfied. That's the easy version of the update: framework predicted it, someone shipped it, here's the existence proof. The companion piece (I Tested CodeGraph on Hono.
I Tested CodeGraph on Hono. The Tool-Call Savings Reproduce — the Cost Savings Don't.
Two weeks ago CodeGraph hit GitHub trending — tree-sitter + SQLite/FTS5 + MCP for Claude Code, 19k+ stars in a week. The team published a benchmark on 7 repos showing 35% cheaper, 57% fewer tokens, 46% faster, 71% fewer tool calls vs. baseline. Those are big numbers. They're also numbers from a benchmark designed by the team that built the tool, on repos they chose.
Docker Kubernetes: What They Really Changed (It's Not What You Think)
"A Docker container is basically a lightweight VM, right?" No. That sentence alone causes more architectural misunderstandings than any other in modern backend engineering. A VM virtualizes hardware. A container is a set of Linux kernel features — namespaces, cgroups, overlay filesystems — wrapped in a nicer CLI. Same host kernel, same memory space, same attack surface if the kernel has a bug. The marketing that says otherwise has cost teams real money in misconfigured production.
The 90% Problem: Why Most AI Agents Are Still Broken
Your Agent Works Great. Until It Doesn't. You built an AI agent over the weekend. It calls tools, remembers context, follows instructions. You demo it to your team. Everyone's impressed. Monday morning, a user types "rename Ember to Infernia." Your agent loops 15 times, burns through your API budget, and returns a response that doesn't contain the word "Infernia." A rename. One entity. One operation. I've been there. I ran an eval suite on a production agent — 5 test cases, 5 runs each. Pass rate: 40%.
Scale-Up vs Scale-Out: Why Every Language Wins Somewhere
I worked with a team that rewrote a critical service from Go to Rust because "performance." Six months later, the service was 30% faster, the team was miserable, and feature velocity had dropped to a crawl. Meanwhile the competitor team, still on Go, had shipped four new features. We did the postmortem eventually. The service handled maybe 2,000 requests per second on a 4-core machine. CPU utilization sat around 20%.
Testing Real-World Go Backends Isn't What Many People Think
I've reviewed enough Go backend test suites to notice a pattern. The services with the most unit tests are often the ones with the most production incidents. Not because unit tests cause incidents — because the teams writing unit tests and calling it a day weren't testing the things that actually broke.
From Locks to Actors: The Four Pillars of Modern Concurrency
Most working engineers have spent ninety percent of their concurrent-programming life in one model: shared memory protected by locks. Threads that all see the same variables. Mutexes around the critical sections. Hope and care. It's the model every OS textbook teaches, every mainstream language supports, and every senior engineer has a horror story about. It's also not the only option. Or even the best one, for many of the problems it gets used for.
Why Go Handles Millions of Connections: User-Space Context Switching, Explained
Somewhere around 40,000 concurrent connections, your Java service falls over. Not from CPU, not from network — from memory, because every connection is a thread and every thread wants its own megabyte of stack. By the time you've finished Googling whether this is a -Xss problem or a ulimit problem, Ops has already bumped the box to 64 GB and you've pushed the wall back another 20,000 connections. Linear in RAM. It never ends.
Claude Code Deep Dive Part 4: Why It Uses Markdown Files Instead of Vector DBs
This is Part 4 of our Claude Code Architecture Deep Dive series. Part 1: 5 Hidden Features | Part 2: The 1,421-Line While Loop | Part 3: Context Engineering — 5-Level Compression Pipeline This article replaces and deepens our earlier analysis, Claude Code's Memory Is Simpler Than You Think. The original focused on limitations.
Claude Code Source Leaked: 5 Hidden Features Found in 510K Lines of Code
What Happened Anthropic shipped Claude Code v2.1.88 to npm with a 60MB source map still attached. That single file contained 1,906 source files and 510,000 lines of fully readable TypeScript. No minification. No obfuscation. Just the raw codebase, sitting in a public registry for anyone to download. Within hours, backup repositories appeared on GitHub. One of them — instructkr/claude-code — racked up 20,000+ stars almost instantly.
Why Your "Fail-Fast" Strategy is Killing Your Distributed System (and How to Fix It)
It's 2 AM. PagerDuty fires. Redis master is down. Your application, trained to fail fast, dutifully fails — every single request, all at once. By the time Sentinel promotes a new master 12 seconds later, you've already generated 40,000 errors and three escalation calls. The system recovered on its own. Your application didn't let it. This is the story of how "good engineering" can make a 12-second infrastructure event into a 12-minute outage — and how to design boundaries that prevent it.
Show More
loading
Actions
Is this you?
As a journalist, you can create a free Muck Rack account to customize your profile, list your contact preferences, and upload a portfolio of your best work.Get in touch with Harrison
Contact Harrison, search articles and posts on X, monitor coverage, and track replies from one place.
Learn more about Muck Rack