Things I learned making, and places I ate.
Tofu dumpling soup at Pyeongyangjip in Deokcheon-dong: mild and good
A northern-style tofu dumpling place in Deokcheon-dong where a friend and I went for lunch after drinking until dawn. The 10,000 won soup was mild and good.

Turning Apple Pencil handwriting into Sudoku digits
Placing a handwritten digit in DailySudoku: splitting strokes into taps and ink, grouping them, building model input, and applying only trusted results.
Exposing 81 Sudoku cells to VoiceOver and TalkBack
The DailySudoku board is one view on screen, but assistive technology needs 81 cells. How iOS and Android expose each cell, and what is still unverified.
A contract for counting ad impressions the same way on three platforms
A finished load on iOS, an impression callback on Android, a DOM mount on the web: one name, three meanings. A contract that splits the stages of an ad.
Daily puzzle scores: which day they belong to and how they get lost
In a game started at 23:50 and finished at 00:05, the puzzle date, the submission time, and the leaderboard window can disagree. How far to guarantee delivery.
Why a daily puzzle ID needs a generator version
A daily board is made from the date. If the generator changes, one date can give two boards, and a date-only ID cannot tell them apart. Design and proposal.
Ordering ad providers by GeoIP region without the location permission
When ad providers differ by region, an app needs a broad region, not coordinates. Consent first, then a server-side region bucket decides the provider order.
Keeping and revoking a one-time remove-ads purchase on iOS and Android
A remove-ads purchase looks final, but reinstalls, pending payments, and refunds make the purchase result alone unreliable. Read current entitlements instead.
Verifying a verification script with deliberately broken input
A check script that exits with status 0 has not necessarily checked the rule. Break one thing in a copy of a good sample and confirm the expected category.
Who watches the watcher: finding a scheduled job that vanished
A deleted scheduled job leaves no error. Compare the expected roles with what the scheduler really holds, and alert on the time of the last success.
Rust shared core, part 7: splitting tests and CI by layer
Passing Rust tests still leaves iOS linking, Android release ABIs, and Wasm loading in web builds to break. Test the domain in Rust and build fresh in CI.
Rust shared core, part 6: using it on the web as a Wasm package
To use the Rust rules from mobile on the web, compile them to WebAssembly and ship a package. Roles, where to initialize in Next.js, and the call contract.
Rust shared core, part 5: what to check when shipping a .so on Android
Generating Kotlin bindings does not finish Android integration. Per-ABI .so placement, wiring Rust into Gradle, the 16 KB page rule, and release checks.
Rust shared core, part 4: delivering it to iOS as an XCFramework
Passing Rust tests does not mean an iOS app links. Bundle device and simulator static libraries into an XCFramework, ship it as a Swift package, and align CI.
Xcode UI tests and what automationmodetool does and does not cover
When Xcode UI tests stall at an authentication prompt on an unattended Mac, automationmodetool covers one part and TCC permissions another. Here is how to tell.
Rust shared core, part 3: keep UniFFI generated code behind an adapter
UniFFI generates Swift and Kotlin calling code from Rust. What to expose and how far generated types spread is up to the app. An adapter keeps them contained.
DevToolsSecurity on macOS and debugger authorization on unattended CI
Attaching a debugger on a Mac can show a password prompt, and unattended CI stalls on it. What DevToolsSecurity changes, read directly on macOS 27.0.1.
Why Hangul file names fall apart into jamo, and how NFC fixes it
A Hangul file name made on macOS can look decomposed or count as a different name elsewhere. The cause is the Unicode normalization form, checked with code.
Rust shared core, part 2: keep the API across the boundary coarse
Types that suit a Rust engine differ from types that are easy to use from Swift, Kotlin, and TypeScript. Expose coarse action-level functions under a contract.
Rust shared core, part 1: what to share and where to draw the line
Building for iOS, Android, and the web means writing the same rules three times. Narrow what Rust shares to rules that must give the same result, in 3 layers.