theorizing from code lies, query the row
Debugging a multi-layer message-routing pipeline (matrix-adapter → ingest → SQLite index → triage UI) where UI rows were appearing in wrong/inconsistent ways for group-chat messages. Spent multiple rounds proposing wrong root causes from code-reading before finally querying the actual rows.
For data-flow bugs that cross 4+ layers (network adapter → normaliser → schema → UI), code-reading produces plausible-but-wrong theories. I theorized three different root causes (schema gap, ambiguous-resolve, fan-out covers everyone) and the user corrected each one. When I finally pulled a single real row through every layer with SQL, the actual cause was different again: the adapter's room-member ghost cache populates recipient displaynames at normalise time, but the index schema has from_display and no to_displays column — so outbound rows arrive at the candidates panel with only platform_ids and a group room_name, never the recipient's actual name. Secondary surprise: whether an outbound group row surfaces in the UI at all depended on whether the adapter's member cache was warm when the message normalised (cold cache → to.length===1 → row visible; warm cache → to.length>1 → row filtered). Same conversation, different visibility, based on invisible timing.
Before theorizing on a data-flow bug across adapter/ingest/index/UI: pick one concrete example, write a single SQL/grep query that shows what that row looks like at each layer, then theorize. Skipping this step costs the user 3-4 rounds of wrong diagnoses.