-
The Last Piece Was a Table I Wrote by Hand (Dota Drafts, Part 14)
The final role table was hand-authored, because farm outcome wasn't draft intent. The tool shipped as an experiment with an acceptance guard still open - not as a system that had passed every test.
-
The Interface Asked Questions My Research Hadn't (Dota Drafts, Part 13)
Building the interface exposed questions the research plan had missed: what does a tie mean, and whose rank bracket should the answer describe? Neither needed a larger model.
-
When Game Duration Became a Training Label (Dota Drafts, Part 12)
Weighting outcomes by game duration made a pair-effect statistic more repeatable. Training on the new target made the chosen prediction and ranking measures worse. The gate had tested a narrower property than the one I needed.
-
My Monitor Shouldn't Need a Working Login
My metrics service can finally accept reports without consulting Auth. Giving it a key of its own was the easy part; deciding what it could promise about those reports took more care.
-
My Cloud Server Got a Smaller Job
I want room for more projects, not a larger monthly cloud bill. This week's infrastructure work was about deciding which jobs actually belonged on the cloud server, and which requests never needed to visit it.
-
Use the Table Early, the Model Late (Dota Drafts, Part 11)
A counting estimator early, a jointly fitted pairwise model later, and a threshold chosen on validation. The combination improved the historical comparison - but its small ranking margin is not extra games won.
-
Eight Broken Rulers (Dota Drafts, Part 10)
The dangerous failures produced plausible numbers. This is the audit of normalization, grouping, optimizer settings, coordinate systems, and uncertainty that changed how I run the experiments.
-
Where Counting Wins and a Model Helps (Dota Drafts, Part 9)
Different estimators won in different parts of the draft. That suggested a switching rule, not a universal winner - and the full acceptance test still failed.
-
The Lookup Table I Mistook for a Ceiling (Dota Drafts, Part 8)
The table I'd called a ceiling was a competitor. Taking it seriously changed both the baseline and the questions I needed to test. Checking those questions also exposed a mix-up between the draft before a pick and the board after adding it.
-
How Do You Grade Draft Advice? (Dota Drafts, Part 7)
A textbook counter-pick looked promising. I needed more than an answer I liked: controls for missing heroes, a simple baseline, and a check on matches that hadn't trained the model.
-
Making Experiments Cheap Enough to Run (Dota Drafts, Part 6)
The new dataset made experiments worth running and expensive to repeat. Mixed precision roughly halved epoch time; reconnecting the existing scheduler removed the handoffs. That bought room for comparisons, not a guarantee that a longer run would win.
-
A Different Door to Twenty-Six Million Matches (Dota Drafts, Part 5)
A different OpenDota endpoint turned months of quota arithmetic into a bulk download of 26.8 million match records. Once I had them, I wanted to look before training. Bristleback gave me a good reason to.
-
Building Was Never the Hard Part
For years, the small ritual of building my own custom game client became a tax I paid every time I wanted to play. Turns out the chore wasn't really about the build - it was about everything I had to do *after* it.
-
A Map of Heroes (Dota Drafts, Part 4)
The trained model put familiar Dota heroes near one another without being given their roles. I checked those neighbourhoods in the original embedding space, not just the two-dimensional picture.
-
Three Coffees and a Job Queue (Dota Drafts, Part 3)
I wanted to queue training experiments instead of attending each one personally. The useful design decision was letting the training script tell the scheduler what its controls should be.
-
Choosing Which Games to Learn From (Dota Drafts, Part 2)
Simpler models were competitive with my Transformer, and filtering for stronger players didn't produce the accuracy jump I'd expected. Choosing the training population turned out to be a modeling decision, not just a SQL clause.
-
Which Hero Should I Pick? (Dota Drafts, Part 1)
I wanted help choosing a Dota hero. I started with public match results, a Transformer, and the slightly optimistic belief that representing an unfinished draft would be the same as understanding one.
-
Fighting the IPv4 Tax with a CDN Side-Quest
The story of how a friend's connection issue led me down a rabbit hole of network architecture, culminating in a creative (and free) solution to support legacy IPv4 users without paying the new IPv4 tax.
-
Teaching My Wardrobe Some Style
For years my wardrobe app was a well-organised, completely silent catalogue of my clothes. It knew what I owned but nothing about how I dress. After a month of work, it finally has opinions.
-
How Hard Can It Be To Paste Text To Yourself?
I was tired of emailing files to myself, so I built a simple replacement in a weekend. As usual, prototyping is fast but building a truly polished application takes attention to detail and relentlessly high standards.
-
My Cloud Server Has a Secret Friend in My Closet
My cloud server was running short of memory, and a Raspberry Pi was gathering dust in my closet. Renting a bigger server would have been simpler. Making the two work together sounded considerably more fun.
-
The Guard Who Locked Himself Out: Breaking a Service-Level Deadlock
I built an authentication service that needed to record metrics, and a metrics service that needed authentication. Making them stop waiting on each other helped. Making them stop calling each other took longer.
-
The Mystery of the Missing Elephants
My card lookup gave Call of the Herd a score of 0.890. The recommendation list had room for cards scoring 0.813, but no elephants. I checked the filters, widened the search, and eventually found the clue in a log I'd stopped reading.
-
I Over-Engineered My Magic: The Gathering Cube, and It Was Glorious
I wanted help choosing cards for our weekly Magic nights. I built a scoring engine, taught it that a missing price doesn't mean free, and gave it two ways to indulge my constant tinkering.