mjdc.io Get in touch →

Things I’ve built

Selected projects

Predicting World Cup results, poorly.

Ran live at World Cup 2026

I built a football rating for every men’s international since 1872, then a model that turns the gap between two teams into match odds. It ran live on ballonpoor.com for the last 19 games of the 2026 World Cup. The bookies won the group stage, but the model called three of the five knockout ties where it and the bookies disagreed.

ballonpoor.comRecorded Oct 2026
Here’s the live site after the final whistle. The whole knockout draw, then the score, scorers and stats from a quarter-final.

Ballon p’Oor

World number one in men’s football, 1872 to 2026

I put every men’s international since 1872 through the same Elo engine that ran my World Cup site. Nineteen countries have had a turn at number one, and the 2026 final was #2 knocking off #1 for the top spot.

Since 1883, when a team first had the 20 matches you need to qualify, nineteen different countries have been number one. Brazil has spent the longest on top, 36.8 years all up, then England (27.7), Scotland (15.6) and Argentina (13.0). The 2026 World Cup final was #1 Argentina (2,245) against #2 Spain (2,233). Spain won 1–0 after extra time and is still number one.

How long each country has spent at world number one, March 1883 to October 2026
NationYears at #1Separate spellsLongest spell
Brazil36.859Apr 1995 to Jul 2000
England27.729Apr 1891 to May 1902
Scotland15.612Mar 1883 to Apr 1891
Argentina13.043Jan 1941 to Jul 1943
Italy11.216Oct 1934 to Feb 1940
Hungary8.513Jun 1918 to Apr 1921
Germany (incl. West Germany)8.022Mar 1993 to Jul 1994
Netherlands4.810May 1915 to Oct 1917
USSR / Russia4.616Apr 1963 to Oct 1964
Spain4.111Jun 2012 to Jun 2013
Austria3.25Sep 1931 to Oct 1933
France3.110Jul 2000 to May 2002
Czechoslovakia1.87Sep 1927 to Jun 1928
Uruguay1.12Jun 1924 to Apr 1925
Mexico54 days1Mar to May 1990
Belgium36 days2Sep to Oct 2020
Denmark14 days1Jun 1918
Sweden6 days1Jun 1988
Czech Republic4 days1Jun 2005

Every men’s international from 1872 to October 2026, rated by POOR. To be #1 you need 20 matches, one of them in the last four years. Ratings creep up as more teams join, so compare like with like. Before 1900 it’s mostly the four British teams playing each other.

There’s a lot hiding in a climb time.

Live at poursuivant.cc

Working out how hard the pros climb, in watts per kilo, from the comfort of my couch. Plenty of climbs never get hand-timed, so I piece the time back together from gap reports, kilometre splits and a bit of physics, and show my working. If a climb’s too short or too shallow for the maths to hold up, it doesn’t get published.

poursuivant.ccRecorded Oct 2026
The live site. A stage profile, the estimated watts per kilo (each with its error band), and every recorded ride up Alpe d’Huez.

Poursuivant

Time gaps on Hautacam, Tour de France 2025

In the archived race tickers, 683 of 684 events are stamped zero. So Poursuivant pieces each climb back together from the gaps, the finish times and some physics, then checks its work against times clocked off the TV.

