In the trade-search route (api_trade_search in src/fantasy_baseball/web/season_routes.py), the analytic-band fill loop recomputes field_stats once per candidate even though it depends only on the loop-invariant config.team_name:
for group in results: # ~line 966
...
for cand in group["candidates"]: # ~line 969
try:
...
field_stats = projected_standings.field_stats(config.team_name) # ~line 974
band = compute_one_for_one_band(..., field_stats=field_stats, ...)
projected_standings.field_stats(config.team_name) returns the same value for every candidate in every group, so it can be hoisted to a single call before the for group in results loop and reused. On a search that returns many candidates this is redundant work on a user-facing request path.
Scope
- Compute
field_stats once (right after the if projected_standings is not None: guard, alongside fr) and pass the hoisted value into compute_one_for_one_band.
- Confirm
field_stats() is genuinely invariant across candidates (it takes only config.team_name); if it has any per-candidate dependency, this is a no-op — verify before hoisting.
- Guard:
tests/test_web/test_trade_search_route.py already exercises the band path.
Context
Pre-existing (not introduced by the #227 type-cleanup); spotted during the loop-review of PR #231 and deliberately left out of scope there since that PR was types-only.
In the trade-search route (
api_trade_searchinsrc/fantasy_baseball/web/season_routes.py), the analytic-band fill loop recomputesfield_statsonce per candidate even though it depends only on the loop-invariantconfig.team_name:projected_standings.field_stats(config.team_name)returns the same value for every candidate in every group, so it can be hoisted to a single call before thefor group in resultsloop and reused. On a search that returns many candidates this is redundant work on a user-facing request path.Scope
field_statsonce (right after theif projected_standings is not None:guard, alongsidefr) and pass the hoisted value intocompute_one_for_one_band.field_stats()is genuinely invariant across candidates (it takes onlyconfig.team_name); if it has any per-candidate dependency, this is a no-op — verify before hoisting.tests/test_web/test_trade_search_route.pyalready exercises the band path.Context
Pre-existing (not introduced by the #227 type-cleanup); spotted during the loop-review of PR #231 and deliberately left out of scope there since that PR was types-only.