What a Coding Agent Taught Me About A/B Test Telemetry A developer used a coding agent to build three A/B/C test variants of a price-tag scanning screen in an Android app for store staff, then documented the telemetry work behind the experiment. The agent reframed the analytics design around a single "scan session" entity delivered via two events (session_start and session_finish), and proposed a prepared BigQuery table, scanner_ab.sessions, that turns raw Firebase exports into one row per scan session. The developer notes the agent also worked around a sandbox network policy blocking the BigQuery API by routing through Cloud Shell. We had three designs for a new price-tag scanning screen in an Android app used by store staff. Claude Design produced the mockups, I showed them to colleagues and ran a vote. There was no clear winner. So I suggested the obvious thing: if we can't decide, let the users decide. A routine Android task turned into an A/B/C test. A coding agent wrote the new screen and all three layouts. That turned out to be the easy part, because I had never run an A/B test. I knew the idea from articles and videos: split users into groups, show different variants, collect metrics, compare. Between that description and a real experiment in production there were a lot of questions I couldn't answer: Instead of reading another round of abstract examples, I went through the whole thing on the real task, with the agent. This post is about the parts you can reuse: the event model, the data layer, the traps in the Firebase to BigQuery export, and the one mistake no amount of SQL fixes. My first idea was simple: the more behavior you want to analyze, the more events you send. I started instrumenting a separate event for everything: opening the scanner, a successful scan, an error, a "move closer" hint, various user actions. The agent proposed a different model. For the experiment it mostly needed two events: barcode scan scanner session start barcode scan scanner session finish The difference was in what each event carried. session start session id, variant A/B/C , store, device, launch source, ... session finish session id, result, code type, scan duration, "too far" hints, mismatches during double confirmation, focus / zoom / torch usage, decoded on first try, ... This was the most useful thing I learned in the whole project, before a single number came in. I would not have designed it this way myself. I had thought of analytics as a list of events: something happens, you send an event. The agent effectively designed an entity, a scan session , and the two events were just how the start and the outcome of that session got delivered. From then on, questions could be asked about a whole scan attempt instead of about individual clicks. Sending events to Firebase Analytics is easy. Analyzing this experiment in the Firebase console quickly isn't: event params ; session id ; I had never worked with the Firebase Analytics export to BigQuery. The agent explained why the analysis needed it and then walked me through the setup: where to go, what to enable, what to click. The learning order was reversed. Normally it's documentation, then an example, then test data, then finally a real project. Here the real task, the real events and the real users came first, and I learned exactly as much BigQuery as the agent needed to keep going. Once the export worked, the next problem appeared. Raw Firebase events are an awkward interface even for an agent. To answer "how many successful sessions did variant B have?" you have to unpack event params , find each start, find its finish, join them on session id , handle missing finishes, and only then compute the metric. Doing that in every query means repeating a large block of SQL over and over. The agent proposed a separate dataset, scanner ab , with a prepared table scanner ab.sessions in which one row is one scan session : Android app ↓ Firebase Analytics ↓ BigQuery events raw export ↓ scanner ab.sessions one row = one scan session ↓ analysis queries This is where I understood why analytics people build prepared layers at all. Raw events stay raw. The prepared layer turns them into the business entity you actually ask questions about. This is how the pipeline actually works, including the details I would not have known to look for. Reaching BigQuery from a sandboxed agent. The agent runs in a sandbox whose network policy blocks the BigQuery API. Instead of fighting that, it goes through Cloud Shell: gcloud cloud-shell ssh --authorize-session --quiet \ --command="bq query --use legacy sql=false '