NSBA Analytics Β· a modeling blog

How we actually modeled a
science-bowl league

TL;DR
We run a science-bowl league like a sports franchise, so we built the whole analytics stack for it β€” ability ratings off a (cheatable) tryout, baseball-style projections, a draft-value curve, a game engine, market pricing, even a live-trading bot. Under the hood that's graded-response item-response theory, empirical-Bayes shrinkage, Plackett–Luce and Bradley–Terry rating models, a Hamiltonian-Monte-Carlo hierarchical Bayesian fit, LMSR market-making, and 50,000-run Monte-Carlo bracket sims β€” basically the full sabermetrics-meets-quant-desk arsenal, pointed at a high-school science quiz. The fun part is how little of it beats a coin flip. Our weekly game model went 20-16 calling winners β€” and got beaten by "always pick the home team" (27-9). Combine ability explains only ~6% of game-margin variance; our fanciest model β€” a joint hierarchical Bayesian fit β€” doesn't out-predict the dumbest baseline; and even the draft "edge" we were proudest of shrinks to almost nothing under scrutiny. Along the way we tried to settle a Discord argument with an experiment (do your two best buzzes reveal your ability better than your average? at this sample size β€” honestly, we can't tell), then handed the finished post to four hostile experts β€” a statistician, a quant, a sharp, and a scientist β€” who tore into it. What they broke is the closing section, and it changed the paper. Everything here comes with its error bars. If you want the pretty charts instead of the math, the Question Lab is next door.

01The data, and why it barely tells us anything

Three seasons of games, four of tryouts, and a mess of names to reconcile before any of it means anything.

NSBA is a science-bowl league run like the NBA. Every player takes a combine β€” a standardized 24-question tryout β€” then fourteen captains build rosters through a snake draft and play a season of head-to-head matches. Two scoring systems live side by side and are never mixed. Game rounds use standard Science Bowl scoring: a correct toss-up is +4, a wrong interrupt (a "neg") is βˆ’4, and a converted team bonus is +10. The combine is pyramidal β€” buzz earlier for more credit (+4 / +3 / +2), with βˆ’1 for a wrong multiple-choice guess β€” which makes it gameable: because only wrong MC buzzes are penalized, late guessing ("biking") is positive-EV. So the combine is used only as a predictor, never as a measure of value.

The corpus is small and we say so up front. Game scoresheets span three seasons (2022, 2023, 2025), reconciled to a clean set of 180 games β€” the games that both balance and aren't empty templates:

$$\text{clean} = \{\, g : \texttt{reconciles}(g) \;\wedge\; \neg(\texttt{score}_a{=}0 \wedge \texttt{score}_b{=}0)\,\}$$

That yields 41 team-seasons and 207 player-seasons over 181 distinct people, plus 216 draft picks across three drafts. Combine data covers four seasons including the current one β€” whose games hadn't been played when the models were built. The parser is faithful: the combine reconstructs with zero mismatches, and per-player points reconcile exactly against the buzz-attributed totals.

The two-scoring-worlds guardrail

The single most load-bearing discipline in the whole project: the pyramidal, gameable combine and the standard-scored game are never folded into the same statistic. The two even use different code vocabularies (b/ch/cs/ess/m/p in games, bio/chem/… in the combine), which forces an explicit crosswalk on every join and makes accidental mixing hard. The one time the guardrail slipped β€” an early finding that "CS points are worth 3.5Γ—" had quietly fed team bonus points into a per-player regression β€” an adversarial re-audit caught it and the ratio collapsed to β‰ˆ1.8Γ— (and lost significance). More on that in Β§10.

Identity: the hardest unglamorous problem

A player appears as a Discord handle in one place, an in-game nickname in another, a real name in the combine. Every raw string is mapped to a canonical_id by a union-find over five bridge rules (shared Discord tag, exact real name, a nsba1 nickname↔name "Rosetta" sheet, and two team-scoped fuzzy matches). Matches are never forced: 65 ambiguous identities are kept raw, and a bare first name appearing on two different teams is treated as two humans, not merged. The draftβ†’game roster bridge is scored by Jaccard overlap of canonical rosters,

$$J(\text{game roster},\,\text{draft roster}) = \frac{|R_g \cap R_d|}{|R_g \cup R_d|},$$

and its per-season quality is wildly uneven β€” median 0.11 in nsba1 (nicknames vs real names: effectively unlinkable), 1.00 in nsba2, 0.50 in nsba3. This is why nsba1 is essentially games-only and nsba2 carries most of the draft-outcome story.

PPTF and how much of it is real

The base currency is points per toss-up faced β€” not per game, because bonuses are team-answered and can't be attributed to an individual:

$$\mathrm{PPTF} = \frac{\texttt{toss\_points}}{\texttt{tossups\_faced}} = \frac{4c - 4g}{n},$$

where c = correct buzzes, g = negs, n = toss-ups faced. How much of the spread in PPTF is talent versus sampling noise? A method-of-moments variance decomposition splits observed variance into between-player (true) and within-player (sampling) parts; the ratio is the stabilization constant M, and reliability at n trials follows:

$$M = \frac{\overline{\sigma^2_{\text{within}}}}{\sigma^2_{\text{between}}}, \qquad \rho_n = \frac{n}{n+M}, \qquad \widehat{\text{PPTF}} = \frac{n}{n+M}\,\overline{\text{PPTF}} + \frac{M}{n+M}\,\mu.$$

PPTF stabilizes at M β‰ˆ 35 faced toss-ups (reliability 0.5, ~1.5 games); at the median sample of ~150 faced, ρ β‰ˆ 0.81 β€” we keep about 80% of the signal. An independent empirical split-half, corrected by Spearman–Brown

$$r_{\text{full}} = \frac{2\,r_{\text{half}}}{1 + r_{\text{half}}},$$

agrees at 0.82, which is the check that the whole reliability edifice actually holds. Neg rate, by contrast, has M β‰ˆ 23 but a tiny denominator (~12–15 buzzes), so ρ β‰ˆ 0.35 β€” mostly noise, and shrunk hard toward the league mean.

The constraints, stated up front n is tiny everywhere (41 team-seasons; some subject cells are a handful of buzzes). CS exists in games only in two seasons. nsba3 uses an estimated toss-ups-heard proxy β€” and it's simultaneously the noisiest-measured season and the one most like the current target. Everything below is a ranked, confound-audited set of directions, not precise numbers. Treat every magnitude as Β± a lot.

02Grading a cheatable quiz

Before the season, all you have is a cheatable tryout. Here's how much to trust it β€” spoiler: not much.

Every player takes a 24-question combine (6 categories Γ— 4 pyramidal questions, buzz earlier for more credit). The catch: a wrong multiple-choice guess costs only βˆ’1 and short-answer buzzes are free, so late guessing β€” "biking" β€” is positive-EV, and a weak player can inflate a raw score. So we don't score it arithmetically; we fit a graded-response IRT model, recoding each question to an ordered outcome (wrong-bike < skip < no-credit < +2 < +3 < +4) and estimating each player's latent ability from the pattern, not the point total:

$$P_{ik}(\theta) = \underbrace{\sigma\!\big(a_i(\theta - b_{i,k-1})\big)}_{\text{clear boundary }k-1} - \underbrace{\sigma\!\big(a_i(\theta - b_{i,k})\big)}_{\text{clear boundary }k}.$$

Fit by marginal maximum likelihood, read out as a posterior-mean (EAP) ability with its error bar; a re-fit that drops the bikeable tier ("de-biking") corrects the worst gaming. It's a tidy model. But here's the honest part, and the reason this section is short: the combine only correlates β‰ˆ0.6 with what players actually do in games β€” it explains about a third of the variance and no more. For a suspected tanker it's a gamed ceiling; for a reliable returner it's an honest floor; for everyone it's a prior we lean on hardest for rookies with no tape and abandon the moment real games arrive. Which they do β€” and that's where the interesting modeling actually happens.

03Stealing baseball's projection playbook

Baseball's projection playbook β€” stabilize, regress, age β€” ported to a buzzer.

Projecting a player is a four-step "Marcel" spine borrowed from sabermetrics. Weight prior seasons by recency (newest gets weight 5, then 4, 3) and by sample; compute the stabilization constant from variance components; then regress the weighted rate toward the league mean with M β‰ˆ 35 toss-ups of padding. The empirical-Bayes shrinkage is a single line:

$$\hat\theta_{\text{PPTF}} = \frac{n_{\text{eff}}}{n_{\text{eff}}+35}\,\bar x_{\text{obs}} + \frac{35}{n_{\text{eff}}+35}\,\mu_{\text{PPTF}}, \qquad \mu_{\text{PPTF}} = 0.332.$$

Per-category projections shrink harder (padding β‰ˆ 5.8, since a subject sees ~β…™ the volume), so a two-buzz "CS specialist" is pulled most of the way back to average β€” appropriately. Replacement level is the projected rate of the 70th-ranked player (a 14Γ—5 league), and VORP = (ΞΈΜ‚ βˆ’ 0.298) Γ— 150. Because the talent pool is thin, replacement sits near average, so VORP cleanly separates the elite but flattens the middle.

Growth, net of the illusion of growth

A naΓ―ve year-over-year delta shows players improving +0.43 z per edition β€” but much of that is regression-to-the-mean of a negatively-selected returning cohort. Fitting the change on prior level separates the two effects:

$$\Delta\theta = \beta_0 + \beta_1\,\theta_{\text{prior}},$$

where Ξ²1 β‰ˆ βˆ’0.43 is mean reversion and Ξ²0 β‰ˆ +0.41 z is the true net development for a returner starting at the mean (95% CI [+0.13, +0.68]). The rule that follows is strict: apply reversion and development once, together β€” never stack a growth bump on top of shrinkage, or you count the same climb twice.

Turning points into wins

Two lenses. Win Shares distribute a team's actual wins by scoring share, so they sum exactly to the team total: WSp = point_sharep Γ— team_wins. Win-Probability-Added models the final margin as a Normal that collapses onto the running score as toss-ups resolve, and credits each buzz's swing to the player:

$$P_A(\text{win}) = \Phi\!\left(\frac{\text{margin}}{\sigma_{\text{rem}}}\right), \qquad \sigma_{\text{rem}} = \text{RESID\_SD}\sqrt{\tfrac{\text{tossups remaining}}{N}}, \quad \text{RESID\_SD} = 56.$$

The residual SD is deliberately un-cocky β€” a 20-point lead is only ~65% pregame β€” so early swings aren't inflated; 1.00 WPA β‰ˆ one full win added.

Value versus luck

Three orthogonal skill-minus-variance separators keep us honest: points above expectation (actual gets minus what the win-model expected from the player's actual lineup); Pythagorean wins from point differential, win% = PFk/(PFk+PAk) with k = 2.37 pinned (a free fit overfits 4–5 games/team); and the model residual, realized output minus combine prior, both z-scored. When all three agree a player is under- or over-rated, we believe it; when they don't, we don't.

What's deliberately missing The shipped value board applies no aging term β€” it regresses to the population mean and therefore under-projects rising youngsters. RAPM (the basketball plus-minus workhorse) is a null here β€” one buzzer per toss-up makes the design rank-deficient (r = 0.19 vs observed) β€” so it's a diagnostic, not a rating.

04The one place the field looks mispriced

The field drafts the tryout, not the talent. The inefficiency is real; the size of it, less than we first claimed.

Here is the market inefficiency in two numbers. The field drafts almost mechanically off the visible raw combine β€” the rank correlation between pick order and combine score is 0.67–0.75 every season. But the combine predicts realized value only at ρ β‰ˆ 0.36–0.43. The room over-anchors on a gameable tryout: that gap is real and directional. How much it's actually worth is where I have to walk myself back.

In betting terms the combine is the number everyone anchors on, so the draft prices like a soft book, and fading it β€” taking the talent the tryout underrates, passing on the biked-up darlings β€” is directionally the +EV play. But the magnitude an earlier draft of this post bragged about, "~13 toss-points per slot," does not survive a hard look, and the quant we sent this to caught it cleanly. That figure comes from a single clean-linkage season (nsba2) on about nine names. Pooled across the whole corpus the recoverable edge is closer to ~2–3 points a slot; it roughly vanishes in the season that most resembles today; and the one fully-independent test of "the field mis-drafts talent" comes back null β€” the combine's own link to the pick-slot residual is 0.007 (p = 0.95). So the inefficiency is real in direction, shaky in magnitude, and quite possibly not exploitable once you're honest about the linkage artifacts. It's the closest thing to an edge in the entire project β€” which mostly tells you how little edge there is.

The pick-value curve

Joining each pick to its realized win-shares and fitting a curve over the normalized snake slot gives a clean exponential (not linear) decay:

$$\widehat{\text{value}}(\text{frac}) = 0.285 + 2.47\,e^{-6.28\,\text{frac}}.$$

Rescaled so pick 1 = 100, the round-openers are worth roughly 100 / 42 / 22 / 15 / 12 / 11 β€” a steep top and a long flat tail, and the curve is convex (the top pick is worth more than a linear board implies). The real "loser's curse" isn't a lower mean at the top; it's variance: round-1 busts run 15%, round-6 busts 73%. Early picks are insurance as much as talent.

Steals and reaches

The live draft grade β€” the one the community bot reports β€” is a rank delta. A player's value is a balanced z-score of skill and volume, ranked, and compared to where they were drafted:

$$\text{value\_score}_i = \tfrac{1}{2}\big(z(\text{Buzzer Elo}_i) + z(\text{toss\_points}_i)\big), \qquad \text{steal\_score}_i = \text{pick\_rank}_i - \text{value\_rank}_i.$$

Positive means drafted later than they've played (a steal); negative means a reach. It runs on a small Β± integer scale (~Β±25) β€” and is deliberately not the same quantity as the ability-adjusted "value grade" on the draft-value page, which uses IRT/PPTF on a Β±70 scale. Two different yardsticks for the same idea. The season's biggest steals were late-round finds (Uddip K at pick 61, +33); the biggest reaches were early picks who underdelivered.

Corrections that didn't matter, and one clustering that did

Two sophisticated adjustments were built and then honestly shelved. Contestation-adjustment β€” a Plackett–Luce model, P(i wins | field) = eΞΈi / Ξ£ eΞΈj, to strip out the "empty stats" a lone star vacuums on a weak team β€” reorders the board by almost nothing (Spearman 0.93 with raw PPTF; the confound test is a clean null). Duo synergy β€” do complementary teammates over-produce? β€” is a bounded null: zero of eight tests survive multiple-comparison correction. The lesson is that team-building here is additive: draft the best individual value, don't chase fit.

The one structure that held is archetypes. K-means on a fused combine+game per-subject vector finds five soft clusters, and only one β€” "elite multi-science" (broad and deep, chem/physics core) β€” reliably wins, carrying ~4Γ— the win-shares and essentially all the VORP. Notably, there is no pure-CS archetype: strong CS players ride with the broad elites.

Read the boards as watchlists With FDR correction, no individual steal or bust name is statistically significant (0 of 94). The named boards are shortlisting flags, not claims. And the "undervaluation" validation (ρ β‰ˆ 0.60) turned out ~90% circular β€” a shared-PPTF artifact β€” with combine's independent link to slot-residual a flat 0.007 (p = 0.95). There is no new edge beyond the ~13 pts/slot above.

05Predicting games, and mostly failing

This is the part everyone actually cares about: we posted a line on every game for six weeks. Here's the scoreboard, and it's humbling.

The model's job was to call games. Across the first six weeks β€” 36 games with a published line β€” it went 20-16 straight up (55.6%). Sounds fine, until you meet the baseline: always pick the home team went 27-9 (75%). The dumbest possible heuristic beat our log-sum-exp-softmax-Bayesian machine at every horizon. So let's answer the only question a bettor actually cares about, up front and in bold: would you have made money betting this model? No. 20-16 is roughly break-even before the vig, and blind-betting home would have buried it. Its Brier score is 0.250 β€” identical to shrugging "50/50" every week. Two caveats, cutting both ways: at n=36 that record is statistically indistinguishable from a coin in either direction (55.6% carries a 95% CI of about [39%, 71%]), so we can't prove it's worthless either β€” and a Brier tie can hide real signal behind bad calibration, which, it turns out, is exactly what's happening here.

WeekGamesStraight-upSU %ATS (home)Spread MAEBrier
161–516.7%5/651.80.312
264–266.7%4/634.70.245
366–0100%4/642.00.176
463–350%3/665.30.264
563–350%5/641.70.262
663–350%5/647.30.241
Total3620–1655.6%26/3647.10.250
.30 .20 .15 coin flip Β· .25 Week 1: Brier 0.312 (1-5) Week 2: 0.245 (4-2) Week 3: 0.176 (6-0) β€” the peak Week 4: 0.264 (3-3) Week 5: 0.262 (3-3) Week 6: 0.241 (3-3) W1W2W3W4W5W6
Lower is better; the dashed line is a coin flip. Week 3 (green) was the high-water mark β€” 6-0, Brier 0.176. Then it reverted. Weeks 4–6 all landed 3-3 at ~coin-flip. This is the whole story: one real early fix, then a plateau.

How the engine works (in one breath)

Under the scoreboard is a clean generative model. Each team's per-subject strength is a log-sum-exp pool over its lineup, the three-way toss-up outcome (A / B / dead) is a softmax, the margin is a sum of independent toss-ups and therefore Normal by the CLT, and the win probability is one normal CDF:

$$P(A\text{ wins toss-up}) = \frac{R_{A,s}}{R_{A,s}+R_{B,s}+e^{c_s}}, \qquad P(A\text{ wins game}) = \Phi\!\left(\frac{\mu_M}{\sigma_M}\right),\;\; R_{T,s}=e^{\beta\,\operatorname{logsumexp}_{p\in T}\theta_{p,s}}.$$

It's a nice model. It just runs into a wall: on the historical backtest, combine ability explains only 1-(56.2/57.9)^2 β‰ˆ 6\% of margin variance. A ~150-point game has a ~56-point residual SD β€” most of the outcome is same-day noise no rating can see.

Why it lost to "pick the home team"

The ~6% ceiling is the irreducible problem. But there was a very reducible one hiding in the calibration, and it's the sharper lesson. In NSBA the home team bans a category, so home teams won 75% of games β€” yet the model's mean probability on its own favorite was just 0.553. It barely leaned home. Bucket the predictions and the miss is glaring:

Model said P(home)GamesHome actually wonMiss
0.40 – 0.45785.7%+0.44
0.45 – 0.501154.5%+0.07
0.50 – 0.55988.9%+0.38
0.55 – 0.60683.3%+0.25

The probabilities are both under-dispersed (they hug 0.5 β€” the standard deviation of p βˆ’ 0.5 is a measly 0.072) and mis-centered (too low on the home side). The spread shows the same tell in tradeable form: home covered the model's own number 26/36 = 72%. In plain terms, we were so reliably light on home that fading our own spread and taking home would have hit 72% β€” a cleaner signal than the moneyline, and proof the miss is a systematic side bias, not variance. Two honest hedges, though: those bucket cells are 6–11 games and non-monotonic (noise texture, not a clean slope), and a home offset fit on these same 36 games would overfit exactly like the Week-3 blunder below β€” the direction (we under-credit home) is safe, the magnitude isn't. And home's 75% rests on a real mechanism (the category ban is a rules artifact), not just a 27-9 record that on 36 games is itself a wide [59%, 86%]. We were tuning the engine while the wheel was pointed slightly the wrong way β€” an ordinary, humbling failure.

The Week-3 mirage

The arc is worth telling straight, because it's the kind of trap every modeler falls into. Week 1 posted road favorites with full rosters and went 1-5 β€” the worst week. We fixed the two obvious things: projected lineups (use who actually dressed last time, catch the no-shows) and a dispersion fix, and Week 3 came back 6-0, Brier 0.176 β€” the peak. Feeling good, we ran an in-sample backtest, saw that a model-only line beat the 70/30 market-futures blend 83% to 50%, and dropped the blend. Then Weeks 4, 5, and 6 all went 3-3 at a coin flip.

The sharp lesson That in-sample backtest was a mirage. The 83%-vs-50% edge that justified dropping the market blend never showed up out-of-sample β€” Weeks 4–6 are three straight coin flips. Fitting a decision on 12 in-sample games and shipping it is exactly how you talk yourself out of the one signal (the market) that was actually helping. If there's a single transferable takeaway in this whole write-up, it's that one: your backtest is lying to you until it's out-of-sample.
The lever we can't pull The biggest movable quantity isn't the model at all β€” it's attendance. Knowing the actual lineup (an oracle) instead of the drafted roster is worth ~+9 points of win accuracy and flips the favorite in ~30% of games. It's a bigger lever than ability, and it's not predictable from history. (The category-ban choice is modeled too β€” a softmax over which subject each home captain removes β€” but next to attendance and home-court it's a rounding error.)

06Home court: 14 points shouldn't win 75% of games

The home team wins three of every four games. The only home mechanic is banning one category β€” call it 14 points. Fourteen points shouldn't do that. So what's really going on?

The instinct to distrust that 75% from Β§5 is correct, and worth working through, because the arithmetic doesn't obviously support it. NSBA is played online β€” no travel, no crowd β€” so the entire home-court effect is one rule: the host bans a category, removing roughly one toss-up and its bonus, about 14 points, from the board. On a game whose margin has a standard deviation of ~57 points, a 14-point shift moves the win probability to only

$$\Phi\!\left(\frac{14}{57}\right) \approx 0.60.$$

So a face-value 14-point ban predicts a 60% home team β€” not 75%. Taken at its sticker price the mechanism is nowhere near big enough. Something has to give.

First: it isn't that stronger teams host

The obvious escape hatch is a scheduling confound β€” if the better team tended to draw the home slot, "home advantage" would just be team strength in disguise. It isn't. Hosting in this league is a coin flip, and the data agrees: home teams averaged a 51.9% season win rate versus 48.1% for visitors β€” a 3.8-point sliver β€” and the home team was actually the stronger side in only 17 of 36 games (47%, itself a coin flip). Hosting is split two-or-three games apiece across all fourteen teams. So whatever edge does show up this season is caused by hosting, not selected by it β€” which matters once we pin down how big it actually is.

The wrong answer we talked ourselves into

Our first pass measured this season alone: home teams outscored visitors by a mean of +24.8 points, so we spun a tidy story β€” the ban must be adversarial (you remove the opponent's single best category, an order statistic above the mean), so it's "really worth ~25, not 14." It's a satisfying story. It's also mostly wrong, and the honest fix is the boring one: get more data.

So we checked it against history

Reach back to the three prior seasons and measure the exact same thing under the same convention β€” the right-hand team on the scoresheet is the host. Across 168 clean regular-season games, home court is worth nothing:

SeasonGamesHome win %Home margin
NSBA 1–3 (all)16845.8%βˆ’3.8
  nsba16648.5%+2.7
  nsba26148.4%βˆ’3.2
  nsba34137.8%βˆ’14.9
nsba4 (this season)4264.3%+18.4

Historically the host wins under half its games (45.8%, 95% CI [38%, 53%]) and the margin CI straddles zero (βˆ’3.8, [βˆ’11.8, +4.3]) β€” no home-court edge, if anything a hair negative. And this season, measured cleanly by the scoresheet's right column rather than the platform's soft home/away label, the edge is +18.4 ([+1.4, +35.4]) at a 64% win rate β€” real, but nowhere near +25/75%, and only just clearing significance.

The honest resolution The title was right: 14 points can't win 75% of games β€” and it doesn't. A 14-point ban predicts Ξ¦(14/57) β‰ˆ 60%; the clean nsba4 number is ~64%. The +25 / 75% we first reported was small-sample noise off a soft "home" label (36 games, CI running to 89%; a 12-game platform-labeled subset that hit 75% by luck). The simple mechanism was right all along β€” our first measurement was the thing that overshot. Best estimate: home court is worth maybe +15 points / ~60% this season and ~zero before it, consistent with the category ban being a new isobowl-era rule the scoresheet seasons never had. A real edge, and a small, uncertain one.

This recalibrates Β§5, too. The engine priced home at roughly +14 / 60% β€” which turns out to be about right. What beat it there ("always pick home," 27-9) was a home side that over-performed its true ~64% in a 36-game sample. The model did still under-lean home, but the gap it missed is a handful of points of win probability, not the 20+ the raw 75% implied.

07Pricing the market, and the bot we never turned on

Pricing the league's play-money prediction market β€” and a live trader that lives off variance collapse.

The league runs a play-money prediction market, which needs prices. Take the flagship binary β€” "will player X score more than 32 toss-up points in some single game this season?" Model per-game points as Normal, price the tail, and compound over the season's games under independence:

$$p_{\text{game}} = 1 - \Phi\!\left(\frac{32 - \mu}{\sigma}\right), \qquad p_{\text{season}} = 1 - (1 - p_{\text{game}})^{N}.$$

The mean comes from the player's rating (a regression with RΒ² = 0.98, on all of thirteen players β€” read with suspicion); the variance is Bayes-blended with history or a population model. This gave Sanjay S β‰ˆ 79% and Kian D β‰ˆ 40% to hit the line β€” and the fat tail matters: a high-variance player gets a bigger over-shot than his mean alone suggests. When bets are placed, size them by fractional Kelly against the market price:

$$f^{*} = \frac{p - \text{price}}{1 - \text{price}}, \qquad \text{stake} = 0.35\cdot\text{bankroll}\cdot f^{*}.$$

Trading the market live

The platform is a Hanson LMSR automated market maker: prices are a softmax of outstanding shares, and the cost to move them is

$$C(q) = b\,\ln\sum_i e^{q_i/b}, \qquad p_i = \frac{e^{q_i/b}}{\sum_j e^{q_j/b}}.$$

Because LMSR is shift-invariant, the bot reconstructs the full share vector from just the observed prices and the liquidity parameter b (qi = b ln pi), then buys until the marginal price hits fair βˆ’ 0.02 (the average fill beats the marginal, so it's +EV by construction). The edge itself comes from variance collapse: as toss-ups resolve, the live win probability conditions on the running score and the remaining uncertainty shrinks toward zero:

$$p_{\text{live}} = \Phi\!\left(\frac{M_k + \mu_{\text{rem}}}{\sigma_{\text{rem}}}\right), \qquad \sigma_{\text{rem}} = \frac{\text{RESID\_SD}}{\sqrt{N}}\sqrt{N-k} \;\to\; 0.$$

The model is essentially "collapse the Normal onto the score" β€” the ability correction is a near-negligible tie-breaker, since Ξ² = 0.296 means skill barely moves a single toss-up.

How it did β€” and an honest walk-back The props nailed the tails: the only player the market gave a real shot to clear 32 (Kian at 93%) did, and all ten longshots priced under a third missed. The pregame game lines were right on just 50% of resolved markets β€” weak, same as Β§5. As for the live bot: an earlier draft of this post called its edge "closing-line value," and that's wrong, so here's the correction. The price drifting to a 72% favorite by lock is just variance collapse β€” Οƒrem β†’ 0 as the score comes in, the market converging on a result it can now see, which every live market does trivially. It isn't CLV (there's no sharp closing line β€” the counterparty is a mechanical AMM), and it isn't realized alpha: the stack has never traded a real dollar. Worse, the price is public arithmetic β€” anyone on the same socket feed computes the identical number, so a second bot erases the "edge." The honest claim is small: against a brainless maker you can pick up the ~2Β’ it leaves by construction. Clever plumbing; not an edge.

08Is buzzing fast even a skill?

When a buzz happens is mostly a fact about the question, not the person β€” with one important open door.

How early someone buzzes feels like it should measure how good they are. We modeled buzz order as a Plackett–Luce race: each player carries a latent buzz-speed strength, and the probability they beat a field is a softmax,

$$P(i\text{ buzzes first} \mid \text{field } S) = \frac{e^{\theta_i}}{\sum_{k\in S} e^{\theta_k}},$$

with dead questions retained through a shared "virtual competitor" term. Fitting this and folding in the actual buzz position (celerity) turns out to add almost nothing: the celerity-weighted rating correlates 0.99 with a pure who-won-the-buzz model, and buys zero held-out predictive lift. Everything the buzzpoints "know" is already implied by who beats whom. A competing "buzz-rank" feature was actively worse β€” it promotes low-volume fast buzzers and punishes high-volume elites, measuring style, not quality.

Why averaging buzz timing fails

The deeper reason is a reliability wall. Split-half reliability of a player's average buzz position is r β‰ˆ 0.08 β€” about 92% noise β€” because a player buzzes only ~5 times a season, so their mean is dominated by which questions they happened to face. The very same buzz data, aggregated by question, is reliable at r β‰ˆ 0.58: a packet is reused across ~6 games, so buzz position is a genuine question-difficulty signal. The signal that's real in the data is question hardness, not player speed β€” which is why buzz timing informs our difficulty priors and stays out of the player ratings.

Read the fine print β€” it sets up Β§9 That r β‰ˆ 0.08 result is about the mean buzz position as a talent metric. It says nothing about a player's peak buzzes β€” their two or three fastest, hardest conversions. A reasonable argument (and a real one someone made) is that the information is in the extremes: "you can tell from a few select buzzes whether someone truly owns a category." The existing analysis never tested that. So we did β€” next section.

09The experiment: do your best buzzes matter?

A specific, falsifiable claim β€” "a few great buzzes reveal category mastery better than the average" β€” put to the data.

The argument is intuitive and worth taking seriously: information is disproportionate, so a player's two or three fastest conversions on hard clues should reveal what they truly know better than a season of middling averages. To test it, we need an ability truth that is independent of in-game buzzing β€” the combine IRT ΞΈ per category β€” and we ask which family of in-game features predicts it better.

For every (player, subject) cell with at least three correct buzzes, we built two feature families. Mean/volume: get count, get rate, average buzz depth. Peak/extreme: the single fastest buzz, the mean of the top-2 and top-3 fastest, and conversions on the hardest questions. Then a head-to-head, leave-one-out out-of-sample RΒ² at predicting combine ΞΈ. Coverage, stated honestly: 87% of buzzes join to an identity, leaving 81 cells across 43 players β€” thin, and that thinness is the binding constraint.

Model (predicting combine ΞΈ)featuresout-of-sample RΒ²
Mean / volume4βˆ’0.051
Peak / extreme7βˆ’0.116
Select peak (feature-matched)3βˆ’0.034
Both11βˆ’0.162

The verdict: we can't tell β€” and being honest about that is the finding. Every family lands below zero out-of-sample, and that does not mean "peak is worse than mean." It means neither recovers the target, so the βˆ’0.12 vs βˆ’0.05 gap is a comparison of two noise realizations. At n=81 the experiment is underpowered to the point of being uninformative about the contrast at all. And the one wrinkle actually cuts toward the theory: the single strongest correlate is a peak feature β€” fastest buzz, r = βˆ’0.22, 95% CI [βˆ’0.42, 0.00], p=0.046 uncorrected β€” so if the thin data leans anywhere, it leans for "select buzzes," not against. We didn't refute the idea. We found we don't have the sample to test it.

The mechanism is a one-way analysis of variance on buzz depth, and it's decisive: which question it is explains 76% of the variance in how deep a buzz lands; the player explains only about 10%.

Ξ·Β² of correct-buzz depth (n = 646) question: 76% player: 10% subject: 2% residual / luck: 12% question Β· 76% player 10% luck 12%
Buzz depth is a property of the question, not the person. The direction β€” question ≫ player β€” is robust; the exact 76/10 split isn't (raw Ξ·Β² flatters a factor with hundreds of levels). But even a generous read leaves little person-signal, and ~5 buzzes a season can't isolate it.
Honest bottom line (revised after review) This is inconclusive, not a rejection β€” a distinction our reviewers rightly hammered. Both families are ~0 out-of-sample, but our "ground truth" is a per-category combine ΞΈ fit on ~4 questions: a shrunk, noisy estimate. Predicting one thin noisy number from another puts a low ceiling on RΒ² before any hypothesis is tested, and biases the whole thing toward the null it "found." The defensible claim is narrow: in this league, at ~5 buzzes per player-season and with a 4-item criterion, per-category ability isn't recoverable from the buzz stream β€” peak or mean. Whether a player's best buzzes genuinely reveal mastery is still open. It'd take a full-season corpus and a cleaner criterion to actually settle it β€” which is a more interesting cliffhanger than a fake win.

10Simulating the season, then trying to break it

Simulating the season 50,000 times β€” and letting adversaries try to break every finding.

Playoff odds come from Monte-Carlo. Each remaining game draws a margin from the calibrated engine, seeds are set by the real tiebreak (wins, then total points scored), and the bracket is run tens of thousands of times. Any probability is a sample mean, with a Monte-Carlo standard error small enough to ignore:

$$\hat p = \frac{1}{N}\sum_{k=1}^{N}\mathbb{1}[\text{event}_k], \qquad \text{SE}(\hat p) = \sqrt{\frac{\hat p(1-\hat p)}{N}} \approx 0.002 \;\;(N = 50{,}000).$$

The title odds come out flat β€” the favorite sits near 16%, the field bunched behind β€” precisely because the ability engine can barely separate teams (recall the ~6% margin variance). The championship is mostly seeding and variance, not a runaway. That flatness is a finding, not a bug.

The joint model, and the discipline to report a null

The technical centerpiece is a joint hierarchical Bayesian model β€” the kind of thing you'd see in a psychometrics paper, fit here with the No-U-Turn sampler. One latent per-(player, subject) ability vector feeds two likelihoods at once β€” the games and the combine β€” with partial pooling across players and seasons and a per-player "bias" term that literally learns how much each person games the tryout:

$$\theta_{p,s} = \text{overall}_p + \text{subject}_s + \tau\,\varepsilon_{p,s}, \quad \text{PPTF}_i \sim \mathcal{N}\!\big(\mu^{\text{game}}_i, \tfrac{\sigma_0^2}{n_i}\big), \quad \text{combine}_j \sim \mathcal{N}\!\big(\mu^{\text{comb}}_j, \sigma_s^2\big).$$

It's the right architecture β€” a player becomes a six-dimensional vector, not a scalar, which correctly re-rates specialists a flat PPTF buries, and it hands combine-only rookies honestly wider intervals (~1.7Γ—). It converges cleanly (zero divergences). And here is the discipline that matters most: out-of-fold, it does not beat raw combine. Drop a season's games, predict from combine alone, and the joint model lands at LOSO rank-correlation 0.32–0.39 versus 0.38–0.49 for raw combine. Its in-sample win was largely same-season leakage. So we report it for what it honestly is β€” better uncertainty and specialist re-rating for mid-board decisions, not a proven predictive upgrade.

The red-teams earned their keep

Every major finding was handed to adversarial reviewers whose job was to break it. They did, repeatedly, and it changed the conclusions:

Four findings were formally revised; several magnitudes were downgraded to "direction only." A backtest scoreboard scores any ranking on realized draft value, with a naΓ―ve combine-greedy board as the bar and a perfect-hindsight oracle as the ceiling. The gap between them is real but β€” same caveat as Β§4 β€” it lives almost entirely in the one clean-linkage season; pooled across the corpus the recoverable per-slot value is a couple of points, not the dozen an earlier draft implied.

11How we'd actually make it better

The model lost to a coin flip. The good news: we know exactly why, and the two biggest fixes are almost embarrassingly unglamorous.

A backtest is only worth running if it tells you what to do next. Ours does, and the punchline is that the fanciest machinery in this whole post β€” the IRT, the hierarchical Bayes, the LMSR β€” is not where the next win comes from. Here's the roadmap, ranked by how much accuracy each lever actually buys.

LeverWhat it fixesAccuracy gainCost
Lean homeΒ§6 under-credits home court56% β†’ 78% SU~free
Know the lineupwho dressed vs who was drafted56.5% β†’ 65.2%collect it
Trust the marketfutures already beat the enginemodestfree
More seasonsthe Β±16-pt error barsslow, only curetime

Lever 1 β€” lean home (nearly free)

Β§6 showed the engine under-credits home court; the season record shows how badly. The model called the home team in just 15 of 36 games β€” it leaned road far too often β€” and 14 of its 16 losses were road picks where home won. Add a single home-nudge parameter (about +0.12 to p_home) and the record jumps from 20-16 to 28-8 (78%) β€” better than blindly picking home, because it keeps the good non-home reads. That Ξ΄ is fit on these same 36 games, so treat the exact 78% with the usual in-sample suspicion β€” and, per Β§6, the true home edge is a modest ~+15 / ~60% (this season only; it was ~zero historically), so the nudge should be small and season-specific, not a permanent constant. But the direction is bulletproof β€” the model leaned road too often β€” and leaning home is the cheapest fix on the board, a recalibration, not a rebuild.

Lever 2 β€” find out who's actually playing (the big one)

This is the lever the whole post keeps circling. Re-run the game model two ways on the games where we know the real dressed lineup: once blind (the full drafted roster, what we had to use) and once with the actual lineup (the oracle). The gap is enormous:

Model inputWin accuracyBrierSpread RMSE
Blind β€” full drafted roster56.5%0.25642.2
Predicted attendance (from history)56.5%0.28942.4
Oracle β€” actual lineup65.2%0.20739.1

Knowing who's in the room is worth +9 points of win accuracy β€” more than the entire ability model contributes β€” and it flips the predicted favorite in 30% of games. But look at the middle row: the model that predicts attendance from history gains nothing (+0.000). Who shows up on a given Saturday is essentially unforecastable from the past. So this ceiling can't be reached by being cleverer β€” only by collecting the data. The single highest-value feature we could add to this entire stack is not a model. It's a pre-game form asking each captain who's dressing.

Levers 3 & 4 β€” trust the market, and wait

The devigged season futures already out-predict the bottom-up engine, and Β§5's Week-3 blunder was dropping that market blend on an in-sample backtest. Fix: raise the market weight and never again cut it on twelve games. And everything here carries a 95% interval of roughly Β±16 points because n = 36; the only real cure for that is more seasons. No amount of modeling cleverness substitutes for the sample we don't have yet.

The humbling summary The two biggest accuracy gains available to a "science-bowl quant" are lean toward the home team and ask who's actually playing. A recalibration knob and a Google Form beat every model in this post. That's not a knock on the models β€” it's the most important thing modeling teaches you: find the lever before you polish the machine.

12What we still don't know

What we don't know, stated as plainly as what we do.

A paper that only advertised its wins would be dishonest about a dataset this small. The load-bearing caveats:

The contribution here is not a single number that wins games. It's a ranked, confound-audited, adversarially-tested map of what a science-bowl season does and doesn't let you know β€” with every magnitude carrying its error bar and every shortcut carrying its caveat. That's the honest version, and it's the only one worth publishing.

13The critics weigh in

We sent the finished post to four hostile readers and told them to break it. They did. Here's the worst of what they found β€” and what we changed.

The statistician "You're rejecting a hypothesis with a test that had almost no chance of detecting it. All-negative out-of-sample RΒ² isn't 'peak is worse than mean' β€” it's an experiment too underpowered to say anything. And 'Brier 0.250 = zero edge' conflates significance with calibration: at n=36 you can't prove it's a coin, and a Brier tie can hide real discrimination β€” which your own next paragraph argues."
Our response: Conceded, both. Β§9 now says inconclusive, not "no," and Β§5 carries the confidence intervals and the calibration-vs-discrimination distinction.
The quant "The candor is asymmetric β€” lavished on the models that failed, withheld from the one number you sell as an edge. Your '13 points per slot' is a one-season, nβ‰ˆ9, in-sample slope; pooled it's ~2.4, and the one independent test of the mispricing is flat null (p=0.95). You disown the shared-PPTF crutch for one number and lean on it for the flagship."
Our response: Fair, and it stung. Β§4 is retitled and rewritten β€” the inefficiency is directional only, the magnitude walked back to ~2–3 points, with the null test stated in the open.
The sharp "The math is honest about being bad; the betting conclusion is missing. Say the words: betting this model lost money. And your 'closing-line value' bot is fake β€” the price drifting to 72% by lock is just the score coming in, against an AMM that can't think, on a stack that never traded a dollar."
Our response: Added the blunt "you'd have lost money" verdict to Β§5, named the 72% ATS home-fade as the actual signal, and deleted the CLV claim from Β§7.
The scientist "Your 'ground truth' is a shrunk, 4-item combine ΞΈ β€” a noisy proxy, not a criterion. A near-zero RΒ² from predicting one noisy proxy with another can't tell you peaks don't reveal ability; it tells you the target is unreliable. And raw Ξ·Β² flatters a factor with hundreds of levels."
Our response: Reframed Β§9 around exactly this β€” the criterion is noisy, the null is attenuated by construction, and the honest claim is narrow and dataset-scoped; the 76/10 split is now flagged direction-only.

None of the four called the paper dishonest β€” the meta-claim ("almost none of this beats a coin flip; trust directions, not decimals") they largely endorsed. What they found is subtler: even a self-critical write-up smuggles its optimism into the one spot it stops checking β€” for us, the draft edge and the peak experiment. The fix, every time, was to go check there too. If this reads as sturdier than the first draft, that's four hostile strangers' doing.