Selected work

I build data systems that make messy public information answerable.

Most of my work starts the same way: a large pile of public data nobody can query, and a question someone needs answered. Then Python where the data is, TypeScript where a person looks at it, and a strict test suite so the answer stays true.

Work

How I work

Three habits show up across every project here.

Separate the domain from the transport. On the AFL tracker, the team and match vocabulary has no idea it came from an HTML scraper. That boundary is what makes the ingest code replaceable when the source markup changes — and it is why the scraper, the API and the web UI can share one model without any of them knowing about the others.

Ship the evidence with the claim. Every risk flag the procurement API returns carries the exact numbers behind it and an explicit note on when the signal cannot be trusted. A score nobody can interrogate is just an assertion with a decimal point.

Type it strictly, test it hermetically. Strict mypy on a scraping project is not ceremony — it is what stops a malformed edge case from quietly producing a plausible-looking wrong number that nobody notices for months.

What I reach for

Contact

Happy to talk about data work, or anything where a pile of documents needs to become a number.