• v4.11.1 e7ab32c8c1

    v4.11.1
    All checks were successful
    CI / build-and-test (push) Successful in 2m5s
    Stable

    joeyr released this 2026-10-21 19:58:19 -05:00 | 0 commits to main since this release

    Changed

    • Team tags show more often. Every tag's line moved one point toward
      showing, after the first real champ select had both teams on "Typical
      comp": Tanky at toughness 9 or more (was 10), Squishy at 7 or less (was
      6), Heavy CC at control 11 or more (was 12), Low CC at 9 or less (was 8),
      Mobile at mobility 10 or more (was 11), Low mobility at 7 or less (was 6),
      High utility at 8 or more (was 9), and Low damage at 11 or less (was 10).
      Each tag now shows in roughly a quarter to two in five games, and "Typical
      comp" is rare.
    • A tag's hover names the line it crossed, e.g. "Tanky — team toughness 9
      (tagged at 9 or more)", in place of the usual range for a team, which the
      new lines now overlap.
    Downloads
  • v4.11.0 059109e9f0

    v4.11.0
    All checks were successful
    CI / build-and-test (push) Successful in 2m25s
    Stable

    joeyr released this 2026-10-21 16:57:33 -05:00 | 1 commits to main since this release

    Added

    • Team tags under each damage bar, on the board and the scouting report.
      A row of short tags says what stands out about each team's comp:
      Tanky, Squishy, Heavy CC, Low CC, Mobile, Low
      mobility
      , High utility and Low damage. They come from Riot's own
      0–3 champion ratings added up across the team, and a tag only appears when
      that total is unusual next to real teams, so each one shows on roughly one
      team in five to one in fourteen. Hovering a tag on the board shows the
      team's score, the usual range, and each champion's rating.
    • Tags fill in as champ select goes. Tanky, Heavy CC, Mobile and High
      utility appear as soon as the picks so far reach them, counting a
      teammate's hover. The "low" tags wait for all five champions, so an early
      team never reads as Squishy. A full team where nothing stands out gets a
      muted Typical comp chip, so an empty row never looks broken.
    • The tags show even when the damage bar can't, since the ratings ship with
      the app. Like the damage bar, they look the same for both teams and give
      no build advice.

    Fixed

    • The scouting report's columns no longer slip out of line when the damage
      bars are missing.
      Without the damage file, every card after the empty
      damage row moved one column over. Each team's damage bar now keeps its
      place, shown or not.
    Downloads
  • v4.10.1 eb2e1b51ac

    v4.10.1
    All checks were successful
    CI / build-and-test (push) Successful in 2m54s
    Stable

    joeyr released this 2026-10-17 13:37:39 -05:00 | 2 commits to main since this release

    Fixed

    • Defensive Bans and Suggested Picks now show the same matchup win rate as
      the board.
      4.10.0 weighted the board's numbers but left both lists on the
      raw rate, so one matchup could read ~58% on the board and 76.5% WR in
      Suggested Picks. Each entry now takes its number from the same lookup the
      board uses — the protected ally against the ban target, the pick against
      your lane opponent — so a weighted one carries the ~ and is dimmed, and
      hovering it shows the actual record. Rates are whole percents, as on the
      board. A Suggested Picks row's hover text quotes the same number. Ranking
      is unchanged: both lists already discounted thin samples when ordering.
    Downloads
  • v4.10.0 657e9a198d

    v4.10.0
    All checks were successful
    CI / build-and-test (push) Successful in 2m0s
    Stable

    joeyr released this 2026-10-16 19:21:25 -05:00 | 3 commits to main since this release

    Added

    • Lane matchup win rates on the champ select board and the scouting
      report.
      Each of your team's rows shows that champion's win rate against
      the enemy in the same lane, at the right edge beside the enemy column, with
      the game count under it. It fills in as soon as both sides of a lane are
      known, counts a teammate's hover, and follows the enemy if you move them to
      a different lane. The scouting report shows the same number in the middle
      of each lane, above the arrow. The numbers come from the counters file the
      tier badges already use, so they need no new download.
    • Matchups under 100 games are weighted, and marked. At the sample sizes
      the data has, a thin matchup is mostly luck: 13–4 does not mean 76%. Below
      100 games the number is pulled toward what the two champions' overall win
      rates predict, counting that guess as 50 games at zero real games and fading
      to nothing at 100, so a matchup never jumps when it gets its hundredth game.
      A weighted number is prefixed ~ and dimmed, a line under the board or
      report explains the ~, and hovering a number on the board shows the
      actual record. A pairing with no games shows —.
    • The board's stale note covers matchups too. When last patch's counters
      file stands in, the note now says the matchup win rates are last patch's as
      well as the tier badges; the scouting report shows its own note.
    Downloads
  • v4.9.0 68ccb67231

    v4.9.0
    All checks were successful
    CI / build-and-test (push) Successful in 2m0s
    Stable

    joeyr released this 2026-10-02 21:38:55 -05:00 | 4 commits to main since this release

    Added

    • Defensive Bans highlights a ban that shows up in more than one column.
      When the same champion counters two or more of your allies, every copy of
      it gets an amber border and tint, so the ban that covers several allies at
      once is easy to spot.
    Downloads
  • v4.8.3 ab6b8637c8

    v4.8.3
    All checks were successful
    CI / build-and-test (push) Successful in 2m1s
    Stable

    joeyr released this 2026-10-02 12:40:57 -05:00 | 5 commits to main since this release

    Security

    • undici 8.10.0 → 8.11.2, and the range floor raised from ^8.5.0 to
      ^8.11.2 so it can no longer resolve to an affected version. Eleven HIGH
      advisories landed against 8.0.0–8.10.1 (WebSocket and decompression DoS,
      retry-interceptor response splitting, shared-cache cookie disclosure and
      cache poisoning, a BalancedPool TLS-validation bypass, and others). The
      app's one call site is a plain request() on the default dispatcher, which
      uses none of the WebSocket, retry, cache, dump or BalancedPool paths they
      name, but the CI gate's npm audit --omit=dev --audit-level=high step
      failed on them, so CI had been red since 4.8.1. 4.8.1 and 4.8.2 shipped
      with the affected version.
    Downloads
  • v4.8.2 3dfacc2f33

    v4.8.2
    Some checks failed
    CI / build-and-test (push) Failing after 25s
    Stable

    joeyr released this 2026-09-30 20:01:01 -05:00 | 6 commits to main since this release

    Fixed

    • A T4 badge no longer looks like an OP badge. On the board, T4 was amber
      and OP gold, a few shades apart, so the best and second-worst tier buckets read
      as the same badge. T4 is now a dusty rose, between T3's grey and T5's red. OP
      keeps its gold.
    Downloads
  • v4.8.1 e4f7956ac2

    v4.8.1
    Some checks failed
    CI / build-and-test (push) Failing after 54s
    Stable

    joeyr released this 2026-09-30 14:37:21 -05:00 | 7 commits to main since this release

    Fixed

    • Last patch's data now stands in when the fetch fails too. 4.8.0 loosened
      the patch rule in the consumers but left the old strict check in the artifact
      provider's fetch-failure fallback, so with no API key, the API down, or a
      timeout, a one-patch-old copy on disk was still thrown away before any
      consumer saw it. Item Import was blank for the whole session on that path,
      because builds and classic items refresh only once the patch is known. The
      fallback now applies the same stand-in rule (patch-fallback.ts): current
      patch, or the previous one published within seven days.
    • The seven-day cap now holds for defensive bans. The stats cache stores a
      stood-in answer under the live patch, and its own fallback served any such
      entry once the adapter refused the aged file — so every champion looked up
      during the window kept last patch's matchups, labelled as a source outage,
      while the tier badges beside them went empty. The fallback now re-applies the
      stand-in rule and labels a stand-in off-patch. A stood-in entry is also no
      longer a fresh cache hit, so the current file replaces it as soon as it lands.
    • Standing in is visible everywhere, not only on defensive bans. Rune and
      Item Import showed last patch's pages and builds exactly like current ones,
      and the tier list's 'stale' was sent to the renderer and dropped. Both
      sections now say when they are showing last patch's data (Import still works),
      and the board says when its tier badges are last patch's. A last-patch roster
      missing a role now reports 'stale' rather than 'partial', which the board
      does not surface.
    • A stand-in rune page or item build is no longer pinned for the session.
      Both option caches kept the first answer per champion and role for the life of
      the process, so a page read from last patch's file survived the current file
      landing and the age cap passing. Only current-patch answers are cached now.
      Builds and classic items also refresh on every LCU connect, like runes; before,
      they were fetched once per process.
    • Pool Strength is held to the same rule. The synergies file was indexed
      whatever its patch or age. It is now dropped once the stand-in rule refuses it,
      so a dead crawler empties the section instead of ranking on old win rates.
    • No more rewriting the stats cache on every lookup. A stood-in or thin entry
      is not fresh, so each lookup reached the adapter and rewrote the whole cache
      file with identical bytes — up to a few seconds of main-process work per champ
      select. An answer the cache already holds is no longer written.

    Changed

    • Comments, the repo CLAUDE.md artifact table, and property test 5 now
      describe the stand-in rule rather than the refuse-off-patch rule it replaced.
    Downloads
  • v4.8.0 4fd4d0813f

    v4.8.0 — serve last patch's artifacts instead of blanking the board
    All checks were successful
    CI / build-and-test (push) Successful in 1m36s
    Stable

    joeyr released this 2026-09-10 20:28:34 -05:00 | 8 commits to main since this release

    Fixed

    • The board no longer goes blank on patch-drop day. On 16.18 the whole
      Summoner's Rift half of the app was empty at once: no defensive-ban
      recommendations, no tier badges, no lane auto-assignment on enemy picks, and
      neither Rune nor Item Import. The cause was one rule applied in five places --
      every consumer compared the artifact's patch to the live patch with !== and
      discarded the file whole on any mismatch.

      The crawler needs a night of games on a new patch before it can publish for
      it, so patch-drop day is always off-patch. That rule was written while the
      op.gg scrapers still sat behind it, and refusing an off-patch artifact meant
      "fall through to a source that has already rolled over". The scrapers are
      gone. The fall-through now lands on nothing, so a strict reject stopped
      meaning "prefer the fresher source" and started meaning "show a blank board" --
      for as long as the crawler stayed behind, which a failed nightly window
      extends by another day.

      An artifact is now servable when it is the current patch, or the
      immediately preceding one published within seven days. Both gates matter and
      they guard different failures: the patch step bounds how far the meta can have
      moved -- champion-counters, -synergies, -benchmarks and -builds
      already pool the current patch with its predecessor when they are built, so
      serving the predecessor's file is serving data the next file would have
      included anyway -- while the age cap bounds how long a dead crawler can go
      unnoticed. Patch adjacency alone would serve 16.17 against 16.18 forever; a
      crawler that died in October would still look like a working app in January.
      Past the cap the board goes honestly empty, which is the signal that something
      upstream needs fixing.

      Standing in is never silent. The counters adapter now stamps the assembled
      ChampionStats with the artifact's patch rather than the requested one,
      which is what lets StatsProvider tell a stand-in from a current file and
      return cached-fallback (reason off-patch) instead of fresh. That maps
      onto the renderer's existing 'stale' freshness, so every affected
      recommendation carries the warning icon it already had for cached stats. The
      tier list reports 'stale' for a complete roster read out of last patch's
      file, kept distinct from 'partial' -- partial means rows are missing and the
      board will have gaps, stale means every row is there and describes last patch.

      Measured against the real 16.17 cache on a 16.18 client: counters for Evelynn
      jungle go from a permanent miss to 52 matchups, the tier list from 0 rows to
      274 across all five roles, and Rune and Item Import from nothing to 4 pages
      and 4 builds.

      Synergies were unaffected throughout -- that provider already indexed whatever
      it fetched -- which is why Pool Strength kept working while everything beside
      it was blank.

    Notes

    • The data/ artifacts this reads are published by lol-companion-data. A
      blank board past the seven-day cap means that crawler has stopped publishing,
      not that this app is broken.
    Downloads
  • v4.7.0 e1d6ac870f

    v4.7.0
    All checks were successful
    CI / build-and-test (push) Successful in 1m45s
    Stable

    joeyr released this 2026-09-07 22:25:30 -05:00 | 9 commits to main since this release

    Changed

    • Rune tooltips now show the rune's full text, figures included. The board
      showed the League client's shortDesc -- the summary with the numbers filed
      off. Electrocute's said it "deals bonus adaptive damage" and stopped there,
      while the damage and the cooldown, the reason anyone hovers a rune, sat in
      longDesc all along:

      Electrocute
      
      Hitting a champion with 3 separate attacks or abilities within 3s deals
      bonus adaptive damage.
      
      Damage: 70 - 240 (+0.1 bonus AD, +0.05 AP) damage.
      Cooldown: 20s
      

      The perk catalog is already fetched once per connect, so this costs no extra
      request. longDesc is taken with a per-entry fallback to shortDesc:
      measured against a live 16.17 catalog all ten stat shards carry the two
      fields byte-identical, so nothing loses text, and the one entry that ships an
      empty longDesc keeps its short form.

      Line breaks are preserved rather than flattened to spaces -- correct for a
      one-sentence summary, wrong for a body whose whole value is the block of
      figures underneath it -- and the rune name now sits above a blank line, so it
      reads as a heading rather than as the first line of the description. Riot's
      closing lore quotes are dropped, by a rule that removes a paragraph only when
      it is wholly italic: <i> also marks mechanic names mid-sentence (the
      Hunter runes' "Bounty Hunter"), and that is content.

    Downloads