Skip to content

Ground waiver bids in league history - #282

Merged
sfreeman422 merged 1 commit into
masterfrom
feature/waiver-wire-bids
Sep 9, 2026
Merged

Ground waiver bids in league history#282
sfreeman422 merged 1 commit into
masterfrom
feature/waiver-wire-bids

Conversation

@sfreeman422

Copy link
Copy Markdown
Collaborator

Summary

  • calculate waiver recommendations from completed Sleeper FAAB bids per projected point
  • normalize prices by league budget and weight recent seasons more heavily across linked league history
  • deterministically apply market prices with position-aware samples, remaining-budget caps, caching, and partial-history resilience
  • add regression coverage for current-season and prior-season bid pricing

Testing

  • npm run test:coverage:all
  • backend build and lint

Use recency-weighted historical FAAB spend per projected point from linked Sleeper seasons to produce deterministic, budget-aware waiver recommendations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 9, 2026 17:28
@sfreeman422
sfreeman422 merged commit 7cdeff9 into master Sep 9, 2026
11 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new caching and pricing paths introduce avoidable memory growth and unnecessary repeated linear scans that should be addressed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds deterministic, history-grounded waiver bid recommendations by deriving a “market” dollars-per-projected-point rate from completed Sleeper FAAB waiver transactions across linked league history, then applying that rate (position-aware when enough samples exist) to current waiver candidates and remaining budget caps.

Changes:

  • Introduces historical waiver bid guidance computation + caching, and injects the resulting guidance into both the AI prompt/input and the final waiver suggestions.
  • Extends the Sleeper league model to include previous_league_id and adds market-sample + weighted-median pricing logic.
  • Adds regression tests covering prior-season pricing and sparse/position-specific/budget-capped markets.
File summaries
File Description
packages/backend/src/fantasy/fantasy.service.ts Computes/caches historical waiver market samples, derives suggested bids, and applies them to AI + waiver suggestions.
packages/backend/src/fantasy/fantasy.service.spec.ts Adds/updates tests validating historical pricing behavior and bid application.
packages/backend/src/fantasy/fantasy.model.ts Adds previous_league_id and introduces WaiverBidGuidance model.
Review details

Suppressed comments (1)

packages/backend/src/fantasy/fantasy.service.ts:387

  • waiverMarketCache entries are never removed when expired, so stale league/week samples can accumulate and grow memory usage over time. Delete the cache entry when it is found but expired before recomputing samples.
    const cacheKey = `${league.league_id}:${state.season}:${state.week}`;
    const cached = this.waiverMarketCache.get(cacheKey);
    if (cached && cached.expiresAt > Date.now()) {
      return this.buildWaiverBidGuidance(cached.samples, league, currentProjections, candidates, remainingBudget);
    }
  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +358 to +360
const key = `${season}:${week}`;
const cached = this.projectionCache.get(key);
if (cached && cached.expiresAt > Date.now()) return Promise.resolve(cached.projections);
Comment on lines +532 to +548
const allRate = this.weightedMedian(samples);
const suggestedBids =
allRate === null
? {}
: Object.fromEntries(
candidates.flatMap((candidate) => {
const projection = currentProjections.find((item) => item.player_id === candidate.id);
const points = this.projectedPoints(projection?.stats, league.scoring_settings);
if (points === null || points <= 0) return [];
const positionSamples = samples.filter((sample) => sample.position === candidate.position);
const rate = this.weightedMedian(positionSamples.length >= 5 ? positionSamples : samples) ?? allRate;
const budget = Math.max(1, league.settings?.waiver_budget ?? 100);
const marketBid = Math.max(1, Math.round(rate * points * budget));
return [[candidate.id, Math.min(remainingBudget, marketBid)]];
}),
);
return { sampleSize: samples.length, suggestedBids };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants