Scoring Changelog

Every meaningful change to how we rate cards. If a card's delta moved, the reason lives here.

2026-04-17 · Scoring now rewards scarce answers and resilient threats

The engine now reads the current Premier meta (1,981 tournament decks) to answer two questions for every card: does it provide something few other cards can do? and is it naturally hard to deal with given what the meta has to answer it? If either answer is yes, the card picks up a small RE bonus.

The two forces are symmetric. When bounce is rare, bombs (cost 5+ units) become more resilient. When upgrade removal is rare, upgrades become more resilient. When single-target removal is rare, high-HP units become more resilient. And the cards that DO provide those rare answers pick up a matching premium.

Five answer categories tracked this release

  1. Upgrade removaldefeat an upgrade effects. Resilient targets: upgrades themselves.
  2. Bounce — return an enemy unit to hand. Resilient targets: cost 5+ cards (bombs).
  3. Single-target removaldefeat a unit or deal damage equal to its power effects. Resilient targets: HP 6+ units.
  4. Capturecapture an enemy unit effects. Resilient targets: Sentinel keyword units.
  5. Discard — force opponent to discard from hand. No clean card-level resilience.

How the math works

The bonus is flat, not a multiplier. Each category has a supply bonus capped at +0.5 RE (for cards that provide the scarce answer) and a resilience bonus capped at +0.3 RE (for cards that are naturally immune). The bonus scales with how scarce the category is in the current meta. A card gets at most ONE bonus (the largest across categories), so effects can't stack.

This means the maximum any card can shift is +0.5 RE. No card moves by a full grade. The overall scoring engine stays anchored to the empirical cost curve; this adjustment is a light meta-aware overlay.

Current Premier meta snapshot

Upgrade removal2.6% of the meta provides it · +0.49 supply bonus, +0.29 resilience
Bounce4.5% of the meta provides it · +0.48 supply bonus, +0.29 resilience
Single-target removal2.7% of the meta provides it · +0.49 supply bonus, +0.29 resilience
Capture0.0% of the meta provides it · +0.50 supply bonus, +0.30 resilience
Discard0.5% of the meta provides it · +0.50 supply bonus, no resilience

Densities update as new tournament data arrives. These numbers reflect the Premier meta at the time this feature landed.

Cards that moved

847 of 2,103 Premier cards (~40%) picked up a bonus. No card lost RE from this change alone. A sample:

Cost-11+ bombs (Supremacy, Executor, Annihilator, Finalizer, etc.)+0.29 RE — resilient to bounce + single-target removal
Upgrades with removal effects (Creditor's Claim, Dorsal Turret, Abandoned the Order)+0.49 RE — provides a scarce answer AND resilient to upgrade removal
Savage Opress — Imbued With Hate−0.42 → −0.13 — body is hard to bounce, even if his ability taxes your base
Lethal Crackdown−3.32 → −2.83 — provides scarce single-target removal
Classic upgrades (Jedi Holocron, Mandalorian Armor, Dorsal Turret)+0.29 to +0.49 RE — upgrade-removal resilience

Known limitations

Events that can't actually be bounced still pick up a bounce-resilience bonus because the current resilience rule checks cost alone, not card type. This mis-credits a handful of cost-5+ events with a +0.29 bonus they don't deserve in practice. The mis-credit never exceeds the cap, and the affected cards mostly sit deep in negative territory anyway (Galactic Ambition, Shadow Cloaking), so the ranking impact is minimal. Fixing this cleanly needs a card-type-aware resilience predicate — follow-up.

2026-04-17 · Self-base-damage now counts as a cost

Cards that deal damage to your own base were being scored as if the damage hit the opponent. That is obviously wrong — a "deal 9 damage to your base" effect is a liability, not an asset. The generic damage pattern was target-blind and the specific base-damage pattern only matched enemy bases, so self-harm silently counted as positive.

Three sub-fixes shipped together:

  1. Hardcoded self-damage ("deal 9 damage to your base") now scores at -N stat points.
  2. Optional self-damage ("you may deal 2 damage to your base") softens to -N/4 because the player only pays if the linked reward is worth it.
  3. Variable self-damage ("deal damage to your base equal to X") is now counted as a cost instead of positive damage.

Cards that moved

Savage Opress — Imbued With Hate +4.60 → -0.13
Steela Gerrera — Beloved Tactician +0.97 → -0.29
Warrior of Clan Ordo +0.99 → -0.21
AAT Incinerator +0.58 → -0.21
Lethal Crackdown -0.77 → -2.12
Galactic Ambition -5.99 → -7.34

Savage Opress was the loudest offender — community feedback flagged him as being ranked as one of the best 6-drops despite dealing up to 18 damage to your base across his played/defeated triggers. He now sits correctly in below-average territory.

2026-04-15 · Empirical cost curve + first community feedback round

Two big shifts in one release: the scoring baseline moved from the designer's linear formula to tournament-derived averages, and six specific ability-pattern bugs surfaced by community feedback got fixed.

Empirical cost curve

The old baseline was 2 + 2 × cost for every ground unit. Reality is more nuanced: high-cost cards pay a bigger "ability tax" than the formula assumes. The new baseline uses real tournament data — the average power + HP of units that actually show up at each cost point — with a fallback to the linear formula when sample sizes are too small (less than 50 deck appearances or 5 unique cards).

Stat distribution penalty

Lopsided stat lines get docked. A 10/1 unit is strictly worse than a 5/5 of the same cost because the game's combat math rewards balanced power/HP. Units where min(power, HP) / max(power, HP) drops below 0.3 now pay up to 1 RE of penalty, scaled by how skewed they are.

Six pattern fixes from community feedback

  1. Friendly capture is a downside. Effects like Escape Pod that capture your own unit are no longer scored as positive capture.
  2. Extra payment costs deducted. "Pay 2 resources to take control" now subtracts half the cost from the effect value.
  3. Opponent-assigned damage is worth less. Sweepers that say "an opponent distributes the damage" now take a -1 RE discount to reflect the suboptimal distribution.
  4. Sweepers moved to the mass-removal tier. Effects that hit every unit (like damage-equal-power-to-each) were in the wrong tier and under-scored as single-target removal.
  5. Planetary Bombardment and indirect damage got their real value. Indirect damage moved from the immediate-impact tier to the debuff tier, boosting its tier multiplier from 0.34x to 1.32x. Planetary Bombardment went from -5.07 to -2.36 delta RE.
  6. Sentinel normalized. The Sentinel delta dropped from -0.34 to 0.0 in Premier to match real-world play value.

Leader-aware scoring

The new LeaderModifier applies leader-specific adjustments on top of the base score. Boba ignores his own friendly cost-discounts. Palpatine treats Force effects as worth more. Thrawn values indirect damage. Thirteen leader profiles landed in this release, with more queued. You see leader-adjusted deltas on the card detail and compare pages now.

2026-04-11 · Per-format scoring + trigger-weight rebalance

Cards are now scored separately for Premier and Eternal. Same card, different delta in each format, because tier multipliers and pattern values are fit to each format's tournament data independently.

Trigger multipliers got a calibration pass. "When Played" effects are the single strongest class of ability in the game (immediate board impact, no setup needed), so they sit at 1.25x. "When Defeated" is half as valuable (the opponent controls the timing) at 0.5x. "Action" abilities trade off resource cost for flexibility at 0.8x. Hard conditionals ("if you control 7 or more units") drop to 0.1x because they usually don't fire.

Synergy-conditional discounts dropped in too: effects that only fire if you have matching traits or aspects get discounted because they aren't always live.

Initial release · Ruby port of the scoring engine

The scoring engine was originally written in TypeScript. We ported it to Ruby for this site, which surfaced four subtle bugs where Ruby's regex and string semantics differ from JavaScript's:

  1. Ruby's \s doesn't match non-breaking spaces. Strapi typesets some cards with NBSPs, so patterns that looked right were silently failing.
  2. Ruby's Oniguruma regex engine doesn't support variable-length negative lookbehinds the way JavaScript does. Patterns that relied on (?<!word\s+.{0,N}) needed rewriting.
  3. "" || "1" returns "" in Ruby (empty string is truthy) but "1" in JavaScript (empty string is falsy). Every pattern that used the idiom to default a missing capture was silently breaking.
  4. Effect patterns don't short-circuit — multiple can match the same text block and all of them contribute to the block's score. That's by design, but a few patterns were accidentally double-counting and needed negative lookaheads.

A parity check (bin/rails data:validate) compares the Ruby output against the frozen TypeScript reference on every build, so any accidental drift is caught in CI.

Found a card that's mis-scored?

Community feedback drives most of the entries above. If you see a card whose delta doesn't match how it actually plays, tell us about it. The scoring engine improves one bug report at a time.