Every ticker event on this climb is stamped 00:00. Rebuilt from the gaps and Pogačar’s kilometre splits, his 35:07 climb comes out at 35:17, ten seconds out. For the nine riders below, the median miss is 27 seconds. Over 47 hand-timed summit-finish times it blows out to 69.

    Hautacam, foot to summit, timed by hand and rebuilt by Poursuivant
    RiderHand-timedRebuiltMiss
    Pogačar35:0735:17+10 s
    Vingegaard37:1737:44+27 s
    Lipowitz37:3037:41+11 s
    Johannessen38:0736:58−69 s
    Onley38:0736:58−69 s
    Vauquelin38:4037:38−62 s
    Evenepoel38:4237:38−64 s
    Gall39:0939:20+11 s
    Roglič39:1539:26+11 s

    Gaps and splits come from public race reports, and the hand times from climbing-records.com. The rest is Poursuivant. Between reports the lines are a smooth guess. Summit gaps assume everyone hit the bottom of the climb together.

    Every cent has to land somewhere.

    In development · private pilot

    Software for small strata buildings in NSW that look after themselves without a strata manager: levies, the books, meetings and records. It splits every levy to the exact cent (harder than it sounds). And when AI reads a document, a number only shows up if the words on the page actually say it.

    • TypeScript
    • PostgreSQL
    • AI extraction
    localhost · fictional demo dataDev build, Oct 2026
    This is a development build running on made-up data. A pretend building’s next 90 days, its levies, then an Agreement Check report.

    Storey

    Splitting a levy between six lots

    Storey splits a strata levy between the lots by unit entitlement, down to the cent. Round each share on its own and the bills don’t add up. Hand the spare cents out fairly and every so often a bigger levy means someone pays less.

    Six made-up lots, with unit entitlements of 15, 15, 17, 17, 18 and 18 out of 100, share a quarterly levy. At $6,000.50, lots 1 to 4 each owe exactly half a cent on top of their whole cents, but there are only two spare cents to go round. Ties go to the lower lot number, so lots 1 and 2 pay $900.08 and lots 3 and 4 pay $1,020.08.

    Put the levy up a cent, to $6,000.51, and lot 2’s bill goes down to $900.07. And if you just rounded each lot, you’d bill $6,000.52 for the $6,000.50 levy.

    A made-up six-lot scheme from Storey’s tests, split by the app’s actual allocation code.Across every levy from $6,000.00 to $6,999.99, rounding each lot gets the total wrong 61% of the time, and a one-cent rise trips the paradox 1% of the time.

    A shop website the shop can maintain.

    Live at vanillacycles.com

    My local bike shop got hacked offline and quoted $20k for a new site, so I built them a Shopify theme instead, mostly over one weekend. They had almost no photos, so the design leans on type, cream bands and one brand blue. Nearly all the copy is editable in Shopify, so the shop can change it without calling me.

    vanillacycles.comRecorded Oct 2026
    The live store. The homepage, X-Lab and the service menu, with the phone version alongside.

    Vanilla Cycles

    How much of each homepage is photos

    Most shop themes are built around big, beautiful photos. The shop didn’t have any, so I built a homepage that holds up without them.

    Shopify’s Horizon demo store

    65.5%photograph

    2.3%type and colour

    A full-bleed hero and eight product photos.

    Vanilla Cycles

    11.1%photograph

    84.7%type and colour

    Three photos, three striped placeholders. The rest is type and colour.

    Both pages are the same width, but Vanilla’s runs 5,075 px to Horizon’s 1,926 px. It’s 2.6× longer and still 85% type and colour.

    Go through Horizon’s demo homepage cell by cell and it’s mostly a full-bleed hero and eight product photos. Take those away and it’s 97.7% blank white. Vanilla’s homepage is cream and sand bands, ink, teal and big type, so when its three photos go, the slots drop back to stripes and the page still holds up.

    What each homepage is made of, share of cells
    Painted asHorizon demoVanilla Cycles
    Photograph65.5%11.1%
    Striped placeholder0%4.2%
    Type2.3%9.9%
    Colour band0%74.8%
    White32.2%0%

    Both live homepages, checked on a 20px grid at 1440px wide in October 2026.The photos here are blocky stand-ins for the real ones.

    Writing

    Occasionally I write up something from a recent side-quest.

    Modelling

    How to build an NRL prediction model with AI

    How to rate NRL teams in points and turn that into win probabilities you can test, with an AI agent writing most of the code.

    Where I’ve worked

    1. Sonder

      AI-enabled care

      Group Product Manager · now

      Where I spend my days, working out what hybrid human and AI care should look like.

    2. Woolworths

      Refresh:Food

      Founding Head of Product

      Built a food marketplace from scratch that did $3M+ for 100+ Australian farmers.

    3. Canva

      Developer ecosystem

      Group Product Manager

      Re-launched the Canva developer platform, which a wave of AI-native businesses now run on.

    4. The New York Times

      Audio and growth

      Product leadership

      Launched NYT Audio, and worked on subscription growth, including an onboarding product that brought 10M+ people to the Times.

    5. Commonwealth Bank

      Everyday banking

      Senior Product Manager

      Everyday banking at Australia’s biggest bank.

    Before all that I started an ad agency with some friends, briefly thought I’d be an academic, and was one of the earliest employees at NEXTDC (in the good old days when normal people barely knew what a data centre was).

    Contact

    Say hello.

    Drop a note below and I’ll get back to you.

    Your message
    All fields are required.