What This Is
The Sports Page is a newsletter for friends and family who love sports and are curious about the numbers behind them. Each issue takes one weird stat and explains what it actually means. No statistics degree required. New issues publish five or six times a week during the season, with a Sunday Edition that grades our predictions against reality.
This page is the behind-the-scenes story. How the newsletter gets built, what went wrong along the way, and what we learned from each mistake. If the newsletter teaches statistics through sports, this page teaches what it takes to build something from scratch — one commit at a time.
Content & Editorial Voice
The first issue was Paul Skenes’ 67.5 ERA on Opening Day. We didn’t have a design system, a publishing workflow, or a queue. We had one weird stat and a Google Font. The newsletter grew from there — one question at a time.
- Mar 27 Launch with Issues #1 and #2: Skenes’ ERA and Alonso’s decline curve. Two pieces, zero infrastructure.
- Apr 1 The Misery Index (#3) crossed sports and markets for the first time. The tone clicked: editorial, not academic.
- Apr 3 Draft Combinatorics (#5) proved 32! makes every mock draft wrong. Our first pure math piece.
- Apr 4 Jets Draft Misery (#6) introduced The Heckler voice. The newsletter stopped sounding like one writer.
- Apr 4 Soto injury (#7) was our first BREAKING piece. Published same day. Bayesian severity model gave 54% chance of 10+ games missed. It hit.
- Apr 10 Started the EO Series — five parts on the executive order’s impact on college athletics. Most ambitious thing we’d attempted.
- Apr 12 First Sunday Edition. Graded every prediction against reality. Three hits, two pending, zero hides.
- Apr 14 Introduced Sal — a guest columnist who writes once every 2–3 weeks with perfectly worded sarcasm. Sal only writes when explicitly invoked.
- Apr 17 WNBA maturity analysis published. Three days later, the new CBA proved the thesis: minimum salary jumped from $66K to $300K+.
- Apr 19 Sunday Edition #2 included our first MISS: the Mets 88-win projection. Downgraded honestly. Willie Randolph parallel.
The newsletter found its identity around Issue #5. Before that, it was a stats blog. After that, it was a publication with voices, opinions, and accountability. The Sunday Edition — where we grade our own predictions — turned out to be the soul of the project. Without it, we’re just another hot-take machine. With it, we’re an experiment in applied prediction.
Automation & Infrastructure
The first ten issues were published by hand: edit the file, update the index, commit, push. It worked until it didn’t. The automation journey was bumpy.
- Apr 8 Restructured into published/queue/reserve content tiers. Before this, everything lived in one folder.
- Apr 11 Added setup-machine.sh for cross-platform development (Linux + Mac).
- Apr 12 Built Sunday Edition automation: template + day-of-week forcing function. Sundays became a workflow, not a chore.
- Apr 16 Publishing backend broke. State was stale, queue ordering was vague, failures were silent. Fixed all three: explicit QUEUE_ORDER.txt, git-derived state, failure alerts via GitHub issues.
- Apr 18 Discovered the auto-publish had never actually been wired up. The scheduled trigger didn’t exist. The workflow was documented but never connected.
- Apr 18 Built GitHub Actions autopublish: a Python script that runs Mon–Sat at 4:30am ET. Reads the queue, enforces variety rules, updates issue numbers, inserts into index.html, commits, and pushes. No AI needed for the mechanical parts.
- Apr 19 Added live-computed publication rate to the homepage. The JS reads the archive directly — no hardcoded values. The page IS the database.
Automation isn’t reliable until it’s boring. The Claude Code scheduled trigger worked sometimes. GitHub Actions works every time. We split the problem: mechanical publishing (Mon–Sat) is a deterministic script; editorial work (Sundays, new content) stays human. The best automation is the kind nobody notices.
Design & User Interface
The broadsheet aesthetic was there from day one. The navigation was not.
- Mar 27 First design: Playfair Display headlines, Libre Baskerville body, Roboto Mono stats. Aged newsprint palette. This has never changed.
- Apr 8 Added branding: logo, banner, favicon, QR code for sharing.
- Apr 8 Masthead redesign #1: badge logo + title. Too busy. Redesign #2: back to text-only broadsheet. Redesign #3: final version. Three commits in one day to get back where we started.
- Apr 10 Added share section with QR code and banner at page bottom.
- Apr 13 Added “Pitch a Story” form with Formspree. First attempt redirected away from the page. Fixed to AJAX submission.
- Apr 19 Discovered articles had zero navigation back to the homepage. No clickable masthead, no back link, no breadcrumb. Added “← Back to Archive” and made the title a link.
- Apr 19 Attempted semantic HTML upgrade (div → header/main/footer) via batch regex. It broke layouts on files with complex nesting. The pitch form spanned 100% of the browser. Reverted to divs, kept the working nav elements.
- Apr 19 Removed the “Ask the Stats Desk” interactive form from all pages. It required an API key that readers didn’t have. If a feature doesn’t work for readers, it shouldn’t be on the page.
Two hard lessons. First: never batch-replace HTML structure with regex. Files have different nesting patterns, and the same regex will match the wrong closing tag in complex layouts. Additive changes (inserting new elements) are safe to batch. Structural changes (swapping element types) require per-file attention. Second: the masthead went through three redesigns in one day before landing back at the original. Sometimes the first instinct was right.
“The best automation is the kind nobody notices. The best design is the one you don’t redesign three times.”
— Lessons from 56 commitsData Integrity & Methodology
A statistics newsletter that publishes wrong numbers has no reason to exist. We got some wrong.
- Apr 6 Fixed issue numbering: Soto piece was labeled #10 internally but published as reader Issue #7. Reader-facing numbers and internal filenames are different systems — we confused them.
- Apr 7 Fixed a cross-reference: an article referenced “See Issue #8” but Issue #8 hadn’t been published yet. Changed to “coming soon.”
- Apr 10 Added topic variety rule: never publish back-to-back on the same sport or series. The EO series ran three parts in five days and tested readers’ patience.
- Apr 12 First Sunday Edition scored 3 of 4 predictions correctly. Soto injury model was our most precise hit (54% chance of 10+ games, placed on 10-day IL).
- Apr 19 Sunday Edition #2 initially reported the Mets’ losing streak as 11 games. It was 10. The error came from inferring the streak grew because the record changed — instead of checking the actual game-by-game log.
- Apr 19 Added the triple-verify rule: every number must be checked against 3 independent sources before publishing. Never infer a number from another number. The cost of checking is seconds; the cost of being wrong is credibility.
The losing-streak error taught us the most important lesson of the project so far: a newsletter about statistical rigor cannot be sloppy with its own statistics. We added “triple-verify every number” as the first editorial rule. If ESPN, Baseball-Reference, and MLB.com don’t agree, we don’t publish until they do. This rule exists because we broke it.
The Arc
In 23 days, The Sports Page went from a single HTML file about Paul Skenes to a daily-publishing newsletter with automated infrastructure, multiple editorial voices, a prediction accountability system, and a five-part investigative series on federal policy’s impact on college athletics.
It also broke. The publishing trigger never existed. The masthead was redesigned three times in one afternoon. An issue went live with the wrong number. A stat was published without verification. A batch script put a form outside its container and it spanned the entire browser window.
Every fix made the system better. The queue ordering became explicit after vague priorities caused confusion. The variety rule was added after the EO series ran too hot. The triple-verify rule was added after a wrong number reached the page. The navigation was added after someone tried to get back to the homepage and couldn’t.
That’s the real story of this project: not that it works, but that it learned how to work. One commit at a time.
“Every fix made the system better. Not because the fixes were brilliant, but because the failures were specific.”
— The Sports Page, on building in publicPeek Ahead: What’s in the Queue
These are written, reviewed, and ready to publish. The autopublish script picks from this list every weekday morning.
- Loading queue…
Like what you see? Have a better idea? ↓
Pitch a Story
Noticed a weird stat? Saw something that doesn’t add up? Send it in. The best ideas become issues.