fix: align naming between evaluator, formula engine, and DB models

- Rename _CareerTotals.k → .strikeouts to match formula engine's
  stats.strikeouts Protocol
- Update test stubs: TrackStub fields t1→t1_threshold etc. to match
  EvolutionTrack model
- Fix fully_evolved logic: derive from post-max current_tier, not
  new_tier (prevents contradictory state on tier regression)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2026-03-18 15:06:34 -05:00
parent 0f969da206
commit 689ff4b70f
2 changed files with 37 additions and 15 deletions

View File

@ -32,16 +32,16 @@ class _CareerTotals:
sp/rp: outs, k
"""
__slots__ = ("pa", "hits", "doubles", "triples", "hr", "outs", "k")
__slots__ = ("pa", "hits", "doubles", "triples", "hr", "outs", "strikeouts")
def __init__(self, pa, hits, doubles, triples, hr, outs, k):
def __init__(self, pa, hits, doubles, triples, hr, outs, strikeouts):
self.pa = pa
self.hits = hits
self.doubles = doubles
self.triples = triples
self.hr = hr
self.outs = outs
self.k = k
self.strikeouts = strikeouts
def evaluate_card(
@ -121,7 +121,7 @@ def evaluate_card(
triples=sum(r.triples for r in rows),
hr=sum(r.hr for r in rows),
outs=sum(r.outs for r in rows),
k=sum(r.k for r in rows),
strikeouts=sum(r.k for r in rows),
)
# 3. Determine track
@ -135,7 +135,7 @@ def evaluate_card(
now = datetime.utcnow()
card_state.current_value = value
card_state.current_tier = max(card_state.current_tier, new_tier)
card_state.fully_evolved = new_tier >= 4
card_state.fully_evolved = card_state.current_tier >= 4
card_state.last_evaluated_at = now
card_state.save()

View File

@ -46,10 +46,10 @@ class TrackStub(Model):
"""Minimal EvolutionTrack stub for evaluator tests."""
card_type = CharField(unique=True)
t1 = IntegerField()
t2 = IntegerField()
t3 = IntegerField()
t4 = IntegerField()
t1_threshold = IntegerField()
t2_threshold = IntegerField()
t3_threshold = IntegerField()
t4_threshold = IntegerField()
class Meta:
database = _test_db
@ -103,15 +103,25 @@ def _compute_value(card_type: str, stats) -> float:
singles = stats.hits - stats.doubles - stats.triples - stats.hr
tb = singles + 2 * stats.doubles + 3 * stats.triples + 4 * stats.hr
return float(stats.pa + tb * 2)
return stats.outs / 3 + stats.k
return stats.outs / 3 + stats.strikeouts
def _tier_from_value(value: float, track) -> int:
"""Stub tier_from_value using TrackStub fields t1/t2/t3/t4."""
"""Stub tier_from_value using TrackStub fields t1_threshold/t2_threshold/etc."""
if isinstance(track, dict):
t1, t2, t3, t4 = track["t1"], track["t2"], track["t3"], track["t4"]
t1, t2, t3, t4 = (
track["t1_threshold"],
track["t2_threshold"],
track["t3_threshold"],
track["t4_threshold"],
)
else:
t1, t2, t3, t4 = track.t1, track.t2, track.t3, track.t4
t1, t2, t3, t4 = (
track.t1_threshold,
track.t2_threshold,
track.t3_threshold,
track.t4_threshold,
)
if value >= t4:
return 4
if value >= t3:
@ -139,12 +149,24 @@ def _db():
@pytest.fixture()
def batter_track():
return TrackStub.create(card_type="batter", t1=37, t2=149, t3=448, t4=896)
return TrackStub.create(
card_type="batter",
t1_threshold=37,
t2_threshold=149,
t3_threshold=448,
t4_threshold=896,
)
@pytest.fixture()
def sp_track():
return TrackStub.create(card_type="sp", t1=10, t2=40, t3=120, t4=240)
return TrackStub.create(
card_type="sp",
t1_threshold=10,
t2_threshold=40,
t3_threshold=120,
t4_threshold=240,
)
def _make_state(player_id, team_id, track, current_tier=0, current_value=0.0):