-
v0.28.0
Stablereleased this
2026-09-01 19:30:36 -05:00 | 507 commits to main since this releaseChanged
-
Benchmarks, counters, synergies and builds are built over both retained
patches instead of one. Retention has kept the current patch and its
predecessor since the table existed, and every aggregate filtered
WHERE patch = $1and walked past rows a night's crawl had already paid for.
Those four now readWHERE patch = ANY($1::text[])over the whole window.The gain is lopsided in time rather than a flat doubling. The predecessor is a
finished crawl — ~26,000 matches on 16.15 — while the current patch holds
whatever the nights since rollover collected: roughly 14x the sample on day
one, ~4x by day four, ~2x by the end of a patch. On counters, whose median
matchup cell was two games, that is the difference between publishing noise
and publishing something a consumer can put a floor under.It does not make counters well-sampled. It roughly doubles a median of two.
MATCH_LOOKBACK_HOURSand the crawl window are where the rest of that
problem lives. -
champion-damageandchampion-runesdeliberately did not change. Damage
splits are ratios that converge in a few dozen games, and pooling would blur
the item reworks anyone reads a damage split to find — it keeps its per-entry
fallback. Runes are the best-sampled artifact here, because a full nine-perk
page rides free on every match-v5 row, and the fastest-moving under a balance
patch; they stay on the current patch under either retention setting. -
RETAIN_PREVIOUS_PATCH=falseis now a quality decision, not a storage one.
It used to cost one thinner morning per patch. It now roughly halves the
sample behind four artifacts for the whole patch. Its doc comment in
config.ts, the README's "The two-patch window" and CLAUDE.md all say so. -
generatedFrom.previousPatchis published on counters, synergies and
builds. Required and nullable here; optional and nullable in lol-companion's
mirror, which shipped first in 4.2.0 — those schemas are.strict(), so a
producer that published the field first would have every install reject the
file and freeze on cached data.generatedFrom.patchis untouched and still
names the patch the file is for.Publishing the window without naming it would have left three files quietly
claiming a one-patch sample they no longer have. -
staleon a benchmarks bucket now means "the current patch has measured
nothing here yet." It used to mean "served from the previous patch because
this one had nothing", which pooling makes meaningless — every bucket may hold
predecessor rows. The producer reads it off a newcurrentNcolumn on
benchmarkRowsrather than off which of two queries the row came from, so the
patch-day signal survives with its meaning intact and lol-companion's existing
labelling stays correct. The damage artifact's identically named flag still
marks a genuine either/or fallback; the two are no longer the same signal. -
Benchmarks reversed "one fresh sample beats a stale thousand" on purpose.
The fallback preferred a single current-patch row over five thousand beside
it. A benchmark is a habit, and 5,001 games describe a habit better than the
one that happens to be on this patch. The pooled mean is weighted byn, so
the fresh sample counts for exactly what it is worth. The rule still holds for
damage, and CLAUDE.md now scopes it to that artifact.Pooling is also the only lever that reaches a thin bucket without withholding
data: raisingBENCHMARK_MIN_SAMPLESdoes not improve a three-game bucket, it
deletes it, and what is never published cannot be recovered downstream. -
buildOrderCoveragestays on the current patch while the builds artifact
pools. It steers which champions the crawl spends its rationed timeline
requests on, and counting the predecessor's orders as coverage would starve
the current patch — leaving the pooled file ever more predecessor-weighted
with each night.
Added
- Nine integration tests for the pooled window, against real SQL, in
test/integration/store.test.ts. Two of them are the correctness properties
the change turns on and that no unit test can reach: that the matchup and
synergy self-joins key onb.patch = a.patch, so a widened window sums two
independent within-patch tallies rather than fabricating pairs between players
who were never in a game together; and thatsynergyRowswidens itspair
numerators and itstotalsdenominators together, since widening only the
first would halve every rate in the file while still validating.
Known risk
- A pooled build order can silently lose an item Riot removed between the two
patches. Purchases are stored raw and classified at build time against
current Data Dragon, socoreSequencedrops an id the catalog no longer
carries — leaving a hole in a sequence presented as observed. Removals cluster
at season boundaries, so this is rare, but it fails quietly rather than
loudly. Documented onRiotBuildsOptions.previousPatch.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-