iOSSwiftUI
#211
2026-06-186 min read

I could have built this twice. ModuleOrderStore is why I didn't.

Making Home and Accounts modules user-rearrangeable could have meant two separate order stores, one per screen. ModuleOrderStore — a @MainActor singleton mirroring an existing PaletteStore pattern — is the reason it's one. The device QA round on AnF confirmed the ordering engine held; six other issues confirmed the QA was necessary.

Read post
Build LogiOS
#212
2026-06-186 min read

One parser for Monzo, Halifax, Revolut and HSBC: how heuristic matching beat four bespoke importers

The on-device LLM for PDF extraction hallucinated on a real Halifax statement. That failure produced a band-based parser that hits 54/54 transactions. The same heuristic approach on the CSV side means one importer, four banks, zero per-bank code paths.

Read post
Build LogiOS
#213
2026-06-185 min read

SoundCloud showed up under my Google Cloud rule on device. That's when part-based matching replaced the algorithm.

Phase Q shipped smart category propagation powered by a fuzzy matcher. Device QA of the Phase R match builder found the structural over-reach immediately: ANY-match on GOOGLE and CLOUD pulled SoundCloud in via 'cloud' and two Google One rows in via 'google'. Phase R v2 added exclude words and per-row select-all to close the gap — because a rule you can read is a rule you can fix.

Read post
Build LogiOS
#214
2026-06-175 min read

An iOS budget app: five rounds of device QA found the same defect every time

Three of the Home screen's gamification blocks were non-interactive labels. The Streak block's Check In button opened the transaction form. Five device-QA sweeps — Phases L through Q — kept finding the same thing: the interface was describing things users expected to control.

Read post
iOSSwift
#215
2026-06-156 min read

Five features, one PR: the two shared-state promotions that had to come first

PR #10 for an iOS budget app bundled a palette picker, a motion layer, a streak milestone overlay, a category-budget quest, and a save-target preference into a single side branch. Getting them to co-exist required promoting BBPalette.current and UserProfileStore before the features could be wired.

Read post