Skip to content

feat(basketball): basketball lab with an honest "new line" test - #210

Merged
Swissystem7 merged 4 commits into
masterfrom
feat/basketball-lab
Nov 14, 2026
Merged

Swissystem7 merged 4 commits into
masterfrom
feat/basketball-lab

Conversation

@Swissystem7

@Swissystem7 Swissystem7 commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

Adds basketball/ (page) and basketball.js (engine) inside ScoutAI.

What it does

  • Data: reads a user CSV (licence checkbox) or a synthetic example. Handles Basketball-Reference and Hebrew headers, 32:15 clock minutes, per-game files (turned into totals via G), TOT/2TM traded players counted once, and reports summary rows and repeated headers. A Round / מחזור column makes the file a game log (one row per player per game), summed to a season.
  • Metric: transparent per-40 recipe with four components: defense (steals, blocks), rebounding (60% ORB, 40% DRB), playmaking (AST, AST/TO), scoring (points, TS%). Defaults 24/20/24/32 and a 250-minute floor, each tied to a cited source (TS% and Four Factors from Basketball-Reference, BPM 2.0, Franks et al. 2016, Medvedovsky 2020).
  • Validation: team split (half the teams train, half test); always labelled "same season".
  • "New line" test: any extra numeric column (body-language coding, fWHR from photos, touches) or PanimGuide is checked on the test teams for raw Spearman and partial Spearman beyond the metric, each against 1,000 shuffles. PanimGuide also gets a spelling probe.
  • Start of season vs rest of season (part 6): on a game log, the metric is computed only on rounds up to a split and the target only on the rounds after it. The metric is compared with every simple early number (the target itself included), each against 1,000 shuffles. Typing a player's name (e.g. the MVP) shows his early rank by each measure and where he finished.
  • Research section: face shape (Sato 2021, Welker 2015, Fujii 2016, Tsujimura 2013, Geniole 2015, Kosinski 2017) and body language (Kraus 2010, Moll 2010, Furley 2012/2014, Furley & Roth 2021, Lian 2026), plus a measurement protocol.
  • Synthetic examples from tools/make-basketball-example.js (seeded): a season file with a pure-noise column and a planted positive-control column, and a game log (80 players, 14 rounds).
  • Every page links to the basketball lab; the site-wide tests cover the new page.

Why rebounding was added (c63fcff)

A local check on 904 Israeli Premier League regular-season games (2021-22 to 2025-26, box scores from the league site, not committed) asked: after 8 rounds, where did the eventual MVP rank? The first recipe had no offensive rebounds and ranked centres far too low (Zach Hankins, MVP 2022-23: #45; the league's PIR had him #6). Rebounding gets its Four Factors share (20%); the other weights keep the old 30/30/40 proportions. It was not fitted to the data.

The result is mixed: the centres moved up (Onuaku 10 → 2, Hankins 45 → 13, Sorkin 7 → 4), but the guard Jared Harper moved down (10 → 26, 14 → 28). Early PIR still predicted rest-of-season PIR better than the metric in every season. Further recipe changes should be judged on seasons not yet looked at (2016-17 to 2020-21).

Results on the synthetic files

  • New-line test: the random column stays inside the noise band; the planted column is caught raw but adds nothing beyond the metric. PanimGuide is noise, and its score changes with name spelling.
  • Start-of-season test on the synthetic game log: the metric from rounds 1-4 predicts later PIR (ρ = 0.75) a little better than early PIR (0.68).

Testing

  • npm test: 185 pass, 0 fail.
  • CodeQL alert on a test regexp (bad tag filter) fixed in 7119869 and e3ce4c6.
  • Checked in a browser at desktop and phone width: no console errors, no horizontal scroll; sliders, the split slider and the player field work.

🤖 Generated with Claude Code

Adds basketball/ (page) and basketball.js (engine) inside ScoutAI:

- Reads a user CSV (licence checkbox) or a synthetic example:
  Basketball-Reference and Hebrew headers, 32:15 clock minutes,
  per-game files turned into totals via G, TOT/2TM traded players
  counted once, summary rows and repeated headers reported.
- Transparent per-40 metric: defense (steals, blocks, DRB),
  playmaking (AST, AST/TO), scoring (points, TS%). Defaults 30/30/40
  and a 250-minute floor, each tied to a cited source (TS% and Four
  Factors from Basketball-Reference, BPM 2.0, Franks et al. 2016,
  Medvedovsky 2020).
- Validation on a team split (half the teams train, half test).
- "New line" test: any extra numeric column (body-language coding,
  fWHR from photos, touches) or PanimGuide is checked on the test
  teams for raw Spearman and partial Spearman beyond the metric,
  each against 1,000 shuffles. PanimGuide also gets a spelling probe.
- Research section on face shape (Sato 2021, Welker 2015, Fujii 2016,
  Tsujimura 2013, Geniole 2015, Kosinski 2017) and body language
  (Kraus 2010, Moll 2010, Furley 2012/2014, Furley & Roth 2021,
  Lian 2026), plus a measurement protocol.
- Synthetic example generated by tools/make-basketball-example.js,
  with a pure-noise column and a planted positive-control column.
- Every page links to the basketball lab; site-wide tests cover it.

npm test: 178 pass, 0 fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread test/basketball.test.js Fixed
…time

CodeQL flagged the scan regexp (js/bad-tag-filter): it missed <SCRIPT>
and tags with attributes. It now matches both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread test/basketball.test.js Fixed
Swissystem7 and others added 2 commits November 14, 2026 13:49
CodeQL js/bad-tag-filter still flagged </script\t\n bar>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A check on 904 Israeli Premier League regular-season games (2021-22 to
2025-26, box scores kept local, not in the repo) showed the recipe ranked
centres far too low: it had no offensive rebounds, and DRB sat inside
defense. Zach Hankins, MVP 2022-23, was #45 after 8 rounds while the
league's PIR had him #6.

Recipe:
- New rebounding component: 60% ORB (cap 5/40) + 40% DRB (cap 9/40),
  since BPM 2.0 values an ORB at 0.18-0.61 points and a DRB at 0.12-0.18.
  Defense is now steals and blocks only (53/47).
- Defaults 24/20/24/32: rebounding gets its Four Factors share (20%), the
  other three keep the old 30/30/40 proportions. Not fitted to the data.
- ORB falls back to TRB - DRB, or 25% of TRB (reported as an estimate).

Start-of-season test (lab part 6):
- A Round / מחזור column makes the file a game log: summed to a season
  for parts 2-5, games kept for part 6.
- Part 6 computes the metric only on rounds up to a split (slider) and
  the target only on the rounds after it, and compares the metric with
  every simple early number, the target itself included, each against
  1,000 shuffles. A player name (e.g. the MVP) shows his early rank by
  each measure and where he finished.
- Synthetic game log (80 players, 14 rounds) from the same seeded tool;
  the season example file is unchanged.

Result on the five real seasons (honest, mixed): the centres moved up
(Onuaku 10->2, Hankins 45->13, Sorkin 7->4) but the guard Harper moved
down (10->26, 14->28). Early PIR still predicted later PIR better than
the metric in every season. Further recipe changes should be judged on
seasons not yet looked at.

npm test: 185 pass, 0 fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Swissystem7
Swissystem7 merged commit a6ed6d6 into master Nov 14, 2026
4 checks passed
@Swissystem7
Swissystem7 deleted the feat/basketball-lab branch November 14, 2026 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants