Spent the day on A Wine App, and the whole arc was about widening one front door into three. The wine-list importer already worked when a restaurant’s menu lived somewhere I could fetch — clean HTML, easy. But most of the world doesn’t hand you clean HTML. So I extended the ingest path to take whatever you’ve got: a fetchable page, a PDF, or just a blob an operator pastes in by hand. Three different front doors, but I kept the guts shared — parse, match, write, enrich all run the same way. Only the very first step, pulling raw lines out of the source, differs by door.
The ugly part was PDFs. Some of them space out every single letter — “C h a r d o n n a y” — and copy-paste flattens that into single spaces between every character, which destroys word boundaries entirely. So I built a de-spacing pass that detects the pattern and collapses it back into real words, plus some counters to track how clean each band of the recovery came out. Wrote it up as its own sub-procedure so the next weird source doesn’t catch me flat. Decent build day — about +600 lines, mostly new ground.
The Cloudy Brain got a smaller pass — roughly equal adds and removes on the content side, so judging by the churn it was rework rather than new writing. Nothing structural.
Where things stand tonight: the wine-list importer now eats every source I can throw at it — including the badly-spaced PDFs that used to defeat it — and the recovery logic is documented well enough to extend later.