Decision Systems · Data · Python

Fantasy Draft
Decision Engine

A live draft board that rescores 700 NFL players under one league's exact rules, ranks them by what they're worth above a free replacement, and tells you who will be gone before your next turn — built in a single afternoon, hours before the draft.

Shipped before the 6 PM draft Python ESPN API nflverse Chrome DevTools Protocol
700
Players pulled, rescored to league rules, and ranked by value over replacement
5
Real defects caught by automated testing before anyone used it
0$
Paid APIs. Three public data sources, no keys, no scraping
The problem

A 60-second clock and a spec with no numbers in it

The starting point was a 35-section planning document describing how an assistant should think about a draft. It was all process and no data — and its core formula didn't work.

1

The spec had no player data at all

Thirty-five sections of instructions. Zero projections, zero draft-market prices, zero tiers. It told a system how to think and gave it nothing to think about.

2

Its scoring formula was incoherent

It summed tier score, market value, scarcity, roster fit and upside — quantities measured on entirely different scales. Adding them produces a number that means nothing.

3

It never mentioned replacement level

The single most important idea in a draft was absent. Without it, raw projections rank nine quarterbacks in the top ten — in a league that starts one.

4

The build order would have eaten the whole evening

Six phases and eleven modules, with the draft in under three hours. Following it would have produced an architecture and no usable board.

5

Every ranking online is scored for a different league

Public rankings assume full-point receptions and standard roster shapes. This league used half-point receptions and started three receivers. The published numbers were simply wrong for it.

The number that reframed everything

Under this league's exact rules, the 11th-best quarterback projects 299.9 points. Patrick Mahomes projects 299.9 points.

Mahomes is worth exactly zero above a quarterback anyone could claim off waivers for free.

That one comparison rewrote half the draft plan — and no public ranking surfaces it, because it only appears once you score for the specific league you're in.

How it works

Score for the league you're actually in, not the average one

Four scripts and one live page. Every number traces to a timestamped pull, so any board can be rebuilt exactly as it stood.

1

Pull

700 players from a public API — projections, live draft-market prices, injury status.

2

Rescore

Apply the league's exact rules. Half-point receptions and 4-point passing touchdowns change every ranking.

3

Value

Measure each player against the last startable player at his position in a league this shape.

4

Tier

Break groups at real scoring cliffs, not fixed buckets. The cliff is what forces a decision.

5

Decide

One recommendation, in plain words, with the odds he survives to your next turn.

Value over replacement

A player is only worth what he beats the person you could have had for nothing. Under this roster shape that line falls at QB11, RB25, WR36 and TE12 — and measuring against it reorders the entire board.

Survival odds

The useful question on the clock isn't "who is best." It's "who will not be here at my next turn." Each player carries a probability of lasting that long, derived from where the market drafts him.

Plain-language context

Built for someone who doesn't follow the sport. Every player carries what he actually did last season — catches, yards, share of his team's plays — so a name is never just a number.

Three free sources

A public projections API, an open play-by-play dataset, and a public trending-adds feed. No paid keys, and nothing scraped from a site whose terms forbid it.

What I learned building it

The tests found things the reasoning missed

Thirty-eight automated checks, nine browser passes driving a real Chrome window, and one adversarial review. Five genuine defects surfaced — and not one was a crash.

Unit tests were not enough

Thirty-three assertions passed and a screenshot looked clean while three real bugs sat in the build. They only appeared by clicking through the actual sequence a person performs.

The interface contradicted itself

A warning correctly said "you still need a kicker" while the recommendation card suggested a running back. A first-time user follows the card. Two halves of one screen, disagreeing.

Well-formed output hid a dead field

Every kicker and defense scored exactly 0.0, because their statistics live under different identifiers. The screen displayed a computed-looking zero. Nothing was broken; it was simply never calculated.

A rebuild silently erased context

Running the data step alone wiped the descriptive text from all 534 players. The page still rendered perfectly, just blank. The fix was making it impossible to ship quietly.

The formula counted the same thing twice

Value over replacement is a scarcity measure. Adding a second scarcity term on top double-counted it, and a one-man tier outranked players worth ten points more. Every test still passed.

Never assume an unverified input

The draft position came from one line in a planning note and was never confirmed. It turned out to be wrong. Making it a control instead of a constant meant the correction took two seconds, not a rebuild.

What came next

The draft was one head on the data spine

The pipeline that scores a draft also scores a waiver wire, a weekly lineup, and a trade. Same engine, different question.

Shipped · Waiver report

Scores the free-agent pool against this roster's actual holes using weekly opportunity trend, league-wide claim volume, and upcoming bye exposure. Because waiver priority is a one-shot resource, it says when to spend it, not just who is good.

Next · Weekly lineup call

Flags the start-or-sit decisions where the gap is under two points, so the choices that don't matter stop consuming attention.

Next · Playoff planner

Schedule strength across the roster for the three playoff weeks, surfaced before the trade deadline rather than after it.

Reusable · Browser test harness

A zero-dependency rig that drives any local page in a real browser with real mouse events, using the runtime's native WebSocket over the Chrome DevTools Protocol. No framework required. It now tests other client deliverables.

Why this generalizes

Strip out the sport and the shape is familiar: what is this worth above the alternative I could have for free, how fast is the opportunity disappearing, and what does waiting cost me?

That's inventory. That's hiring pipelines. That's capital allocation. The engine doesn't care that the rows happen to be football players — it cares that the scoring rules are specific, the supply is finite, and the clock is running.

Try it

Open the board and take a pick

The real tool, running on real 2026 projections. Click any player to take him off the board and watch the recommendation, the tier counts, and the survival odds all recalculate.

1 · Remove a few players

Click rows in the table the way you would when other managers draft. The counter at the top moves and the board rethinks itself.

2 · Read the green card

It names one player and says why in plain words — which hole he fills, how far he has fallen, and who you drop to if you wait.

3 · Change the draft slot

Set "I pick" to a different position. Every pick number, survival probability and recommendation recomputes for that seat.

4 · Toggle QB discipline

Turn it off and watch an elite quarterback climb the board. That switch exists because the model and the analysis genuinely disagreed.

Open the live board →

Nothing is saved anywhere but your own browser. Refreshing gives you a clean board.