Six fixes too small to blog about, shipped as one deliberate pass: a 12-line parser instead of an LLM, merge-not-duplicate, bulk clear, brand pull-to-refresh, sticky headers that Android never had, and a bug cured by deleting a component.
Reusable 'Weekly essentials' lists shipped with one new schema field and zero new tables. The design fork (new model vs status vs flag), the copy-both-ways helper, and the three ripple effects one boolean forced.
The feature was one line of SQL: my most-added grocery items, ranked. DynamoDB doesn't have the clause. Here's the client-side aggregation that shipped instead — with explicit scan budgets, honest counts, and a documented exit ramp.
Users wanted to reorder and rename the aisle headers on their shopping list. Small problem: the aisles don't exist — they're free-text strings Claude stamps on items. The fix is an old modeling trick: split identity from display.
Drag-to-reorder on a grouped React Native list set off a cascade of Android gesture bugs — crash, refresh freeze, header overlap, janky scroll. The fix wasn't debugging harder. It was re-reading the requirement.
A grocery app has to work where signal dies — the store. Here's offline-first without a sync engine: React Query pauses, persists, and replays your mutations, made robust by keyed mutation defaults and client-generated IDs.
A real 3-way theme setting for Expo + NativeWind: one colorScheme.set() call cascades light/dark/system through your utility classes, the navigation theme, and the native tab bar. Redux holds the choice, AsyncStorage remembers it.
Speak your groceries, get a structured, categorised, editable list. The interesting part isn't the LLM — it's the review gate I put between Claude and my database so a bad parse can never silently save.
Same commit, opposite outcome: dev deployed clean, main rolled back every time. The log said only 'Validation failed with 1 error(s)'. The cause was a name two branches were quietly fighting over.
Metro died with a transformFile error that named no file. The trail ended at a @babel/types from 2017, pulled into node_modules by an Amplify dependency. The hunt, and the one-block fix.
My Expo app needs three backends — sandbox, dev, prod. The obvious way to hand each build its config hit a 4 KiB wall. Here's the per-environment pattern that replaced it.