WP-09: Formula Engine #74

Closed
opened 2026-03-12 20:56:17 +00:00 by cal · 1 comment
Owner

Description

Core formula computation logic — three pure functions that compute evolution values from career stats. Called by the evaluator (WP-08).

Repo: database
Phase: 1b (API & Formula Engine)
Dependencies: WP-02, WP-03
Complexity: S

Formulas

def compute_batter_value(stats) -> float:
    """PA + (TB × 2) where TB = 1B + 2×2B + 3×3B + 4×HR"""
    tb = (stats.hits - stats.doubles - stats.triples - stats.hr) + 2*stats.doubles + 3*stats.triples + 4*stats.hr
    return stats.pa + tb * 2

def compute_sp_value(stats) -> float:
    """IP + K where IP = outs / 3"""
    return stats.outs / 3 + stats.so

def compute_rp_value(stats) -> float:
    """IP + K (same formula, different thresholds)"""
    return stats.outs / 3 + stats.so

Files

  • Create: database/app/services/formula_engine.py

Tests (write first in database/tests/test_formula_engine.py)

  • Unit: batter formula — 4 PA, 1 single, 1 double = 4 + (1+2)×2 = 10
  • Unit: batter formula — 4 PA, 0 hits = 4
  • Unit: batter formula — HR-heavy game
  • Unit: SP formula — 18 outs + 5 K = 6.0 + 5 = 11.0
  • Unit: RP formula — 3 outs + 2 K = 1.0 + 2 = 3.0
  • Unit: zero stats → 0.0
  • Unit: formula dispatch by track name
  • Unit: tier from value — exact threshold boundary (e.g. value=37 → T1 for batter)
  • Unit: tier from value — just below threshold (36 → T0)
  • Unit: tier from value — T4 boundary

Plan reference: docs/prd-evolution/PHASE1_PROJECT_PLAN.md WP-09

## Description Core formula computation logic — three pure functions that compute evolution values from career stats. Called by the evaluator (WP-08). **Repo:** `database` **Phase:** 1b (API & Formula Engine) **Dependencies:** WP-02, WP-03 **Complexity:** S ## Formulas ```python def compute_batter_value(stats) -> float: """PA + (TB × 2) where TB = 1B + 2×2B + 3×3B + 4×HR""" tb = (stats.hits - stats.doubles - stats.triples - stats.hr) + 2*stats.doubles + 3*stats.triples + 4*stats.hr return stats.pa + tb * 2 def compute_sp_value(stats) -> float: """IP + K where IP = outs / 3""" return stats.outs / 3 + stats.so def compute_rp_value(stats) -> float: """IP + K (same formula, different thresholds)""" return stats.outs / 3 + stats.so ``` ## Files - **Create:** `database/app/services/formula_engine.py` ## Tests (write first in `database/tests/test_formula_engine.py`) - [ ] Unit: batter formula — 4 PA, 1 single, 1 double = 4 + (1+2)×2 = 10 - [ ] Unit: batter formula — 4 PA, 0 hits = 4 - [ ] Unit: batter formula — HR-heavy game - [ ] Unit: SP formula — 18 outs + 5 K = 6.0 + 5 = 11.0 - [ ] Unit: RP formula — 3 outs + 2 K = 1.0 + 2 = 3.0 - [ ] Unit: zero stats → 0.0 - [ ] Unit: formula dispatch by track name - [ ] Unit: tier from value — exact threshold boundary (e.g. value=37 → T1 for batter) - [ ] Unit: tier from value — just below threshold (36 → T0) - [ ] Unit: tier from value — T4 boundary **Plan reference:** `docs/prd-evolution/PHASE1_PROJECT_PLAN.md` WP-09
cal added this to the Card Evolution Phase 1 milestone 2026-03-12 20:59:13 +00:00
cal added the
evolution
phase-1b
labels 2026-03-12 20:59:24 +00:00
Claude added the
ai-working
label 2026-03-13 00:32:00 +00:00
Claude removed the
ai-working
label 2026-03-13 00:35:03 +00:00
Collaborator

PR #85 opened: #85

Implemented app/services/formula_engine.py with all five public functions:

  • compute_batter_value, compute_sp_value, compute_rp_value — pure formula functions
  • compute_value_for_track(card_type, stats) — dispatch helper
  • tier_from_value(value, track) — T0–T4 classifier; accepts both dict and Peewee model track objects

One deviation from the issue spec: pitcher formulas use stats.k (not stats.so) to match the PlayerSeasonStats model from WP-02 where pitcher Ks are stored as k to avoid collision with batter so.

19 unit tests, all passing.

PR #85 opened: https://git.manticorum.com/cal/paper-dynasty-database/pulls/85 Implemented `app/services/formula_engine.py` with all five public functions: - `compute_batter_value`, `compute_sp_value`, `compute_rp_value` — pure formula functions - `compute_value_for_track(card_type, stats)` — dispatch helper - `tier_from_value(value, track)` — T0–T4 classifier; accepts both dict and Peewee model track objects One deviation from the issue spec: pitcher formulas use `stats.k` (not `stats.so`) to match the `PlayerSeasonStats` model from WP-02 where pitcher Ks are stored as `k` to avoid collision with batter `so`. 19 unit tests, all passing.
Claude added the
ai-pr-opened
label 2026-03-13 00:35:11 +00:00
cal closed this issue 2026-03-16 16:10:44 +00:00
Sign in to join this conversation.
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/paper-dynasty-database#74
No description provided.