Writing
Postmortems and longer-form notes.
- Design · Data freshness 2026-07-23
Price alerts without a holiday calendar: two gates instead of an almanac
How a family bot watches stock prices with zero idle cost and no false alarms on holidays — a market-hours gate for cost, a freshness gate for correctness, and a boundary decision that got reversed in one day.
- Side Project · Type Safety 2026-07-22
tsc kept saying 0 errors — because it had stopped checking anything
@types/react quietly went missing from node_modules on a side project. tsc --noEmit kept running, kept exiting 0 — it just wasn't checking anything React-shaped anymore, and nothing about a green CI run said so.
- Side Project · Build vs Buy 2026-07-22
We skipped the stroke-order library — then needed three tries to get 'close enough' right
Zhuyin symbols only have 1-4 strokes, simple enough to hand-roll stroke tracing instead of adopting a library built for full Chinese characters. The build-vs-buy call was easy. Scoring how close a 4-year-old's finger has to get to 'correct' took three rounds — and the first two were both wrong in opposite directions.
- Side Project · Frontend 2026-07-22
Fine in Chrome, broken in Safari: two bugs a kids' app only caught by checking twice
A Zhuyin-teaching app for my kid rendered perfectly in Chrome — twice. One bug only surfaced in Safari, the other only in an actual print preview. Both times the fix was checking a different lens, not staring harder at the same one.
- Side Project · Game Design 2026-07-22
When the 'wrong' answer was actually the right sound
A child heard the sound ㄅㄟˋ at the start of a completely different symbol's example word, picked ㄅ — and the matching game told them no. The fix wasn't really a bug fix; it was making a product principle enforceable: never punish correct listening.
- Side Project · CSS 2026-07-22
The same CSS bug shipped three times because fixing it once didn't fix the ratio
A pill nested inside another pill needs real clearance between the two curves, or the inner shape visibly pokes into the outer border. Fixed once, fixed again elsewhere, then shipped a third time — inside new size variants of the very component already fixed.
- Side Project · Randomness & Data Integrity 2026-07-22
The bug that only showed up on 1 in 4 page loads
Two Zhuyin symbols quietly shared the same example word. On roughly a quarter of page loads, a quiz question showed two choice cards with the identical emoji and word — a coincidence that only became visible once someone did the math on why.
- LLM · Design 2026-07-20
Same write path, opposite read models: long-term memory vs reminders
An LLM doesn't learn you — 'it gets smarter the more you use it' has to be engineered. Two features that write identically and read in opposite directions, and why the bot has no recall tool.
- LLM · API design 2026-07-17
One file per tool: the registry that turned a chatbot into a family utility
The function-calling contract behind 14 tools — errors as data, context threading, and two opt-in presentation protocols with one sharp gotcha about buttons that don't wake the bot.
- LLM · Production hygiene 2026-07-14
Three layers of scrubbing between a reasoning model and a family group chat
Reasoning models leak <think> blocks, MiniMax occasionally spits raw tool-call markup into the reply, and LINE renders exactly zero Markdown. One pipeline catches all three.
- Self-hosting · Platform quirks 2026-07-11
Five LINE Messaging API gotchas the docs won't warn you about
Mention offsets in UTF-16 code units, an @ menu that vanishes on desktop, zero history APIs, one-shot reply tokens — and how each one bent the bot's architecture.
- Self-hosting · LLM 2026-07-08
A family AI assistant that lives in a LINE group
Why I built a self-hosted LINE bot for my family instead of pointing everyone at a chatbot app — architecture, the four design decisions, and where the boundaries are.
- Machine Learning · Real Estate 2026-06-25
The information ceiling: why an AVM built on public sales data tops out at 12% MdAPE
I built a house-price model on Taiwan's public transaction records and hit ~12% MdAPE on 107k live records. Then I proved it can't get more accurate — the residual is something this data simply doesn't contain. Knowing when to stop beats squeezing one more point.
- Postmortem · Data Engineering 2026-06-23
The fake zero: when a missing value must be NULL, not 0
An Instagram analytics chart flatlined to zero while the follower count kept climbing. The bug wasn't missing data — it was a fake 0 written where NULL belonged.
- Migration · Astro 2026-06-23
The build that dropped a random post: moving my blog to MDX
Migrating five bilingual posts from per-page Astro to MDX content collections. Two bugs only showed up after the move — a reserved field name, and a Markdown rule that won't bold Chinese.
- Cost discipline · LLM 2026-06-18
Running an LLM in BigQuery without the bill scaling with users
Two features in my pipeline call Gemini through BigQuery AI.GENERATE — a batch classifier and an on-demand dashboard button. One of them quietly scales with headcount. Here's how I capped both.
- Migration · Cost discipline 2026-06-10
Replacing a $7.88/mo n8n on Zeabur with a 178-line Python script on OpenClaw
Migrating a family-schedule alert off hosted n8n into a local OpenClaw cron job — and the latent bug I noticed along the way.
- Postmortem · Open Source 2026-05-28
How to write an issue so good someone else sends the PR
A silent 500-character truncation in OpenClaw's reply-context handler. I filed the issue; someone else opened the PR.
- Postmortem · Open Source 2026-05-22
Fixing a deadlock that kept OpenClaw Gateway from restarting after upgrade
An ESM dynamic import, a signal handler, and a race condition — the gateway broke silently for six days.