Musings
Notes, essays, and algorithms.
War stories from shipping iOS, the algorithms I teach, how AI models actually work, and the occasional note on how I learn. Filter by what you're here for.
I didn't learn LangGraph. I interrogated it.
What a graph-execution framework looks like rebuilt from a Swift systems bias — typed state overlays, edges as projection layers, and context selection as a retrieval problem solved on the edge. A 6/10 design, published honestly.
7 min
The golden age of engineering
LLMs are the first abstraction layer that's non-deterministic — and the cure is the exact discipline senior engineers already carry. An argument I derived myself, with its bias named and its weak flanks left open.
11 min
I built my own Socratic tutor instead of taking a course
The learning science behind it, why courses and even a raw chatbot get it wrong, and a theory of using AI to learn — built on a system that derives my mastery from evidence I can't fudge.
17 min
Why the same prompt at temp=0 still returns two different answers
Greedy decoding isn't determinism. A short tour of where the randomness actually hides.
4 min
I kept solving everything with dynamic programming
A confession, and the one question that fixed it — do the choices interact? The spine for a series on reaching for the lighter pattern instead of reflexively reaching for DP.
4 min
Greedy is easy to code and hard to justify
The local choice is only safe if you can prove it. The choices-interact test, the exchange argument, and deriving the Gas Station proof from scratch instead of memorizing the rule.
8 min
Sliding window: the prerequisite nobody mentions
A window is only legal when the quantity you track is monotonic. The need-counter as elegant state, and the record-placement bug that silently decides minimum vs maximum.
10 min
A/B testing from first principles (the 95% tutorials skip)
Deterministic bucketing, sticky assignment, exposure vs conversion, and the statistics that decide whether you actually learned anything — the part the tutorials never reach.
12 min
Binary search has nothing to do with sorted arrays
It searches a monotonic answer space, not an array. Why min/max isn't always DP, and the isValid + monotonic-boundary checklist that tells you when to bisect a range.
7 min
Prefix sum: turning a range query into a lookup
O(n) range queries become O(1) differences. Why map[0] = 1 seeds the empty prefix, the sum−k trick, and the frequency-vs-first-index fork — the tool I kept mis-reaching for.
8 min
Two pointers is a family, not a technique
Converging vs read-write — they share nothing but two indices. Why all sliding windows are two-pointer but not the reverse, and the Trapping Rain Water insight that only needs which side is shorter.
7 min
How one SDK blew our launch budget — and how we got it back
An analytics SDK quietly multiplied our pre-main time. Splitting dylib cost from initializer cost with DYLD_PRINT_STATISTICS, deferring init past first-interactive, and a CI gate so it can't regress again.
9 min
Dynamic programming is recursion with a cache
Defining the state is the whole game; the recurrence falls out. Top-down by default, the Int.max sentinel bug, and why bottom-up is a space optimization, not the honest form.
10 min
The monotonic stack is a waiting room
Unresolved elements waiting for the thing that answers them; amortized O(n) because each is pushed once and popped once. And why the leftovers aren't a bug — they're the answer.
10 min
Carry history or start fresh: Kadane in one decision
Maximum subarray as a single per-step choice — and why sliding window can't do it: the same symptom needs the opposite fix, so there's no consistent shrink rule.
5 min
Killing a scripted promo-abuse attack with App Attest
Someone disassembled our IPA, rebuilt the API in Python, and farmed promos at scale. Per-request App Attest assertions, a DeviceCheck flag that survives reinstall, and leading-indicator scoring broke the economics.
9 min
A heap is an array pretending to be a tree
Parent/child is pure index arithmetic; two repair operations derive everything else. When a heap beats sorting, and two bugs that looked helpful while quietly breaking the invariant.
9 min
Routing as architecture: resolution is data, navigation is a side effect
A first-principles build-up of an iOS deep-link and navigation layer — why the routing engine and the coordinator are two orthogonal layers, what each one actually buys, and the lifecycle leaks nobody warns you about.
32 min
One UI, two platforms: a shared Rust core for server-driven UI
iOS and Android were re-implementing the same parse-and-validate logic and drifting. A UniFFI Rust core makes the rule set single-source, ships flows without app releases, and old clients degrade instead of crashing.
13 min
Make a malformed deep link impossible to crash on
Three hand-rolled entry points, inconsistent auth, crashes on attacker URLs. Separating resolution from execution — the engine returns a decision as data, never navigates — collapsed three bug classes into one testable gate.
8 min