The Edgework value model gives every on-ice action a goal-value — by how much it shifts the odds of the next goal — then sums those values per player. It adapts VAEP, an action-value framework from soccer analytics, to hockey, and splits the result by rink zone. The payoff is a defensive metric that repeats year over year better than the expected-goals-against rate every public model uses.
The only test that matters for a player rating is whether it predicts the future. We measure that with year-over-year persistence: rate every player in season T, again in season T+1, and correlate the two. A metric that repeats is a metric that forecasts.
Our defensive-zone contribution rate (v_in_dz_per_60) repeats at 0.54 and 0.60 across the two season-pairs we can measure. The standard public defensive metric — on-ice expected goals against (xga_per60_on_ice) — repeats at only 0.42 and 0.37 over the same pairs. Our action-credited defense is a stronger predictor of a player’s future defense than the rate everyone else cites.
The full table is in Validation below. The sections in between explain how each metric is built, at an intuition level.
Everything starts from the NHL’s public play-by-play feed — the recorded stream of shots, hits, faceoffs, takeaways, giveaways, blocks, penalties, and goals, with coordinates and game state. Two foundation models read that stream. An expected-goals model scores every unblocked shot by quality alone — location, angle, rebound, rush — deliberately ignoring who took it, so shooter skill is measured later rather than baked in. A pair of state-value models then estimate, from the game state at any moment, the probability the team scores — or concedes — within the next ten events.
Action value is the change in those probabilities across each event, credited to the player who caused it. A dangerous shot that raises scoring odds earns positive value; a turnover that raises the opponent’s odds earns negative value. Goals carry a realized +1 reward split across the scorer and assisters (0.55 / 0.30 / 0.15), so playmaking is credited, not just finishing.
Each action happens somewhere on the ice, so its goal-value is filed by zone from the acting player’s perspective: offensive, neutral, or defensive. Summed over a season and divided by 5v5 ice time, that yields a per-60 rate for each zone. v_in_oz_per_60 measures offensive-zone contribution — the value a player generates attacking; v_in_dz_per_60 measures defensive-zone contribution — value generated defending, including credit for blocked shots.
The defensive rate is the model’s headline: it lands in the skill-stable 0.40–0.65 persistence band and out-predicts the public xGA rate. The offensive rate persists higher (0.86) but is honestly role-confounded — offensive deployment (who gets the offensive-zone starts and the minutes) is itself extremely sticky season to season, so the offensive number repeats partly through usage rather than isolated skill. Read it as informative, not pure.
v_net_per_60(Net Contribution) is a position-adjusted, weighted z-score index. Its base is a player’s offensive-zone value (60% weight) and defensive-zone value (40% weight); as of 2026-06-12 (v2 — see the changelog) the published number blends that zone composite with a chance-creation-for-others term: net = 0.9 · z(0.6 · z(OZ) + 0.4 · z(DZ)) + 0.1 · z(C1), where C1 is the chance-creation-for-others RAPM described below. Each component is measured as standard deviations above or below the average for that position-and-season cohort, then combined. The asymmetric zone weighting reflects that offensive actions generate more total value per minute in hockey, while still giving defensive performance enough weight to materially affect rankings. Pure offensive stars rank near the top; elite two-way players — defensemen who drive offense, forwards who defend — surface high; pure defensive specialists rank in the middle, because their offensive contributions are below the cohort average. The result is a relative index (it carries a + or − sign), not a count of goals.
One framing matters when reading net against the scoring race: net is a strength-matched 5v5 rate— 5v5 value over 5v5 ice time. That is deliberate: 5v5 rates are what repeat year over year (the validation table below is built on them), while power-play production rides heavily on deployment. The cost is that all-strength value — a power-play playmaker’s specialty — is out of the headline number’s scope by design. So the leaderboard and player pages show v_total_season(“Season impact”, cumulative action value across all strengths) alongside net: a player can lead the league in season impact while sitting mid-pack on the 5v5 rate, and both statements are true at once.
The goals companion. Under the Net Contribution headline the player page shows a plain-language conversion: “≈ +X goals vs positional average at 5v5”. It is the rate-times-time algebra on the same underlying quantities — ((OZ/60 + DZ/60) − cohort average) × 5v5 TOI — so it prices a player’s 5v5 zone value in goals against the average player at his position, over his own minutes. What it excludes, deliberately: the chance-creation (C1) term, which is an xG-rate coefficient with no goals identity, and everything outside 5v5 — all-strength goal value lives in Season impact. And one approximation is owned: the companion weights offense and defense equally in goal units, while the z-score headline weights them 60/40 in standardized units, so the two can order players slightly differently. The baseline is the positional average, which means roughly half the league’s companions read negative — that is the honest arithmetic of an average baseline, not a defect.
Goals to wins. The secondary phrase (“~Y wins”) divides the goals figure by ≈5.9 goals per win — measured, not folklore: perturbation experiments in our own season-simulation engine (shifting a team’s scoring environment by ±0.05 and ±0.10 goals per game and simulating full seasons at the frozen, validated parameters) put one win at 5.75–6.05 goals of goal differential across strong, median, and weak teams. The classic rule-of-thumb of ~6 happens to be right; we cite our measurement of it.
The same per-action value also splits by what the player did. v_from_shots is sniping value — value created by taking shots and scoring. v_from_assists is playmaking value, the assist share of goal credit; because the play-by-play feed records no passes, assists are the only window into setup work, so crediting them separately keeps playmakers from being under-rated. v_from_blocks is pure shot-suppression value: a blocked shot earns the blocker a small fixed credit (about the average quality of the attempt it prevented), defensive value a shot-only model never sees.
Action value only sees the player who touched the puck. RAPM — Regularized Adjusted Plus-Minus — is the complement: a ridge regression over every 5v5 shift that isolates each player’s per-60 impact on expected goals while controlling for the quality of teammates and opponents on the ice with them. rapm_net is their net effect on expected goals for minus against.
Single-season RAPM is noisy — one season is not enough lineup variety to separate players who are almost always on the ice together — so the production metric pools multiple seasons of shifts into one regression. Pooling lifts stars who were collinearity-bound (McDavid climbs roughly 25 spots across two seasons of pooling), but it does not fully resolve players whose linemate pairings barely change year to year. Treat rapm_net as a useful, regression-isolated second opinion, not a final word.
Goalies are rated by Goals Saved Above Expected. Sum the expected-goal value of every unblocked shot a goalie faced, subtract the goals they actually allowed, and the residual is performance above (or below) what an average goalie would manage on that shot load. Because the expected-goals model is shooter-agnostic and calibrated over the full shot universe, the league average sits at zero, so positive GSAx is genuinely above-average.
Small samples — backups, call-ups — can post wild rates on a handful of starts, so the production figure (gsax_shrunk) is pulled toward the league average by a Bayesian weight: a goalie’s raw GSAx is scaled by shots / (shots + 200). A goalie with thousands of shots is barely moved; one with a few hundred is regressed hard toward zero.
Every metric below is a strength-matched 5v5 per-60 rate, correlated between the 2023-24 and 2024-25 seasons across the 602 players with at least 200 minutes of 5v5 in both. We read the result in three bands: below 0.30 is noise; 0.30–0.65 is skill-stable (real signal that persists); above 0.85 is role- and usage-confounded (it measures sticky deployment more than individual skill).
| Metric | Pearson | Spearman | Q4 persist | Reading |
|---|---|---|---|---|
| v_score_delta_per_60 | 0.936 | 0.923 | 0.90 | Math component of state-value change — tracks role/usage, not skill |
| v_concede_delta_per_60 | 0.928 | 0.792 | 0.58 | Math component — role/usage, not skill |
| vaep_per_60 | 0.876 | 0.876 | 0.71 | Total action rate — role/usage-dominated |
| v_in_oz_per_60 | 0.855 | 0.852 | 0.65 | Offensive-zone contribution — role-confounded but informative |
| xgf_per60_on_ice | 0.629 | 0.567 | 0.55 | Public on-ice xGF — the cleanest repeatable public skill signal |
| v_in_dz_per_60 | 0.537 | 0.525 | 0.50 | Defensive-zone contribution — skill-stable, and beats public xGA |
| v_in_nz_per_60 | 0.459 | 0.359 | 0.44 | Neutral-zone contribution — skill-stable, no public analog |
| xga_per60_on_ice | 0.421 | 0.425 | 0.47 | Public on-ice xGA — the standard benchmark v_in_dz beats |
| rapm_net | 0.313 | 0.269 | 0.42 | Single-season RAPM ≈ the raw control (noise-bound) |
| goal_share_5v5 | 0.311 | 0.314 | 0.42 | Raw 5v5 on-ice goal share — the control |
| rapm_off | 0.268 | 0.243 | 0.36 | Below 0.30 — noise |
| rapm_def | 0.147 | 0.120 | 0.31 | Individual defense barely repeats year to year |
The two all-strength delta components are omitted; the strength-matched 5v5 columns shown are the primary skill-comparison rates.
v_in_dz_per_60 (0.54) clears the public on-ice xGA benchmark (0.42) — and on the second, noisier season-pair (2024-25 → 2025-26, measured on the complete recovered 2025-26 season with real full-season ice-time denominators) the gap widens to 0.60 vs 0.37. Single-season RAPM, by contrast, barely matches the raw goal-share control, which is exactly why the production RAPM pools seasons. The math components near the top of the table (0.93+) repeat because they track role and usage, not because they are the best player ratings — read them with that caveat.
The model is honest about what it cannot see. The most important constraints:
The NHL feed records discrete events — shots, hits, faceoffs, takeaways, giveaways, blocks, penalties, goals — but no passes, controlled zone entries, zone exits, or sustained possession. So the model cannot directly credit the cross-ice feeds, carries, and entries that drive much of elite-player value. Assists are the only proxy for playmaking, and the partial divergence between action value and RAPM is one symptom of this blind spot. The same constraint cuts on defense: positioning, gap control, and lane denial that never produce a recorded event are invisible to action data, so defensive-zone value rewards players who defend by doing recordable things (blocks, takeaways) over those who defend by being in the right place. Closing either side would need tracking data (NHL EDGE) or licensed microstats.
Because no passes are recorded, the value of an unconverted scoring chance goes entirely to the shooter; playmakers are credited only when a chance becomes a goal. We built and tested the obvious repair: redistributing part of each chance’s value to teammates whose recorded actions (takeaways, earlier shots) built the possession. Candidate parameters were evaluated blind against a pre-registered two-part test, with bootstrap confidence intervals on every comparison: the adjusted metric had to predict the next season’s on-ice goal differential at least as well as the unadjusted one, and had to improve year-over-year repeatability by a margin set before any results were seen. It passed the first part — the adjustment carried a real but tiny predictive gain, about +0.002 correlation — and failed the second outright: repeatability slightly declined rather than improving. It was rejected under that pre-set bar. The per-event credit asymmetry itself still stands and is not repaired here, pending passing or tracking data. A separately-constructed term — chance-creation RAPM (C1), evaluated the same blind way — cleared its out-of-sample prediction bar and ships in the net definition; see “Chance creation for others (C1)” below. It earns its place by improving prediction, not by repairing per-event shooter credit. One experiment rejected, one shipped, under the same pre-registered standard.
Players who share almost all of their ice time cannot be cleanly separated by the regression. The canonical case is McDavid and Hyman in Edmonton, on the ice together for roughly 85% of their 5v5 minutes year after year; some of McDavid’s credit leaks to his linemate. Pooling seasons reduces this but does not eliminate it.
Goalie GSAx barely repeats season to season (persistence near zero on adjacent seasons with a high shot floor). This is largely real — goaltending is genuinely volatile, the qualifying sample is small, and our shot model has no traffic/screen features — so single-season GSAx is descriptive, not a projection.
The 2025-26 regular season is complete and was promoted out of provisional status on 2026-06-12. Two facts worth keeping on the record. First, the NHL’s JSON feed remains permanently missing shift charts for 505 of 1,312 games — re-checked at the source after season’s end; those shifts were recovered in full from the league’s legacy HTML time-on-ice reports, validated with an exact per-shift match against the JSON feed on games both sources carry, so every 2025-26 metric is built on complete, real shift data. Second, the season’s expected-goals model failed our strict held-out calibration gate (−5.2% on the final tenth of the season) — we investigated rather than waved it through. Full-season calibration is −0.5%, comfortably inside our ±2% standard; the miss is confined to the temporal tail, where league scoring jumped about 7% relative to the rest of the season, with no concentration by team, arena, or feed era. That is a genuine scoring-environment shift the gate punishes by construction, not a data defect — so the season ships as stable with this deviation documented instead of hidden. The gate design itself is queued for review before the 2026-27 build, since it currently cannot distinguish calibrator failure from real late-season scoring drift.
Our action values are built from NHL play-by-play, which records shots but not passes — every non-goal scoring chance is credited entirely to the shooter, and the pass that created it is invisible. That per-event asymmetry is a structural limitation we keep on the record. C1 is not a proven fix for it: it ships because it improved out-of-sample prediction under a pre-registered blind test — the same standard as the rejected chain-credit experiment — not because a playmaking deficit in Net has been demonstrated.
C1: chance creation for others. Standard RAPM asks: when this player is on the ice, does his team generate more expected goals? C1 asks a sharper question: when this player is on the ice, do his teammates — excluding the player himself— generate more shot quality? Every 5v5 stint (a stretch with both lineups unchanged) is expanded ten ways, once per skater. In the copy where a given skater is the “focal” player, the target is the expected-goal total of shots taken by the other four teammates, and the focal player’s own column is zeroed out. A ridge regression over ~1.35 million such rows then estimates each player’s marginal effect on teammates’ shot quality — chance-creation influence with the player’s own shot volume removed by construction. (Without the focal exclusion, the design collapses algebraically into ordinary offensive RAPM.) C1 is moderately related to offensive RAPM (r ≈ 0.55–0.68 across seasons, far below our pre-registered 0.85 redundancy threshold) and repeats within a season at a split-half reliability of ~0.60 after Spearman-Brown adjustment, in all three seasons tested.
This is distinct from the “Playmaking” figure shown on the leaderboards and player pages: that one is realized assist credit (the share of a player’s goal value coming from his actual primary and secondary assists), whereas chance creation for others is a regression-isolated estimate of how much a skater lifts his on-ice teammates’ shot quality, whether or not it ever shows up as a recorded assist.
The blind test and what shipped. Every decision was registered before any result existed. The candidates: the current net definition (baseline), C1 alone, and small fixed blends (10/20/30% C1, plus two variants adding box-score primary assists). The criterion: cross-prediction of next-season on-ice 5v5 goal differential per 60, over two season pairs, with bootstrap confidence intervals — the same out-of-sample standard everything else on this page is held to. The ship bar: at least +0.010 pooled improvement over the baseline with the confidence interval excluding zero, no degradation on a secondary team-level check, and — among everything that cleared — the smallest admixture wins. No names, no ranks, and no player-level numbers were examined until the choice was frozen from the aggregate table. Every blend cleared the bar; the smallest-weight rule selected the 10% blend now published as net v2 (formula above). C1 alone predicted worse than the existing net — it is a complement, not a replacement, which is exactly what a small admixture is for.
External validation against tracked passing — including the miss. We also tested C1 against ground truth it was never trained on: All Three Zones’ manually tracked passes that lead to shots (“shot assists”), a few hundred games per season. We registered one validation variable (primary shot assists per 60 of tracked 5v5 time), one coverage floor, and one bar — pooled Spearman ≥ 0.50 with the confidence interval excluding 0.30 — before computing anything, with no alternative columns permitted regardless of outcome. The result: pooled Spearman +0.479, CI [+0.441, +0.518], across ~1,580 player-seasons (per season: +0.53 / +0.42 / +0.49). The interval excludes 0.30 decisively — C1 genuinely tracks real passing — but the point estimate missed our bar. By the registered rule, C1 therefore does not ship as a standalone chance-creation metric; it ships only inside net v2, where its predictive value was established directly. For context, raw primary assists per 60 correlate at +0.621 with the same tracked-passing variable on the same panel — unsurprising, since both are realized-pass counts, while C1 estimates on-ice influence(pre-pass movement, retrievals, and sequence play that tracking attributes to no one). We report the miss rather than re-litigating it, and we deliberately call C1 chance creation rather than playmaking: the validation shows it tracks real passing only moderately, because it measures the on-ice lift in teammates’ shot quality however it arises, not realized passes. One re-test is registered for when fuller tracking coverage publishes; the spec is frozen.
The entanglement caveat. RAPM-family estimates separate players by seeing them in different lineups. A handful of pairs are nearly inseparable — skaters sharing more than 90% of their 5v5 minutes (permanent lines and defense pairings; roughly 5–10 pairs per season). For those players, C1’s split of chance-creation credit within the pair is statistically under-determined, and the 10% C1 component of net v2 should be read with that grain of salt. The affected pairs move very little under v2 in practice (within about ±4 ranks in almost all cases), but the caveat is structural and we flag it rather than hide it.
The contracts page asks a different question: what does the marketpay for what this player produces? For each position group (forwards, defensemen) we build the market’s own pay curve — every market-priced contract in the panel, sorted by restated cap hit — and sort the same players by production value. A player’s fair value is what the curve pays at his production percentile, and surplus = fair value − restated cap hit— positive is a team-friendly deal, negative is an overpay. That makes the board’s natural sentence the method itself: “produces like the #3 forward, paid like the #13.”This rank-to-rank map replaced an earlier linear regression of cap hit on value (see the changelog): a straight line under-prices the market’s steep top — the pay gap from the 90th to the 99th percentile is roughly 5× the mid-curve slope among forwards ( 3× among defensemen) — so the old fit billed elite-percentile stars for curvature the market actually pays, and could never price the top of the market at all.
The value ordering is a recency-weighted (5:3, two seasons) blend of the all-strengths total action value — the same metric as the leaderboard’s “Season impact” — expressed as a z-score vs position peers. It replaced an earlier 5v5-only input (see the changelog): the market demonstrably prices special-teams production, so a 5v5-only ordering systematically read power-play-heavy stars as overpays. A property of the rank map worth stating: because only the ordering of players enters the model, the choice of value metric matters less than it did under the regression — re-scoring with a raw goals-unit blend instead of the z moves fair values by a median of $0.08M (surplus correlation 0.996). One honest caveat carried from the metric itself: season totals repeat partly through stable deployment, and a contract market pays for exactly that usage-plus-production bundle.
Cap-era restatement. Nominal AAVs from different cap eras are not the same money. Drew Doughty’s $11M, against a $79.5M Upper Limit, consumed 13.8%of his team’s cap — the same nominal figure today would consume 10.6%. So before anything meets the curve, every AAV is restated to current-cap (2026-27) dollars by the ratio of today’s cap to the cap of the season the deal takes effect: Doughty’s deal meets the curve at $14.4M, not $11M. All surplus dollars on these surfaces are current-cap dollars, and every card shows the chain — nominal AAV, share of cap at signing, restated AAV — so the arithmetic visibly adds up.
Why the effective season, not the signing date. A cap hit is money spent in a season, so the ceiling it should be measured against is that season’s. The signing date is only a proxy for that — a good one when a deal is signed and takes effect in the same league year, and wrong by a whole cap era when it is not. This replaces an earlier signing-year convention that carried a standing caveat, and the caveat turned out to change a headline rather than a decimal: Kirill Kaprizov’s $17M, signed in September 2025 but effective 2026-27, was restated against the smaller $95.5M cap it was signed under and so read $18.5M — enough to rank him above Leo Carlsson’s $18M, which is in fact the largest cap hit in the NHL. Measured against the season it is actually paid in, Kaprizov’s deal reads $17M and the order is right. The same correction moves every signed-but-not-yet-effective extension onto the $113.5M2027-28 ceiling it will actually be paid under rather than the $104M one it was signed beneath — Cale Makar’s extension meets the curve at $18.7M, not $20.4M. Each contract’s effective season is read from the contract itself; every scored deal on the current board carries one, with the signing date kept only as a fallback.
What the surplus model is measuring: an established level, on purpose. The value ordering blends the two most recent seasons (5:3) rather than reading only the latest one, because a contract is a multi-year bet and the thing worth pricing is the level a player has established, not the form he is in. A pure recency read would be the right choice for a projection; this is not a projection, and the two questions have different right answers. The consequence is visible and intended: a player can rank higher on a single-season leaderboard than on this board, and neither number is wrong. Leo Carlsson is the clearest case — #49 of 249 forwards on 2025-26 Season impact, and roughly #62of the 250 priced forwards over two seasons, because an earlier below-average season is still in the blend. Every surplus surface therefore names the metric and shows the single-season reading beside it, so the gap reads as the model’s design rather than as a contradiction.
Why two seasons and not three. The blend used to reach back three seasons (5:4:3). It stopped at two because a third season back was pricing a level players had already left: with 2023-24 still in the window, Carlsson read #121of 314 forwards while his two most recent seasons put him at #79 — the market pays for what it has seen lately, and a curve that argues with it from three years back is measuring the wrong thing. The cost was measured before the change and is accepted: re-scoring last season’s board, verdicts flip about 30% year over year under the two-season blend against 20% under three, so the board is a little noisier, and says so. Two seasons is where the trade sits — an established level, without a stale one.
Why growth deals are labeled rather than fixed. This is also why the board labels growth deals instead of quietly forgiving them. A long-term contract signed before age 24 is priced on a trajectory the team expects — and this model deliberately does not price trajectories. So it scores those deals against the same curve as everyone else, reports the (often large) negative that follows, and marks the row so the reason is legible: the gap is not a claim that the team blundered, it is the distance between what a player has established and what he was paid to become. Those cards show the two seasons behind the blend for exactly that reason. The one exception is registered and narrow — a top-of-market deal on a player already producing at top-of-market level is the market speaking, not a projection, and is admitted to the curve.
The curve population. The pay curve is built only from market-priced deals: contracts signed as UFAs, plus RFA deals that are not growth-priced. Two classes are excluded from the curve itself — entry-level contracts, whose price is set by CBA rule, and growth deals (long-term deals signed before age 24, the young max-extension class), whose price is set on the player a team expects rather than the one it has. A curve meant to read the market’s price for current production should not be taught by prices the market never set. Both classes are still scored against the curve — everyone gets a number — and carry a label instead of a filter (next paragraph).
What “structural” means. A surplus figure on an entry-level or growth deal is real money, but it is not a GM outsmarting the market — it is the CBA’s pricing rules (or a projection bet) showing at full size. Those rows are labeled: structural — entry-level for ELC players (an ELC star can show a double-digit surplus; that is the point of the label), and growth deal — priced on projectionfor the young max-extension class (they read negative against current production by design — the production hasn’t arrived yet; that is a statement about today, not a verdict on the bet). Market-priced rows carry no label.
Smoothing and the anchored top. Raw percentile curves are jagged at a few hundred contracts, so the body of each curve is smoothed (a ~5% rolling window, kept monotone). Smoothing alone, though, drags the very top of the curve down toward the pack — which would make the league’s #1 producer read as an overpay purely by construction. So the top of each curve is anchored to what the market actually pays its top contracts: the last few percentiles ramp into an anchor set by the average of the top three restated cap hits in the group. The very best producers are priced at the market’s real ceiling, not a smoothed echo of it.
Fair value is capped by the market’s observed maximum, which the CBA bounds. A player’s fair value can never exceed the largest cap hit the CBA permits — 20% of the Upper Limit, or $20.8M in 2026-27 — because the pay curve is built from contracts that are themselves bound by that rule; surplus for the very best players is therefore understated by construction, and a player who produces at the top of his position group will read at or near “market rate” no matter how far ahead of the field he is.
Extensions enter the curve when they are signed, not when they take effect. A signed extension is a market price the moment it is agreed, so it joins the pay curve immediately (restated to current-cap dollars using the cap in force at signing), while the player continues to be scored against the cap hit he actually carries this season — so a player on a modest current deal with a large extension already signed reads as a bargain today and re-prices when the extension begins. An extension is judged by the same growth-deal rule as any other contract, at its own signing date, so a long deal signed by a very young player stays out of the curve. One exception: a young player’s max-priced deal counts as a market price when he was already producing at (or within a rank-notch of) the level that price implies at signing — a top-of-market deal on a top-of-market producer is the market speaking, not a projection.
What surplus does not price. The model prices current production in today’s cap dollars only: no term structure, no projected growth, no negotiation or marquee premium — and, stated plainly, no aging control. The old regression carried a small signing-age term; the rank map deliberately does not, so a 35-year-old producing like a top-10 forward is priced like a top-10 forward. That is consistent with “prices current production” — read an aging star’s bargain as today’s snapshot, not a projection of the deal’s remaining years. The per-player PP share still appears in board tooltips as information; special-teams value is in the ordering.
The market-rate bands. Every contract is classified by its surplus into a triptych: ≤ −$1M reads overpaid, ≥ +$1M reads underpaid, and anything in between reads market rate — priced about where the market pays that rank. The thresholds are in current-cap dollars, like the surplus itself. When the model changed, the threshold was re-derived on the new residual distribution rather than carried over blind — the coverage-matching cut came out at $1.05M, so the $1M figure stood. The bands are display classification only; a gap inside ±$1M is within the model’s noise and is not asserted as a verdict either way.
The bargain floor. The market genuinely pays a median-rank skater several million dollars, so a league-minimum depth contract shows positive surplus under any honest pricing — without a floor the “bargains” board would be dominated by minimum-salary bodies. Headline bargains must therefore clear both an AAV floor ($1.5M) and a value floor (0.25 SD above positional average on the Season-impact z), applied within the underpaid band. Every player keeps his computed surplus; the floor only governs the headline bargain board. The overpay board lists the whole overpaid band by magnitude — no value filter, so the star-contract negatives stay visible. The snapshot is hand-maintained, refreshed manually rather than nightly.
The projections board and the team-page projection panels show a projected 5v5 zone-rate value vs position peersfor the upcoming season, built from each player’s prior seasons and age curve. Zero means positional average; the number is a per-60 rate, not a season total.
Not total player value. Like the headline net metric it projects, this is 5v5-only by design — a power-play-driven or heavy-usage star can rate below average here while remaining an elite overall contributor. (The contract-surplus model once shared this blind spot; it now prices all-strengths production — see the changelog.)
The Goals toggle on projection surfaces. Goals mode prices the projected σ value with the goals companion’s own quantities: each position cohort’s goals-per-60 per σ of net, fitted on the 2025-26 season (the two are nearly collinear — the map is faithful), times the player’s 2025-26 5v5 ice time — a prior-season TOI basis, labeled on the surface, because the projection bundle carries no projected TOI. Players without a prior-season TOI show no goals figure rather than a guessed one. The two units can order players differently because goals price σ by ice time — the toggle sorts each board by whichever unit is shown.
A projection, not a proven forecast. It beats naive carry-forward decisively, but its edge over the existing stability blend is unproven at one fold — the 2026-27 season resolves it. Until then, read projected values as the model’s best estimate, not a validated forecast.
The Tonight boardand the player-page “Tonight” line show projected shots on goal for tonight’s games: an expected-SOG figure per skater plus the probability of reaching 2, 3, or 4 shots. Three drivers compose it — the player’s recent per-minute shot rate (shrunk toward league rates by strength state), a projected deployment (ice time from recent usage, line/pair slot, and power-play unit), and the opponent’s shots-allowed rate.
Explicitly not a betting product. This model was developed inside a pre-registered research protocol whose betting question is answered and closed: in registered backtests against real DraftKings lines, the model does not beat DraftKings closing lines — the original gate and three successor hypotheses (honest calibration + selectivity; deployment-aware ice-time projection; predicting the close from the early line) all failed their pre-registered bars, and the close proved ~99% unexplainable by anything the model can know on the morning of a game. What ships here is the descriptive by-product: the projection itself, with honest uncertainty.
Calibrated uncertainty.The confidence tags come from a registered segment-calibration study on held-out data: forward projections are well-calibrated (predicted vs realized P(2+/3+/4+) within ~1–2 points); defensemen run slightly optimistic, worsening down the lineup — third-pair projections carry the widest tag. Early in a season, players without a recent usage history show a “thin data” tag and lean on position averages.
The projected standings are a true forward forecast. Team strength is composed from the current roster: each rostered skater carries his projected value (the same Marcel-plus-age-curve projection behind the player projections), weighted by expected ice time from his prior-season minutes, with an 18-skater dress cut; rookies and other players with no projectable history enter at a stated replacement level rather than being silently dropped. Goaltending enters as a start-share-weighted tandem of multi-year shrunk GSAx. Each game of the real schedule gets a win probability from that strength gap, and the season is simulated thousands of times: the headline is median projected points, the bar is the P10–P90 range. Because the input is the roster, the forecast updates when rosters move — trades and signings show up at the next refresh (weekly until puck drop), stamped on the page.
Anchored to last season’s results. The roster-composed strength is a per-minute average of projected 5v5 value: on its own it rewards a roster with no weak regulars over a stars-and-holes roster, and it says nothing about special teams. So it is shrunk toward each team’s actual points from the most recent completed season— a regression toward what teams have actually done. The blend weight is not eyeballed: it is calibrated out-of-sample, choosing the mix that best predicts the following season’s point totals across the seasons available (a roughly 60/40 tilt toward the roster model). The effect is to pull teams whose recent results diverged from their roster profile back toward their results, while still letting a genuinely improved or declined roster move.
The goalie weight, honestly. Goaltending is the input that most decides a single game and the least predictable thing we measure year over year, so a predictive model must down-weight it — it enters at a weight of about 0.065, reflecting its measured reliability. The consequence is owned rather than hidden: teams whose recent point totals were driven by elite goaltending project lower here than their standings history suggests. When such a team’s goaltending repeats, this forecast will have been wrong about them — that is the position the model takes, on the record, rather than quietly trusting the least repeatable signal in hockey.
Point ranges are compressed by design. The model separates teams conservatively — a measured low-discrimination property of the underlying game model — so a tight league spread reflects the model, not a lack of confidence. Forecast probabilities are tracked against results on the calibration curve: they follow the predicted line, with a disclosed mild over-confidence in the 0.6–0.8 band. The roster-composed strength was backtested through the same harness (playoff-odds log-loss 0.4243 vs the prior chain’s 0.4372) — with a stated caveat: historical “preseason rosters” were approximated from each season’s early dressed lineups, a mildly hindsighted proxy, and the 2026-27 season is the registered binding test.
Measured against the betting market.In a registered evaluation on 631 games (Oct–Dec 2025, eleven US books), the engine’s win probabilities scored a log-loss of 0.693 against the closing market’s 0.685 — a paired-bootstrap difference whose 95% CI spans zero, i.e. statistical parity with the closerat that sample size (and clearly ahead of an Elo baseline at 0.702). Opener-CLV in the same evaluation read favorably but is flattered by construction — the engine’s inputs include the dressed lineup and starting goalie, which the noon market does not yet know — so it is reported, not claimed. One defect is on the record as a known issue: the engine runs ~5 points over-confident on home favorites in the mid-probability bins (the same home-lean visible when 2025-26’s home-win rate sagged), and a home-shrink recalibration check is queued for the 2026-27 data unlock.
Seed vs playoff odds. Seed is a league-wide points ranking; playoff odds fold in each team’s division and wild-card path — so a team can seed above another yet carry lower playoff odds.
The score layer (2026-27 forward). The forecast now simulates scores, not just winners. Win probabilities are unchanged — the fitted win-probability link retains sole authority over who wins each simulated game, an identity verified to machine precision when the layer shipped. Beneath that, a separately validated score layer generates each game’s margin and goal totals conditionally on the drawn outcome, and a calibrated empty-net application then adds the late empty-net goals real games contain — so the projected GF / GA / GD columns are comparable to official NHL totals (empty-net goals are about 6.5% of all goals, roughly 16 for and 16 against per team over a season). Standings order is resolved by the NHL’s own tiebreak chain — head-to-head record before goal differential — computed on those simulated, empty-net-applied scores, replacing the earlier stand-in that broke median-point ties by mean points. All totals are stated over the full 84-game 2026-27 schedule.
One-time shift at switchover, on the record. When the score layer shipped, projected points moved up by roughly 1.5–2 league-wide against the prior week’s table. That shift is a tie-rate correction, not a team-strength change: the earlier tie layer used an overtime/shootout rate pooled over 2023-24 and 2024-25 (about 0.213), while the score layer’s adaptive target starts each season at the most recent completed season’s actual rate — 0.2485 per 2025-26 — and more overtime/shootout games mean more loser points for everyone. No team’s strength, win probability, or relative standing moved from this correction; bubble-adjacent seeds that changed did so because real tiebreaks replaced the mean-points stand-in.
What the player-page Linemates section measures. Linemate strength is seconds of shared 5v5 ice time between a player pair — the overlap of shift intervals, strength-filtered to true 5v5 (five skaters a side, both goalies in net). Not points, not shift counts, not event co-occurrence: actual shared seconds, computed from the NHL’s shift-level data.
Windows are the player’s own games. The selector offers the full season, the player’s last 10 games, and last 5 — and defaults to the last 10, because a full-season view blends line shuffles away; the recent window is what “current linemates” actually means. The percentage next to each linemate is the share of the player’s own 5v5 ice time in that same window they spent together.
Display rule. Forwards show their top 5 forward linemates and top 3 defensemen; defensemen show their top 3 D partners and top 5 forwards — ranked by shared seconds, nothing curated.
Data. The 2025-26 regular season — 1,311 of 1,312 games (one game produced no valid 5v5 segments and is excluded). Shift coverage is complete for the season: the mid-season gap in the NHL’s JSON shift feed was recovered in full from the league’s legacy HTML time-on-ice reports. The section will track 2026-27 once the new season’s games exist.
What the Trends page shows. Recent, statistically unusual changes in how a player is being used and how they are performing, each rendered as one sentence from a fixed template and backed by a game-by-game chart. Five families: linemates(share of a skater’s own 5v5 ice spent with a teammate — the same shift-interval overlap as the Linemates section), ice time (all-situation minutes per game, with 5v5 alongside), power play(share of the team’s man-advantage seconds the player is on the ice for), offensive impact (5v5 offensive-zone action value per 60 — the same channel as v_in_oz_per_60, recomputed per game), and shot volume (individual 5v5 shot attempts per 60). Every sentence describes what is recent. Nothing on that page is a forecast.
Windows and baselines. The recent window is the player’s last 5 games with 5v5 ice (3 for the power play, where opportunities are sparse); the baseline is the 15games before that, and at least 8 must exist. For the two team-relative families (linemates, power play) both windows must be with the player’s current team — a traded player is skipped until enough same-team games accumulate. Baselines may reach back into the previous season early in a year; such takeaways are flagged. A player’s latest game must fall within their team’s last six, so a January injury does not surface as an April “trend”. And every baseline game must fall within the team’s last 30team games before the recent window: a call-up whose “15 games before” stretch back a year has no recent norm to compare against and is skipped. Team games, not days, so the offseason gap costs nothing and an early-season baseline that reaches into last spring still counts.
Salience.Each family gets a noise scale calibrated empirically on 2024-25 and 2025-26: every eligible player-window in both seasons, the distribution of (recent − baseline), and its standard deviation pooled across positions. A change’s zis the delta divided by that scale. A takeaway is emitted only when |z| clears the family’s threshold and a minimum absolute effect is met (at least 10 percentage points for shares, 1:30 per game for ice time, 0.25 goals/60 for offensive impact, 4 attempts/60 for shot volume). Thresholds are set per family — linemates 3.75, ice time 2.75, power play 3.25, offensive impact 2.75, shot volume 2.75 — chosen so that a typical weekly refresh across the two calibration seasons yields about 45 takeaways league-wide (10th–90th percentile 34–56). A single shared threshold could not do this: linemate changes are discrete jumps with a heavy tail and crowd out everything else at any common cutoff. Each player is limited to two takeaways and each linemate pair appears once. Because the thresholds differ, a raw z is not comparable between families, so the board is ranked by salience= |z| divided by the family’s own threshold (a 1.5× ice-time change outranks a 1.2× linemate change even if the latter’s raw z is larger); the card shows that multiple.
Shrinkage for offensive impact.Five games of 5v5 action value is a small sample, so the recent-window rate is shrunk toward the player’s own baseline with an empirical-Bayes prior worth 154minutes of 5v5 ice — estimated from split-half reliability inside the 15-game baselines (odd vs even games, r = 0.39 at ~100 minutes a half). The number in the sentence is the shrunk rate and the change is measured from it; the card’s micro-label says so, and its small print shows the raw rate and the minutes behind it.
Percentage points versus percent. Shares — linemate share, power-play share — change in percentage points(34% → 71% is “up 37 points”, never “109% more”). Rates — goals/60, attempts/60 — are shown as a difference in the rate’s own units, never as a percent change, because a percent of a small rate is meaningless. Ice time is the one family where a relative change is shown alongside the absolute one, because minutes are a large, well-behaved denominator. Every sentence states its windows as a game count plus a date range.
Persistence — a historical fact, not a ship gate. For every eligible historical window in 2024-25 and 2025-26 we checked whether the next five games stayed on the same side of the prior baseline as the change, for flagged windows (those that would have made the board) against unflagged ones. In those two seasons, the share of flagged changes that stayed on the same side over the next five games was:
| Family | Flagged | Unflagged | Flagged n |
|---|---|---|---|
| Linemates | 93% | 66% | 3,245 |
| Ice time | 93% | 66% | 1,046 |
| Power play | 88% | 65% | 1,045 |
| Shot volume | 79% | 59% | 669 |
| Offensive impact | 71% | 58% | 1,106 |
Usage changes were the stickiest — a coach who moves a player up tended to leave them there — while the performance families sat nearer their base rates. This is what happened in two past seasons. It is not used to rank anything, and the board’s sentences describe the last few games only.
Why passing is not shown. Public NHL data does not track passes: the play-by-play feed has no pass event and the EDGE tracking aggregates carry speed, distance and zone time, not completions. Anything that cannot be sourced is left out rather than proxied.
In-season scoring. The offensive-impact family needs a per-event state-value model, which is trained once a season is complete. During a season the new games are scored with the previousseason’s frozen model — no refit until the season ends — so early-season offensive-impact numbers rest on last year’s value surface. The other four families need no model.
Data.Built from the same regular-season shift, play-by-play and lineup data as the value model. During the offseason the board is built from the final games of the completed season and labelled so in its header; in season it is refreshed every morning from the previous night’s final regular-season games (preseason never enters).
Where the numbers come from. Every figure on Edgework is pulled from the NHL’s public web API (api-web.nhle.com). The homepage leaderboards draw on the NHL EDGE tracking feed — the same puck-and-player tracking that powers broadcast graphics — while player profiles blend EDGE data with classic box-score stats. The value model runs on play-by-play and shift data from the same public API.
League leaders. The six homepage leaderboard cards each call a dedicated EDGE “top-10” endpoint — skating speed, speed bursts, skating distance, shot speed, offensive-zone time and 5-on-5 save percentage — fetched in parallel and normalized into one shape. Speed Bursts · 20+ MPH sums the 20–22 mph and 22-plus tracking buckets for a true count at or above 20 mph.
Scoring leaders. Top Forwards and Top Defensemen rank by points, split out of the league-wide scoring list. Top Goalies ranks by wins on the homepage; the value surfaces use our own GSAx (above), which the public NHL API does not provide.
Known gaps. The NHL does not expose public top-10 leaderboards for shots on goal or high-danger shots — that tracking lives only on individual player pages, so those boards are not shown. Anything that cannot be sourced cleanly is left out rather than estimated.
Freshness. Leaderboard data is cached for one hour; player profiles for twelve. The “last refreshed” timestamp in the home footer marks when the homepage last regenerated.
2026-09-23 — Player Trends page. New /trends board: one-sentence, template-generated takeaways on recent changes in linemates, ice time, power-play share, 5v5 offensive impact and shot volume, ranked by an empirically calibrated salience score and backed by game-by-game charts. Descriptive only; persistence is reported, not used. See Player Trends.
2026-09-01 — Contract surplus: rank-to-rank market map. The surplus model changed from a within-position linear regression to a rank-to-rank market map: fair value = what the market’s own pay curve (UFA + non-growth RFA deals, per position) pays at the player’s production percentile, with the curve’s body smoothed and its top anchored to the market’s actual top contracts. The linear fit under-priced the market’s steep top (p90→p99 slope ~5× the mid-curve among forwards), billing elite-percentile stars for curvature; verdicts agree in sign with the old model on 20 of 21 notable contracts tested, but magnitudes redistribute — true albatrosses read worse, elite stars soften. Entry-level and growth deals are now scored against the curve and labeled (structural / growth) instead of dummy-adjusted; the signing-age control was dropped and disclosed (the model prices current production only); the ±$1M band threshold was re-derived on the new residual distribution and stood. See Contract surplus.
2026-08-12 — Contract surplus: cap-era restatement + growth-deal exclusion (S4). Shipped combined with the regressor swap below. The cost model now fits AAV restated to current-cap (2026-27) dollars — a deal signed against an older, lower cap meets the curve at its true market weight (Doughty: 13.8% of the 2018 cap, $14.4M restated) — and training excludes long-term deals signed before age 24 (criterion-defined, still scored; they read negative by design). Surfaces show the restatement chain, and surplus is computed against the restated figure. A tested convexity term (steeper curve at the top) was null and did not ship; the growth-exclusion’s own effect on the curve measured small (~$0.1M at the top) and is disclosed as such. See Contract surplus.
2026-08-12 — Contract surplus: all-strengths regressor + market-rate bands. The cost model’s value input changed from the 5v5-only net to the all-strengths Season-impact z (the market prices special-teams production; the 5v5-only fit misread PP-heavy stars as overpays). The PP-heavy caveat chip is retired (PP is now in the price); guard text now reads “prices current production, not term or growth.” Contracts are also classified into overpaid / market rate / underpaid bands at ±$1M. See Contract surplus.
2026-06-29 — Contract surplus board. Added the contract-surplus surface (board + player-page card): expected cost from a within-position fit on 5v5 value vs actual AAV, with a derived PP-heavy flag and a prominent “estimate, not a verdict” caveat. See Contract surplus.
2026-06-12 — Net Contribution definition change (v2). Net is now 0.9 · z(0.6 · z(OZ) + 0.4 · z(DZ)) + 0.1 · z(C1) per position cohort and season, same qualification floor (500 events). Selected blind under a pre-registered bar (+0.010 pooled next-season predictive improvement, CI excluding zero; smallest admissible weight wins). Effect: rank correlation with v1 is 0.995 within season; the median absolute rank change is 3–4 spots; same-season agreement with on-ice goal differential improved in all three seasons. Historical seasons are restated under v2 — every season page and leaderboard reflects the new definition.