on wax

KEEPING SCORE

From the stands to the semantic layer.

178 games I was actually in the stands for — joined to the historical record, modeled in dbt on BigQuery, tested, and documented down to the lineage graph. My grandfather kept score by hand. I carried the tradition. This is the same diamond, a generation later, answered with new tools.

dbt BigQuery Retrosheet Semantic Layer Agentforce Snowflake Cortex Baseball

The whole project is live and browsable — models, tests, and the full lineage graph.

Explore the live dbt docs →

#What it is

KEEPING SCORE is a personal data project: every MLB game I've ever attended — 178 of them, going back to childhood — turned into a queryable, tested, documented dataset. My attendance record joined to Retrosheet's historical game logs, modeled in dbt on Google BigQuery, with a semantic layer on top so the questions can be asked in plain language.

It started analog. My grandfather kept score by hand at the ballpark, and I grew up doing the same — pencil, scorecard, the little diamond you fill in when someone reaches base. Those scorecards, his and mine, are the seed. This is what happens when you point modern data tooling at a shoebox full of them.

#How it works

The foundation is five pieces, each doing one job:

The move here: treat a personal archive like production data. Sources, staging, marts, tests, docs — the same discipline a team would use, applied to a shoebox of scorecards. The dataset is sentimental; the engineering is real.

#Same questions, new tools

A scorecard answers questions. Who's up? What did he do last time? How did this game actually go? Fans have asked the same handful of questions for a hundred years.

The tools to answer them keep changing. First the scorecard in your lap. Then the box score in the morning paper. Then the stat sites. Now: a semantic model an agent can query in plain English.

Same questions every baseball fan ever asked. New tools answering them — scorecard, box score, now agentic. This project is the literal proof of that thesis. The same diamond my grandfather filled in by hand, now a tested data model with a lineage graph of its own.

#Now agentic

"Now agentic" isn't the tagline anymore — it's the build log. The same 178 games now answer questions three ways, on three stacks:

Best bugs so far — there are two, and they failed in opposite directions. The first test answer was "9" — a number from nowhere. The session trace showed the agent never called its action; it just guessed. One instruction rewrite later — you have no knowledge of your own, call the action first — it answers 100, from the query, every time.

The second: ask what percentage of games were Yankees games, and it said 0%. Not a hallucination this time — the trace showed the agent doing everything right: action called, result reported faithfully. The bug lived a layer down, in the Apex filter — it demanded an exact match, and "Yankees" isn't "New York Yankees" in the data, so the query returned zero and the agent honestly repeated it. One matching fix later: 143 of 178 — 80.3%, verified at the action layer and again at the agent layer. Two failure modes — an agent guessing without its data, and an honest agent handed bad data logic — two different fixes. That's the whole job now: agents are only as honest as the boundary you build around them, and the trace is how you find out which side broke.

The move here: the semantic layer wasn't the finish line — it was the prerequisite. Answer what the data supports, decline what it doesn't, and let every declined question write the roadmap. My grandfather's scorecard never invented a play. Neither do these.