Releases
1.8.2
For you
- The rankings table now shows what a projection is made of: for a quarterback, the passing attempts, yards and touchdowns behind the number; for a running back, carries, rushing yards and touchdowns; for a receiver or tight end, targets, receiving yards and catches.
- The rankings band is named in plain words. It reads "floor to ceiling" rather than a pair of statistical percentiles, and the page says what the bar and the tick actually are.
- A rankings page shows the top of a position rather than every player at it, and says how many there are in total, so the page states its own depth instead of running to hundreds of rows.
- Where a projection came from is stated once above each position's rankings table instead of on every row, and the rows that differ are marked. The full detail for any one player stays on that player's own page.
- A rankings page's top rows are the top in every scoring format, not just the one showing when the page loads. Switching between Standard, Half PPR and Full PPR can reorder the visible rows, but it can no longer reveal a player who was not even sent to the page a moment before.
- A search result now opens a page that actually has that player on it: their own page when they have one, otherwise that position's rankings. If a row still is not on screen there, the page says so plainly instead of quietly scrolling to nothing.
- The marker on a rankings row now checks its floor, its projection and its ceiling together, not one of the three alone, so a row whose sources genuinely disagree is marked instead of sitting unmarked beneath a sentence that says every unmarked row shares one source. A row marked only because its sources disagree, with nothing on it actually filled in, gets its own distinct marker rather than being called imputed.
- The sentence above each position's rankings table, and the site's own explanation of it, now describe exactly what that table shows, a row marked imputed or mixed, rather than a broader claim about every player's provenance across the whole site.
- The saved players filter now tells apart having saved nobody yet from having saved players who simply are not among this page's rows, instead of showing the same empty message either way.
- A player's floor to ceiling bar is drawn to the same scale wherever that position appears, so the same player's bar is not narrower on one rankings page than another.
- The longest player names, and the imputed or mixed marker beside them, no longer get cut off in the rankings table; long names truncate the same way every other cell already does.
- Every team page links to all 32 clubs, grouped by conference and division, so you can reach any other club without going back to an index.
- A team's header states its Record, Home and Away splits, and the division it plays in, instead of a bare name and a breadcrumb.
- The rating panel says what its number means, "points better than an average team," and states plainly that there is nothing to show yet rather than an empty chart.
- Every schedule row shows the published forecast as a two-sided bar in each club's own color, or says plainly "not forecast" when a game has not been priced. The list shows the first eight games and says so, with the real total count alongside it.
- A team's roster is a real depth chart: each player's own depth slot, sorted so the starter comes first at every position.
- A player's projection band says floor, projection and ceiling instead of p20, median and p80, with a sentence explaining what the gap between them means: uncertainty, not a big game on the way.
- A player's header names the position and club, and the position rank carries a real label instead of a bare code; the scoring table names Standard, Half PPR and Full PPR to match.
- A player's peer list carries each nearby player's club and projection, not just a rank and a name, so you can see how close the next player along really is.
- The icon in the browser tab is the current one. The site offered its icon only in a format many clients do not read, and the address those clients ask for instead returned nothing, so they kept showing a copy saved before the colours changed. Google's icon service was still handing out the old amber mark weeks later, on every device, and clearing a local cache could not replace it. The site now offers the icon in the formats those clients ask for, including a home screen icon for phones.
- Games we call at 65 percent or better now carry a mark, and it links to a page showing how those calls have actually done. The page starts at nothing and fills up as the season is played, because the only record worth showing is one you can check against games we called in advance.
- Nothing else changes on the site. The forecasts, the numbers and the bands are the ones that were there yesterday.
- Nothing changes on the site. This is a research plumbing fix in the player projection model, and no published number moves.
Under the hood
- The per row source column carried three provenance blocks on every row, almost entirely repetition, since nearly every published row's floor, projection and ceiling trace to the same single source. It is replaced by a statement above the table and a mark on the exceptions, which is what the approved design already specified.
- A new division rail component builds all 32 clubs, grouped by conference and division, from team_summaries at page-build time, with the viewed club marked current.
- The schedule's result badge and forecast bar, and the roster's depth-slot sort, are covered by real Astro build assertions in components-contract.test.ts: resolved club colors and computed bar widths, not just a rule's presence in source.
- PercentileBand takes an opt in plainLanguage prop so the player page's and the rankings table's relabeling do not touch the compare page's own statistical labels, which its client script still depends on by name.
- The rankings table's row limits and per position stat columns, previously stated in three separate places, now live in one module that both rankings pages and the table component share.
- A rankings page's structured data now lists exactly the rows the page renders, not every ranked player at the position; a search engine crawler following those links no longer lands on a fragment nothing in the page carries.
- A leftover client side script for a projection-source control that no longer exists in the markup, and the test fixture that kept it passing, are both removed.
- A row count passed to the rankings table is now validated at build time; a bad value fails the build loudly instead of silently rendering an empty position while its own sentence falsely claims none are published.
- `favicon.ico` and `apple-touch-icon.png` are rasterised from `favicon.svg` by `site/scripts/generate-icons.mjs`, never redrawn, which is what `docs/BRAND.md` requires of a derived asset. Regeneration is manual, run with `npm run icons` from `site/`; a test renders from the current source and compares bytes, so an accent change that forgets to regenerate them fails rather than shipping a stale mark next to correct source files.
- Engine 1 can now calibrate its published ranges on the season being played rather than only on the one before it. The capability ships switched off and the weekly run does not use it; turning it on is a separate change that has to bring the visible switch with it (docs/adr/0005-in-season-band-calibration.md).
- Band calibration no longer switches itself off on a training window with one season in it: it falls back to a split inside that season, with a week of separation, where before it produced no calibration at all.
- A research seeding path read its tree settings from a snapshot taken at import, so a capacity sweep that also passed a seed fitted the deployed model every time and reported no difference between settings. Both engines now read the live settings, and a test asserts it against the fitted trees rather than the source.
- The 65 percent cutoff was picked by a rule written before the numbers behind it were recomputed, and the rule takes the lowest cutoff that clears its bar rather than the one that looks best. Two lower cutoffs were tested and neither cleared.
- Every verdict prints the smallest effect its sample could detect, at 80 percent power, beside the effect it measured. Five reference tables from the backbone source join the master: the ID crosswalk, officials, the draft, the combine and contracts. None of them is a model input.
- Engine 2 read its tree settings from a copy taken when the module loaded, so a capacity experiment that changed those settings and also passed a seed would have quietly fitted the shipped model every time and reported no difference between settings. Engine 1 had the same defect and was fixed first; this closes it on the other engine. The settings now live in one place instead of being typed out twice, and a test checks the fitted trees rather than the source.
- The deployed path is unchanged and it is verified rather than argued: the same fixture through the shipped route, before and after, gives identical predictions on all three quantiles, identical tree and leaf counts, and every constructor parameter equal.