Skip to content

feature/ml-calibration-v2 — Error store, calibration layer, live odds + DFS integration#42

Merged
jaayslaughter-cpu merged 1 commit into
mainfrom
feature/ml-calibration-v2
Mar 20, 2026
Merged

feature/ml-calibration-v2 — Error store, calibration layer, live odds + DFS integration#42
jaayslaughter-cpu merged 1 commit into
mainfrom
feature/ml-calibration-v2

Conversation

@jaayslaughter-cpu

@jaayslaughter-cpu jaayslaughter-cpu commented Mar 20, 2026

Copy link
Copy Markdown
Owner

PropIQ ML Calibration v2

Complete rewrite of the prediction pipeline with error storage, self-correction, and live sportsbook + DFS integration.

New Files

api/services/prop_model.py — Full rewrite

  • ErrorStore — SQLite-backed prediction log (every prediction + outcome stored)
  • CalibrationLayer — 3-layer post-hoc calibration:
    • L1: Bayesian Beta distribution shrinkage per (player, prop_type, line_bucket)
    • L2: Market efficiency shrink toward book line
    • L3: Active error-pattern corrections (self-correcting)
  • PropModelWithCalibration — XGBoost + calibration + feedback loop
  • Auto-refresh calibration every 50 results
  • american_to_implied() and remove_vig() helpers

api/services/odds_fetcher.py — Rate-limited fetcher

  • Exponential backoff with jitter (handles 429s gracefully)
  • Both API keys with automatic rotation when one is exhausted
  • Per-minute + per-day quota tracking
  • In-memory cache with configurable TTL
  • Player prop batching (5 markets per request per API rules)
  • get_all_mlb_props() — sweeps all active games

api/services/mlb_data.py — Multi-source aggregator

  • MLBStatsClient — Official MLB Stats API (free, no auth)
  • ESPNClient — Scores, standings, injuries, news
  • StatcastClient — pybaseball Statcast advanced metrics
  • MLBDataAggregator — Unified build_player_features() for model input
  • backfill_prop_results() — auto-backfill actual outcomes from boxscores

api/services/error_logger.py — Self-correction engine

  • JSON-lines structured error log (rotating)
  • Pattern detection: systematic bias, low accuracy, edge decay
  • Alert thresholds (configurable via env vars)
  • SelfCorrectionEngine.run_analysis() — detects + generates correction deltas
  • generate_daily_summary() — daily accuracy + edge report

api/services/dfs_tracker.py — DFS + backtester

  • FanDuel + DraftKings scoring engines
  • DFSTracker — logs lineup entries and actual outcomes
  • PropBacktester — flat-stake and Kelly simulations against historical lines
  • kelly_criterion() and half_kelly() sizing

api/routes/predictions.py — Updated router

  • POST /predictions/predict — single prop with full calibration
  • POST /predictions/predict/batch — multiple props
  • GET /predictions/live — fetch + predict all live MLB props
  • POST /predictions/result — record actual outcome (triggers calibration update)
  • GET /predictions/accuracy — model accuracy report
  • GET /predictions/health — model health check
  • POST /predictions/calibration/refresh — manual recalibration
  • GET /predictions/api-status — Odds API quota status

context7/setup.md — Context7 MCP integration

  • Cursor, Claude Desktop, VS Code config
  • REST API usage
  • How to index your own GitHub repo

requirements.txt — Complete dependencies

  • All missing packages added: numpy, scikit-learn, scipy, pybaseball, redis, apscheduler, etc.

Environment Variables Added

ODDS_API_KEY_1=e4e30098807a9eece674d85e30471f03
ODDS_API_KEY_2=673bf195062e60e666399be40f763545
ODDS_CACHE_TTL=120
PROPIQ_ERROR_DB=data/propiq_errors.db
PROPIQ_MODEL_PATH=models/xgb_prop_model.json
PROPIQ_LOG_DIR=logs
ACCURACY_ALERT_THRESHOLD=0.45
EDGE_DECAY_THRESHOLD=0.02
BIAS_THRESHOLD=0.06
CONTEXT7_API_KEY=ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e

Summary by cubic

Rewrote the prop prediction pipeline with Bayesian calibration, persistent error storage, and a self-correcting loop. Added live sportsbook odds ingestion, DFS tracking/backtests, and new fastapi routes to run, monitor, and update predictions.

  • New Features

    • Calibration v2: SQLite ErrorStore + 3-layer CalibrationLayer (beta shrinkage, market shrink, pattern corrections) with auto refresh every 50 results.
    • Model: PropModelWithCalibration (xgboost raw prob → calibrated prob) with feedback loop and accuracy report.
    • Live odds: OddsFetcher (backoff, key rotation, TTL cache) and /predictions/live sweep for MLB props.
    • MLB data: MLBDataAggregator (MLB Stats, ESPN, Statcast) for feature builds and result backfill.
    • DFS + backtests: FanDuel/DraftKings scorers, DFSTracker, PropBacktester with Kelly/half-Kelly sizing.
    • API: /predictions/predict, /predict/batch, /result, /accuracy, /health, /calibration/refresh, /api-status.
  • Migration

    • Install new deps: pip install -r requirements.txt (includes xgboost, pybaseball, pandas, requests).
    • Set env vars: ODDS_API_KEY_1/2, ODDS_CACHE_TTL, PROPIQ_ERROR_DB, PROPIQ_MODEL_PATH, PROPIQ_LOG_DIR, and alert thresholds.
    • Ensure an XGBoost model at PROPIQ_MODEL_PATH (falls back to heuristic if missing).
    • Start recording results via /predictions/result to update calibration and unlock self-corrections.

Written for commit 6bb2958. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added comprehensive prediction API with endpoints for single and batch prop predictions
    • Introduced live prop discovery integrated with MLB game data and odds
    • Implemented model calibration and self-correction system to improve forecast accuracy
    • Added error tracking, health monitoring, and performance analytics
    • Launched DFS tracking and backtesting capabilities for strategy validation

@vercel

vercel Bot commented Mar 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mework Error Error Mar 20, 2026 6:38am

@secure-code-warrior-for-github

Copy link
Copy Markdown

Micro-Learning Topic: SQL injection (Detected by phrase)

Matched on "SQLi"

What is this? (2min video)

This is probably one of the two most exploited vulnerabilities in web applications and has led to a number of high profile company breaches. It occurs when an application fails to sanitize or validate input before using it to dynamically construct a statement. An attacker that exploits this vulnerability will be able to gain access to the underlying database and view or modify data without permission.

Try a challenge in Secure Code Warrior

Helpful references

@coderabbitai

coderabbitai Bot commented Mar 20, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces a complete prop prediction API service layer, adding six new service modules and one FastAPI router that together enable real-time sports betting inference with MLB data enrichment, odds fetching, predictive modeling with Bayesian calibration, error tracking, and DFS backtesting.

Changes

Cohort / File(s) Summary
API Routes
api/routes/predictions.py
New FastAPI router exposing 8 endpoints: /predict (single prop inference), /predict/batch (multi-prop predictions), /live (fetch and rank live props by edge), /result (record outcomes and trigger async logging), /accuracy, /health, /calibration/refresh, /api-status. Single-prop flow enriches inputs via MLB data, applies feature overrides, computes Kelly fractions via backtesting, and returns structured predictions with edge/recommendation tiers.
Core ML Services
api/services/prop_model.py
Implements end-to-end prediction pipeline: ErrorStore (SQLite persistence of predictions/outcomes), CalibrationLayer (Bayesian Beta-calibration per player/prop_type/line_bucket with learned correction deltas), PropModelWithCalibration (orchestrates XGBoost inference, calibration, and result recording). Includes American odds helpers and singleton accessor.
Data Integration Services
api/services/mlb_data.py, api/services/odds_fetcher.py
MLBDataAggregator composes three API clients (MLBStatsClient, ESPNClient, StatcastClient) to provide game context, player features (last-7/last-30 averages, hot streaks), pitcher stats, and boxscore backfill. OddsFetcher wraps The Odds API v4 with in-memory TTL caching, per-key rate limiting, retry/backoff logic, prop fetching with market chunking, and consensus-line calculation.
Tracking & Monitoring Services
api/services/dfs_tracker.py, api/services/error_logger.py
DFSTracker logs DFS entries and computes value metrics via platform-specific scoring (FanDuel/DraftKings). PropBacktester backtests predictions against sportsbook probabilities to compute Kelly fractions and P&L. PropIQLogger and SelfCorrectionEngine provide structured error/prediction logging to JSON-lines, pattern detection for systematic bias/accuracy drops/edge decay, daily summary generation, and model health classification.
Documentation & Dependencies
context7/setup.md, requirements.txt
Added Context7 MCP integration guide for IDE-specific configs and workspace rules to query external library documentation. Pinned dependencies covering FastAPI, SQLAlchemy, XGBoost, pandas, requests, pybaseball, Redis, Celery, structlog, and testing utilities.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PredictionAPI as /predict Endpoint
    participant MLBData as MLBDataAggregator
    participant PropModel as PropModelWithCalibration
    participant DFSBacktester as PropBacktester
    participant ErrorStore as ErrorStore (DB)

    Client->>PredictionAPI: PropPredictionRequest<br/>(player, market, odds, event_id)
    PredictionAPI->>PredictionAPI: Compute implied probs<br/>& remove vig
    alt event_id provided
        PredictionAPI->>MLBData: build_player_features()
        MLBData-->>PredictionAPI: {features, errors?}
    end
    PredictionAPI->>PredictionAPI: Apply feature overrides
    PredictionAPI->>PropModel: predict(features, ...)
    PropModel->>ErrorStore: Load player/prop calibration
    ErrorStore-->>PropModel: Beta params & deltas
    PropModel->>PropModel: Raw inference + calibrate
    PropModel-->>PredictionAPI: {calibrated_prob, edge, tier}
    PredictionAPI->>DFSBacktester: kelly_criterion()<br/>half_kelly()
    DFSBacktester-->>PredictionAPI: {kelly_frac, half_kelly}
    PredictionAPI-->>Client: PropPredictionResponse
Loading
sequenceDiagram
    participant Client
    participant LiveAPI as /live Endpoint
    participant OddsFetcher as OddsFetcher
    participant PropModel as PropModelWithCalibration
    participant Deduplicator as (player, market) Filter

    Client->>LiveAPI: GET /live?markets=...,<br/>max_events=15
    LiveAPI->>OddsFetcher: get_mlb_events()
    OddsFetcher-->>LiveAPI: [event_ids, ...]
    LiveAPI->>OddsFetcher: get_all_mlb_props()<br/>(markets, max_events)
    OddsFetcher-->>LiveAPI: {event_id: [props]}
    LiveAPI->>Deduplicator: Filter Over-side props<br/>deduplicate by (player, market)
    Deduplicator-->>LiveAPI: [unique_props]
    LiveAPI->>PropModel: predict() for each prop<br/>(with event metadata)
    PropModel-->>LiveAPI: [predictions with edge]
    LiveAPI->>LiveAPI: Sort by edge DESC
    LiveAPI-->>Client: {count, predictions[]}
Loading
sequenceDiagram
    participant Client
    participant ResultAPI as /result Endpoint
    participant PropModel as PropModelWithCalibration
    participant ErrorStore as ErrorStore (DB)
    participant SelfCorrection as SelfCorrectionEngine
    participant Logger as PropIQLogger
    participant BackgroundTasks as BackgroundTasks

    Client->>ResultAPI: ResultFeedbackRequest<br/>(prediction_id, actual_result,<br/>model_prob?, ...)
    ResultAPI->>PropModel: record_result(...)<br/>persist prediction outcome
    PropModel->>ErrorStore: record_result()<br/>update calibration layer
    ErrorStore->>ErrorStore: Update Beta posterior<br/>per (player, prop_type)
    alt every 50 results
        ErrorStore->>SelfCorrection: refresh_corrections()
        SelfCorrection->>Logger: read_prediction_log(30 days)
        SelfCorrection->>SelfCorrection: Detect bias, low accuracy,<br/>edge decay patterns
        SelfCorrection->>Logger: _fire_alert()
    end
    alt model_prob provided
        ResultAPI->>BackgroundTasks: add_task()<br/>log_prediction_outcome()
        BackgroundTasks->>Logger: Write to predictions.jsonl
    end
    ResultAPI-->>Client: {status: "recorded",<br/>prediction_id}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 Hops through props with models bright,
Odds and edges, edges right!
Kelly fractions, calibrated true,
DFS value, live and new!
Self-correction learns each day,
What the sportsbooks couldn't say! 🎰

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main components introduced: ML calibration (error store + calibration layer), live odds fetching, and DFS tracking integration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/ml-calibration-v2
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@deepsource-io

deepsource-io Bot commented Mar 20, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 7230a0b...6bb2958 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
Docker Mar 20, 2026 6:38a.m. Review ↗
JavaScript Mar 20, 2026 6:38a.m. Review ↗
Python Mar 20, 2026 6:38a.m. Review ↗
SQL Mar 20, 2026 6:38a.m. Review ↗
Secrets Mar 20, 2026 6:38a.m. Review ↗

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a significant upgrade to the PropIQ analytics platform by overhauling its prediction pipeline. The changes introduce a sophisticated, self-correcting machine learning model that leverages real-time data from various sports sources and integrates directly with DFS platforms. The focus is on improving prediction accuracy through advanced calibration techniques, robust data acquisition, and continuous learning from past performance, ultimately providing more reliable and actionable insights for player prop betting.

Highlights

  • Prediction Pipeline Rewrite: The core prediction pipeline has been completely rewritten to include error storage, self-correction mechanisms, and enhanced integration with live sportsbook and DFS data.
  • Multi-Layer Calibration: A new CalibrationLayer has been introduced, featuring Bayesian Beta distribution shrinkage, market efficiency adjustment towards book lines, and active error-pattern corrections for improved prediction accuracy.
  • Robust Data Fetching: The OddsFetcher service now includes rate-limiting, exponential backoff with jitter, automatic API key rotation, in-memory caching, and player prop batching for reliable access to live odds.
  • Comprehensive MLB Data Aggregation: A new MLBDataAggregator combines data from MLB Stats API, ESPN, and pybaseball's Statcast to provide rich player features and game context for the prediction model.
  • DFS Integration and Backtesting: Dedicated services for DFS scoring (FanDuel, DraftKings) and a PropBacktester have been added, allowing for tracking lineup performance and simulating betting strategies.
  • Enhanced API Endpoints: The FastAPI router (predictions.py) has been updated with new endpoints for single and batch predictions, live prop fetching, result recording, model accuracy reports, and health checks.
  • Error Logging and Self-Correction: A structured ErrorLogger and SelfCorrectionEngine are now in place to log prediction outcomes, detect systematic biases, and generate correction deltas, ensuring continuous model improvement.
  • Dependency Management and Context7 Integration: The requirements.txt file has been updated with all necessary packages, and context7/setup.md provides documentation for integrating Context7 MCP for version-accurate documentation and AI assistance.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codacy-production

Copy link
Copy Markdown

Codacy's Analysis Summary

42 new issues (≤ 0 issue)
23 new security issues
345 complexity
4 duplications
More details

AI Reviewer: run a review on demand. To trigger the first review automatically, go to your organization or repository integration settings. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes. Give us feedback

Comment thread api/routes/predictions.py
try:
player_features = mlb.build_player_features(req.player, req.game_date)
features.update(player_features)
except Exception as e:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused variable 'e'


An unused variable takes up space in the code, and can lead to confusion, and it should be removed. If this variable is necessary, name the variable _ to indicate that it will be unused, or start the name with unused or _unused.

Comment thread api/routes/predictions.py
try:
result = await predict_prop(prop)
results.append(result)
except Exception as e:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused variable 'e'


An unused variable takes up space in the code, and can lead to confusion, and it should be removed. If this variable is necessary, name the variable _ to indicate that it will be unused, or start the name with unused or _unused.

import os
import json
import logging
from datetime import datetime, date, timedelta

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused timedelta imported from datetime


An object has been imported but is not used anywhere in the file.
It should either be used or the import should be removed.

from typing import Dict, List, Optional, Tuple

import pandas as pd
import numpy as np

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused numpy imported as np


An object has been imported but is not used anywhere in the file.
It should either be used or the import should be removed.


return round(pts, 2)

def salary_value(self, dfs_points: float, salary: int) -> float:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Method doesn't use the class instance and could be converted into a static method


The method doesn't use its bound instance. Decorate this method with @staticmethod decorator, so that Python does not have to instantiate a bound method for every instance of this class thereby saving memory and computation. Read more about staticmethods here.

prob = self._xgb_model.predict_proba(numeric_df)[0][1]
return float(prob)
except Exception as e:
logger.error(f"XGBoost predict error: {e}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Use lazy % formatting in logging functions


Formatting the message manually before passing it to a logging call does unnecessary work if logging is disabled. Consider using the logging module's built-in formatting features to avoid that.

).fetchone()[0]
if total % 50 == 0:
self.calibration.refresh_corrections()
logger.info(f"Auto-calibration refresh triggered at {total} results")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Use lazy % formatting in logging functions


Formatting the message manually before passing it to a logging call does unnecessary work if logging is disabled. Consider using the logging module's built-in formatting features to avoid that.

)
results.append(result)
except Exception as e:
logger.error(f"Batch predict error for {p.get('player')}: {e}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Use lazy % formatting in logging functions


Formatting the message manually before passing it to a logging call does unnecessary work if logging is disabled. Consider using the logging module's built-in formatting features to avoid that.

"accuracy_by_prop": self.error_store.get_recent_accuracy(days=7),
"active_corrections": [
{"player": k[0], "prop_type": k[1], "correction": v}
for k, v in self.calibration._corrections.items()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Access to a protected member _corrections of a client class


Accessing a protected member (a member prefixed with _) of a class from outside that class is not recommended, since the creator of that class did not intend this member to be exposed. If accesing this attribute outside of the class is absolutely needed, refactor it such that it becomes part of the public interface of the class.



def get_model() -> PropModelWithCalibration:
global _model_instance

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using the global statement


It is recommended not to use global statement unless it is really necessary. Global variables are dangerous because they can be simultaneously accessed from multiple sections of a program. This frequently results in bugs. This also make code difficult to read, because they force you to search through multiple functions or even modules just to understand all the different locations where the global variable is used and modified. Read more about why it should be avoided here.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request is a significant and impressive rewrite of the prediction pipeline, introducing a robust architecture with error storage, calibration, and integration with various data sources. The code is well-structured into services. My review focuses on improving robustness, performance, and security. Key areas for improvement include handling exceptions more gracefully by adding logging instead of silently passing, improving the performance of batch operations using concurrency, and removing hardcoded secrets from the codebase.

"command": "npx",
"args": ["-y", "@upstash/context7-mcp@latest"],
"env": {
"CONTEXT7_API_KEY": "ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

A hardcoded API key (CONTEXT7_API_KEY) has been found in the source code. Storing secrets in code is a major security risk, as it can be exposed to anyone with access to the repository. This key should be removed from the code and loaded from a secure source, like an environment variable.

Suggested change
"CONTEXT7_API_KEY": "ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"
"CONTEXT7_API_KEY": os.getenv("CONTEXT7_API_KEY")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Micro-Learning Topic: Hard-coded API key (Detected by phrase)

Matched on "hardcoded API key"

What is this? (2min video)

Poor or missing authentication/authorization schemes allow an adversary to anonymously execute functionality within the mobile app or backend server used by the mobile app. Weaker authentication for mobile apps is fairly prevalent due to a mobile device's input form factor. To detect poor authentication schemes, testers can perform binary attacks against the mobile app while it is in 'offline' mode. Through the attack, the tester will force the app to bypass offline authentication and then execute functionality that should require offline authentication. To test for poor authorization schemes, testers can perform binary attacks against the mobile app and try to execute privileged functionality that should only be executable with a user of higher privilege while the mobile app is in 'offline' mode.

This kind of vulnerability occurs when the app uses a hardcoded API key to communicate to the server. It is possible for an attacker to use the API key and make direct calls to the server.

Try a challenge in Secure Code Warrior

Comment thread context7/setup.md

## Your API Keys
```
ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e (primary)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

This documentation file contains a hardcoded API key. Secrets should never be committed to version control, even in documentation files, as they can be discovered by repository scanners. Please remove the key and replace it with a placeholder like <YOUR_CONTEXT7_API_KEY>.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Micro-Learning Topic: Hard-coded API key (Detected by phrase)

Matched on "hardcoded API key"

What is this? (2min video)

Poor or missing authentication/authorization schemes allow an adversary to anonymously execute functionality within the mobile app or backend server used by the mobile app. Weaker authentication for mobile apps is fairly prevalent due to a mobile device's input form factor. To detect poor authentication schemes, testers can perform binary attacks against the mobile app while it is in 'offline' mode. Through the attack, the tester will force the app to bypass offline authentication and then execute functionality that should require offline authentication. To test for poor authorization schemes, testers can perform binary attacks against the mobile app and try to execute privileged functionality that should only be executable with a user of higher privilege while the mobile app is in 'offline' mode.

This kind of vulnerability occurs when the app uses a hardcoded API key to communicate to the server. It is possible for an attacker to use the API key and make direct calls to the server.

Try a challenge in Secure Code Warrior

Comment on lines +32 to +33
os.getenv("ODDS_API_KEY_1", "e4e30098807a9eece674d85e30471f03"),
os.getenv("ODDS_API_KEY_2", "673bf195062e60e666399be40f763545"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

The default values for ODDS_API_KEY_1 and ODDS_API_KEY_2 are hardcoded API keys. This is a significant security vulnerability. These keys should be removed from the code. The application should rely solely on the environment variables being set, and perhaps fail with a clear error message if they are missing.

Suggested change
os.getenv("ODDS_API_KEY_1", "e4e30098807a9eece674d85e30471f03"),
os.getenv("ODDS_API_KEY_2", "673bf195062e60e666399be40f763545"),
os.getenv("ODDS_API_KEY_1"),
os.getenv("ODDS_API_KEY_2"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Micro-Learning Topic: Hard-coded API key (Detected by phrase)

Matched on "hardcoded API key"

What is this? (2min video)

Poor or missing authentication/authorization schemes allow an adversary to anonymously execute functionality within the mobile app or backend server used by the mobile app. Weaker authentication for mobile apps is fairly prevalent due to a mobile device's input form factor. To detect poor authentication schemes, testers can perform binary attacks against the mobile app while it is in 'offline' mode. Through the attack, the tester will force the app to bypass offline authentication and then execute functionality that should require offline authentication. To test for poor authorization schemes, testers can perform binary attacks against the mobile app and try to execute privileged functionality that should only be executable with a user of higher privilege while the mobile app is in 'offline' mode.

This kind of vulnerability occurs when the app uses a hardcoded API key to communicate to the server. It is possible for an attacker to use the API key and make direct calls to the server.

Try a challenge in Secure Code Warrior

Comment thread api/routes/predictions.py
try:
result = await predict_prop(prop)
results.append(result)
except Exception as e:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

This exception handler catches failures for a single prop prediction in the batch, which is good. However, it doesn't log the exception e. This makes it impossible to know why the prediction failed. Please log the exception to aid in debugging. You will need to add import logging and logger = logging.getLogger(__name__) at the top of the file.

        except Exception as e:
            logger.error(f"Failed to predict prop for {prop.player}: {e}")

Comment thread api/routes/predictions.py
Comment on lines +217 to +218
except Exception:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Silently continuing after an exception during prediction for live props can hide significant issues with the model or data fetching. This makes debugging very difficult. The exception should be logged so that failures are visible. You will need to add import logging and logger = logging.getLogger(__name__) at the top of the file.

            except Exception as e:
                logger.warning(f"Failed to predict live prop for {prop.get('player')}: {e}")
                continue

return {"status": "no_data", "corrections": {}, "alerts": []}

# Group by (player, prop_type)
from collections import defaultdict

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This local import is inside the run_analysis function. According to PEP 8, imports should be at the top of the file. This improves readability and code organization. Please move this import to the top of the file.

Comment thread api/services/mlb_data.py
if not log:
return {"player": player_name, "player_id": player_id}

import pandas as pd

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This is a local import inside build_player_features. According to PEP 8, imports should be at the top of the file. This improves readability and code organization. Please move this import to the top of the file.

})

# Polite delay between chunks
time.sleep(0.5)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

A hardcoded time.sleep(0.5) is used between chunked API requests. While this is a good practice for being polite to the API, hardcoding the value makes it inflexible. Consider making this delay configurable via an environment variable or a class attribute to allow for easier tuning.

Comment thread api/routes/predictions.py
)

# Kelly sizing
from api.services.dfs_tracker import PropBacktester

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This local import is inside the predict_prop function. According to PEP 8, imports should be at the top of the file. This improves readability and helps avoid issues like circular dependencies. Please move this import to the top of the file with the other imports.

Comment thread requirements.txt
# ── Testing ─────────────────────────────────
pytest==8.1.1
pytest-asyncio==0.23.5
httpx==0.27.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The httpx package is listed twice in requirements.txt (also on line 26). While pip can handle this, it's best to remove the duplicate entry to keep the dependency file clean and maintainable.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 14

🧹 Nitpick comments (9)
api/services/mlb_data.py (2)

443-444: Remove unused variable df.

The DataFrame df is created but never used in get_pitcher_context().

Proposed fix
-        import pandas as pd
-        df = pd.DataFrame(log)
         # For pitchers the stats come back differently — use season totals
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/mlb_data.py` around lines 443 - 444, In get_pitcher_context(),
remove the unused pandas DataFrame creation: delete the import pandas as pd and
the line creating df = pd.DataFrame(log) (or keep the import only if used
elsewhere in the module) and ensure the function uses the existing 'log'
variable directly; locate these lines inside the get_pitcher_context() function
and remove them so there are no unused variables or imports.

139-139: Rename unused loop variable.

pid is not used in the loop body.

Proposed fix
-            for pid, pdata in players.items():
+            for _pid, pdata in players.items():
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/mlb_data.py` at line 139, The loop uses an unused variable named
pid in the iteration "for pid, pdata in players.items()"; rename pid to _ or
_pid (e.g., "for _pid, pdata in players.items()" or "for _, pdata in
players.items()") to signal it is intentionally unused and satisfy linters
without changing behavior; update any related references if present (none
expected since pid is unused).
api/services/odds_fetcher.py (2)

147-166: Consider using ClassVar for mutable class attributes.

PROP_MARKETS and GAME_MARKETS are mutable lists defined as class attributes. While not a bug in this usage, annotating with ClassVar clarifies intent and satisfies type checkers.

Proposed fix
+from typing import Any, ClassVar, Dict, List, Optional, Tuple
...
 class OddsFetcher:
-    PROP_MARKETS = [
+    PROP_MARKETS: ClassVar[List[str]] = [
         "batter_hits",
         ...
     ]

-    GAME_MARKETS = ["h2h", "spreads", "totals"]
+    GAME_MARKETS: ClassVar[List[str]] = ["h2h", "spreads", "totals"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/odds_fetcher.py` around lines 147 - 166, Annotate the mutable
class attributes PROP_MARKETS and GAME_MARKETS with typing.ClassVar to declare
they are class-level variables for type checkers: import ClassVar from typing
and change the declarations to PROP_MARKETS: ClassVar[list[str]] = [...] and
GAME_MARKETS: ClassVar[list[str]] = [...]; keep the existing list contents
unchanged so runtime behavior is the same but static analysis knows these are
class variables.

225-236: Log unexpected exceptions before retrying.

Line 229 catches bare Exception and only logs a generic message. Consider logging the exception type/traceback for debugging unexpected failures.

Proposed fix
-            except Exception as e:
-                logger.error(f"Unexpected error: {e}")
+            except Exception as e:
+                logger.exception(f"Unexpected error during request to {endpoint}")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/odds_fetcher.py` around lines 225 - 236, The except Exception as
e block only logs a generic message; update it to log full exception details
(type and traceback) before retrying by replacing logger.error(f"Unexpected
error: {e}") with a call that includes exception info (e.g.,
logger.exception(...) or logger.error(..., exc_info=True)) in the same
error-handling scope (the except Exception block) so the traceback is captured
for debugging; keep the existing backoff and sleep behavior unchanged.
api/services/error_logger.py (2)

319-320: Module-level singletons initialized at import time.

These singletons are created when the module is imported, before any configuration or dependency injection can occur. This makes testing difficult and couples the module to its dependencies.

Consider lazy initialization or a factory pattern for better testability.

Example lazy initialization
-_prop_logger = PropIQLogger()
-_self_correction = SelfCorrectionEngine(_prop_logger)
+_prop_logger: Optional[PropIQLogger] = None
+_self_correction: Optional[SelfCorrectionEngine] = None


 def get_logger() -> PropIQLogger:
+    global _prop_logger
+    if _prop_logger is None:
+        _prop_logger = PropIQLogger()
     return _prop_logger


 def get_self_correction() -> SelfCorrectionEngine:
+    global _self_correction
+    if _self_correction is None:
+        _self_correction = SelfCorrectionEngine(get_logger())
     return _self_correction
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/error_logger.py` around lines 319 - 320, The module currently
creates module-level singletons _prop_logger = PropIQLogger() and
_self_correction = SelfCorrectionEngine(_prop_logger) at import time, which
couples configuration and makes testing hard; change to lazy initialization or a
factory by replacing these direct instantiations with either (a) getter
functions like get_prop_logger() and get_self_correction() that create and cache
the instances on first call, or (b) a factory function/class that accepts
dependencies and returns configured instances of PropIQLogger and
SelfCorrectionEngine, and update all call sites to obtain instances via these
getters/factory to allow injecting mocks and configuration during tests.

98-120: Dual prediction logging creates data inconsistency.

Prediction outcomes are logged to both:

  1. predictions.jsonl via PropIQLogger.log_prediction_outcome() (called from routes)
  2. SQLite prediction_log via ErrorStore.log_prediction() (called from model)

This duplication means accuracy metrics may differ depending on which store is queried. Consider consolidating to a single source of truth.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/error_logger.py` around lines 98 - 120, The file currently
writes prediction outcomes to a JSONL file using log_prediction_outcome
(PREDICTION_LOG_FILE and _write), but the same events are also persisted to the
SQLite prediction_log via ErrorStore.log_prediction, causing divergent metrics;
consolidate to one source of truth (prefer the SQLite prediction_log). Replace
direct JSONL writes by routing all prediction logging through
ErrorStore.log_prediction (update callers that currently call
PropIQLogger.log_prediction_outcome and any model-level calls to instead call
ErrorStore.log_prediction), remove or deprecate log_prediction_outcome's JSONL
write (or make it a thin forwarder to ErrorStore.log_prediction), and ensure
recorded fields and types (player, prop_type, model_prob, book_prob,
actual_result, edge, ts) match the DB schema; update any tests or consumers that
read PREDICTION_LOG_FILE to use the DB instead.
api/routes/predictions.py (2)

130-134: Move import to module level.

Importing PropBacktester inside the function on every request is inefficient. Move it to the top with other imports.

Proposed fix
 from api.services.prop_model import get_model, american_to_implied
 from api.services.odds_fetcher import get_fetcher
 from api.services.mlb_data import get_mlb_data
 from api.services.error_logger import log_prediction_outcome, get_self_correction
+from api.services.dfs_tracker import PropBacktester
...
     # Kelly sizing
-    from api.services.dfs_tracker import PropBacktester
     bt = PropBacktester()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/routes/predictions.py` around lines 130 - 134, The PropBacktester import
is inside the request handler causing repeated imports; move "from
api.services.dfs_tracker import PropBacktester" to the module-level imports at
the top of predictions.py, then in the handler keep creating bt =
PropBacktester() and calling bt.kelly_criterion(...) and bt.half_kelly(...);
ensure no other local references to the import remain and run tests to confirm
no side effects from changing import location.

91-95: Consider using the existing remove_vig() helper.

This vig removal logic duplicates remove_vig() from prop_model.py. While the implementation is correct, using the shared helper improves maintainability.

Proposed fix
-from api.services.prop_model import get_model, american_to_implied
+from api.services.prop_model import get_model, american_to_implied, remove_vig
 ...
     over_raw = american_to_implied(req.book_over_odds)
     under_raw = american_to_implied(req.book_under_odds)
-    total = over_raw + under_raw
-    book_prob = over_raw / total  # vig-removed
+    book_prob, _ = remove_vig(over_raw, under_raw)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/routes/predictions.py` around lines 91 - 95, Replace the manual
vig-removal math in predictions.py with the shared helper: after computing
over_raw and under_raw via american_to_implied, call remove_vig(over_raw,
under_raw) from prop_model.py and assign its returned vig-adjusted over
probability to book_prob (or unpack its returned tuple if it returns both
adjusted probabilities). This ensures predictions.py uses the centralized
remove_vig logic instead of duplicating the over_raw/under_raw normalization.
api/services/prop_model.py (1)

227-240: Unused variable rows and consider removing unused imports.

Line 230: rows is fetched but never used.
Also: json (line 16), Any (line 22), and expit (line 26) are imported but unused.

Proposed fix
 import os
-import json
 import sqlite3
 import logging
 import hashlib
 from datetime import datetime, date
 from pathlib import Path
-from typing import Dict, List, Optional, Tuple, Any
+from typing import Dict, List, Optional, Tuple

 import numpy as np
 import pandas as pd
-from scipy.special import expit  # sigmoid
     def _load_calibration(self):
         """Load saved calibration from DB."""
         try:
-            rows = self.store.conn.execute(
+            self.store.conn.execute(
                 "SELECT * FROM calibration_store"
             ).fetchall()
+            # Note: calibration_store data currently unused; Beta params fetched on-demand
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/prop_model.py` around lines 227 - 240, The _load_calibration
method fetches rows into the local variable rows but never uses them—remove the
unused fetch (the execute(...).fetchall() assigned to rows) or, if those rows
were intended to initialize state, use them to populate calibration structures;
update the function _load_calibration accordingly to only query error_patterns
if calibration table rows are not needed. Also remove the unused imports json,
Any, and expit from the module top-level imports to eliminate dead imports and
linter complaints (search for json, Any, expit in the file and delete their
import statements if they are indeed unused).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/routes/predictions.py`:
- Around line 99-104: The try-except in the predictions route silently swallows
errors when calling mlb.build_player_features(req.player, req.game_date); add a
module-level logger (import logging and logger = logging.getLogger(__name__))
and replace the bare "except Exception as e: pass" with logging the exception
(e.g., logger.exception or logger.error(..., exc_info=True)) and then optionally
continue graceful degradation; reference mlb.build_player_features and
features.update so the logged message includes context (player, game_date,
event_id) to aid debugging.
- Around line 203-218: The try/except around model.predict is currently
swallowing all errors; update the block that calls model.predict to catch
Exception as e, log the error (including event_id and
prop["player"]/prop["market"]/prop["book"] and the traceback) via the existing
logger or Python logging, and also append a short error object (e.g.,
{"event_id": event_id, "prop": prop, "error": str(e)}) to a new errors list so
the live endpoint can return both all_predictions and errors; keep adding
successful results to all_predictions as before (refer to model.predict,
all_predictions, event_id, and prop in your changes).

In `@api/services/dfs_tracker.py`:
- Around line 96-114: The computed singles variable can go negative when hits <
doubles + triples + homers; clamp singles to zero before using it in the points
calculation (replace singles = hits - doubles - triples - homers with a
non-negative value, e.g. singles = max(0, hits - doubles - triples - homers)),
then proceed to compute pts using singles, doubles, triples, homers and the
stats/rules dictionaries as before so negative singles cannot reduce the
returned score.
- Around line 324-333: Remove the hardcoded CONTEXT7_MCP_CONFIG constant (the
mcpServers/context7 block that includes the leaked CONTEXT7_API_KEY) from
dfs_tracker.py; instead, load MCP configuration from a secure external source
(environment variables or the app config) and update any code that referenced
CONTEXT7_MCP_CONFIG to read the config via that secure accessor (e.g.,
settings.get("CONTEXT7_MCP_CONFIG") or os.environ["CONTEXT7_API_KEY"]) so no
secret literal remains in the service file.

In `@api/services/error_logger.py`:
- Around line 172-176: SelfCorrectionEngine.run_analysis currently produces
JSONL correction deltas but never persists them to the shared store, so update
run_analysis to persist its correction deltas into the same SQLite
error_patterns table used by CalibrationLayer (or call an
ErrorStore.insert_correction helper); ensure persisted rows match the schema
expected by CalibrationLayer.refresh_corrections/CalibrationLayer._corrections,
commit the transaction, and then either call
CalibrationLayer.refresh_corrections or emit an event to trigger a refresh so
corrections become active; touch SelfCorrectionEngine.run_analysis, ErrorStore
(add insert method if missing), and ensure CalibrationLayer.refresh_corrections
accepts and loads those new rows.

In `@api/services/mlb_data.py`:
- Around line 411-430: build_player_features() currently emits keys like
hits_avg_7/hr_avg_7/k_avg_7 but _raw_predict() in prop_model.py expects
recent_avg, season_avg, park_factor, pitcher_era, and is_home; when XGBoost is
missing those rolling stats are ignored. Fix by adding a mapping step (either
inside build_player_features or immediately before calling _raw_predict in the
prediction flow) that translates the MLB-enriched keys to the fallback names:
map hits_avg_7 -> recent_avg, hits_avg_30 -> season_avg (or choose the most
appropriate stat), add park_factor (from stadium data or default 1.0),
pitcher_era (from pitcher data or default 4.0), and is_home (from game context
or False); ensure the final dict passed into prop_model._raw_predict contains
those exact keys so .get() in the heuristic picks up the computed values instead
of falling back to defaults.

In `@api/services/odds_fetcher.py`:
- Around line 31-34: The API_KEYS list currently uses hardcoded fallback
defaults via os.getenv in API_KEYS; remove those literal keys and require
environment variables instead (e.g., change API_KEYS =
[os.getenv("ODDS_API_KEY_1"), os.getenv("ODDS_API_KEY_2")] and validate that
they are present), and add a clear runtime error if any are missing (raise
RuntimeError or log+exit) so the service never falls back to embedded secrets;
update any code that reads API_KEYS to handle None-safe validation and document
that the keys must be provided via environment or secret manager.
- Line 46: The type annotation for self._store uses Any but Any is not imported,
causing a NameError at runtime; fix this by importing Any from typing (e.g., add
Any to the existing typing import statement) so the annotation Dict[str,
Tuple[float, Any]] in odds_fetcher.py is valid and resolves correctly at
runtime.

In `@api/services/prop_model.py`:
- Around line 49-52: The ErrorStore currently opens a synchronous sqlite3
connection in __init__ (self.conn = sqlite3.connect(...),
check_same_thread=False) and calls synchronous methods (_init_tables(),
.execute(), .commit(), pd.read_sql()) which block the event loop; refactor to
use aiosqlite by replacing sqlite3.connect with aiosqlite.connect and making
ErrorStore initialization asynchronous (e.g., an async classmethod like
ErrorStore.create or an async init coroutine) so callers (get_model) can await
it, convert all DB calls in methods of ErrorStore to await conn.execute/await
conn.commit/await conn.execute_fetchall and, instead of pd.read_sql, fetch rows
via aiosqlite and construct DataFrame with pd.DataFrame.from_records; remove
check_same_thread and ensure _init_tables is converted to an async method that
uses await for executing CREATE TABLE statements.
- Around line 278-283: The L1 calibration uses an unconventional weighting (p_l1
= (a * p + b * beta_mean) / (a + b)) that gives more weight to the raw
prediction when successes (a) are high and to the historical mean when failures
(b) are high; either document this rationale or change to a standard shrinkage.
Update the L1 block around variables beta_mean, p_l1, a, b, and p in
prop_model.py: either add a concise comment explaining why this custom weighting
was chosen (e.g., backtest results, domain constraint, intent to weight by
successes) and what calibration behavior it yields, or replace the formula with
a conventional posterior/shrinkage expression (e.g., weight by counts
consistently toward the prior) and run/mention verification tests to confirm
expected calibration before merge.

In `@context7/setup.md`:
- Around line 99-118: Replace the hardcoded API key in both the curl example and
the Python get_docs function with an environment variable reference; update the
curl Authorization header to use $CONTEXT7_API_KEY and modify get_docs to read
the key from os.environ (add an import for os) and use f"Bearer
{os.environ['CONTEXT7_API_KEY']}" for the headers, ensuring no literal keys
remain in the examples.
- Around line 6-10: Remove the hardcoded Context7 API keys from the
documentation block and replace them with a placeholder (e.g.
<YOUR_CONTEXT7_API_KEY>) and an instruction to obtain the key from the Context7
settings, and update all examples to reference an environment variable (e.g.
CONTEXT7_API_KEY) instead; also mark the exposed keys as compromised so they are
rotated immediately. Locate the markdown code block that currently contains the
two keys (the block showing "ctx7sk-8e246594-..." and "ctx7sk-5c73433a-...") and
replace its contents with the placeholder text and a short note to use
process/env configuration for real keys. Ensure no real keys remain anywhere in
the file and add a reminder comment to rotate the leaked keys.

In `@requirements.txt`:
- Line 49: Remove the duplicate dependency entry for "httpx==0.27.0" in
requirements.txt by deleting the redundant line so only one declaration remains
(keep the existing single correct occurrence and remove the second one).
- Around line 25-27: The requirements file lists vulnerable and duplicated
dependencies: update aiohttp to >=3.13.3, requests to >=2.32.5, and scikit-learn
to >=1.8.0 by changing the version pins for aiohttp, requests, and scikit-learn
respectively, and remove the duplicated httpx==0.27.0 entry (keep a single httpx
line if needed, consider bumping httpx if a newer safe version exists); ensure
the changes replace the existing pins for aiohttp, requests, scikit-learn and
eliminate the duplicate httpx entry.

---

Nitpick comments:
In `@api/routes/predictions.py`:
- Around line 130-134: The PropBacktester import is inside the request handler
causing repeated imports; move "from api.services.dfs_tracker import
PropBacktester" to the module-level imports at the top of predictions.py, then
in the handler keep creating bt = PropBacktester() and calling
bt.kelly_criterion(...) and bt.half_kelly(...); ensure no other local references
to the import remain and run tests to confirm no side effects from changing
import location.
- Around line 91-95: Replace the manual vig-removal math in predictions.py with
the shared helper: after computing over_raw and under_raw via
american_to_implied, call remove_vig(over_raw, under_raw) from prop_model.py and
assign its returned vig-adjusted over probability to book_prob (or unpack its
returned tuple if it returns both adjusted probabilities). This ensures
predictions.py uses the centralized remove_vig logic instead of duplicating the
over_raw/under_raw normalization.

In `@api/services/error_logger.py`:
- Around line 319-320: The module currently creates module-level singletons
_prop_logger = PropIQLogger() and _self_correction =
SelfCorrectionEngine(_prop_logger) at import time, which couples configuration
and makes testing hard; change to lazy initialization or a factory by replacing
these direct instantiations with either (a) getter functions like
get_prop_logger() and get_self_correction() that create and cache the instances
on first call, or (b) a factory function/class that accepts dependencies and
returns configured instances of PropIQLogger and SelfCorrectionEngine, and
update all call sites to obtain instances via these getters/factory to allow
injecting mocks and configuration during tests.
- Around line 98-120: The file currently writes prediction outcomes to a JSONL
file using log_prediction_outcome (PREDICTION_LOG_FILE and _write), but the same
events are also persisted to the SQLite prediction_log via
ErrorStore.log_prediction, causing divergent metrics; consolidate to one source
of truth (prefer the SQLite prediction_log). Replace direct JSONL writes by
routing all prediction logging through ErrorStore.log_prediction (update callers
that currently call PropIQLogger.log_prediction_outcome and any model-level
calls to instead call ErrorStore.log_prediction), remove or deprecate
log_prediction_outcome's JSONL write (or make it a thin forwarder to
ErrorStore.log_prediction), and ensure recorded fields and types (player,
prop_type, model_prob, book_prob, actual_result, edge, ts) match the DB schema;
update any tests or consumers that read PREDICTION_LOG_FILE to use the DB
instead.

In `@api/services/mlb_data.py`:
- Around line 443-444: In get_pitcher_context(), remove the unused pandas
DataFrame creation: delete the import pandas as pd and the line creating df =
pd.DataFrame(log) (or keep the import only if used elsewhere in the module) and
ensure the function uses the existing 'log' variable directly; locate these
lines inside the get_pitcher_context() function and remove them so there are no
unused variables or imports.
- Line 139: The loop uses an unused variable named pid in the iteration "for
pid, pdata in players.items()"; rename pid to _ or _pid (e.g., "for _pid, pdata
in players.items()" or "for _, pdata in players.items()") to signal it is
intentionally unused and satisfy linters without changing behavior; update any
related references if present (none expected since pid is unused).

In `@api/services/odds_fetcher.py`:
- Around line 147-166: Annotate the mutable class attributes PROP_MARKETS and
GAME_MARKETS with typing.ClassVar to declare they are class-level variables for
type checkers: import ClassVar from typing and change the declarations to
PROP_MARKETS: ClassVar[list[str]] = [...] and GAME_MARKETS: ClassVar[list[str]]
= [...]; keep the existing list contents unchanged so runtime behavior is the
same but static analysis knows these are class variables.
- Around line 225-236: The except Exception as e block only logs a generic
message; update it to log full exception details (type and traceback) before
retrying by replacing logger.error(f"Unexpected error: {e}") with a call that
includes exception info (e.g., logger.exception(...) or logger.error(...,
exc_info=True)) in the same error-handling scope (the except Exception block) so
the traceback is captured for debugging; keep the existing backoff and sleep
behavior unchanged.

In `@api/services/prop_model.py`:
- Around line 227-240: The _load_calibration method fetches rows into the local
variable rows but never uses them—remove the unused fetch (the
execute(...).fetchall() assigned to rows) or, if those rows were intended to
initialize state, use them to populate calibration structures; update the
function _load_calibration accordingly to only query error_patterns if
calibration table rows are not needed. Also remove the unused imports json, Any,
and expit from the module top-level imports to eliminate dead imports and linter
complaints (search for json, Any, expit in the file and delete their import
statements if they are indeed unused).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3de3bd50-dbba-4c2e-b0c5-10f8f1cb009e

📥 Commits

Reviewing files that changed from the base of the PR and between 7230a0b and 6bb2958.

📒 Files selected for processing (8)
  • api/routes/predictions.py
  • api/services/dfs_tracker.py
  • api/services/error_logger.py
  • api/services/mlb_data.py
  • api/services/odds_fetcher.py
  • api/services/prop_model.py
  • context7/setup.md
  • requirements.txt

Comment thread api/routes/predictions.py
Comment on lines +99 to +104
if req.event_id:
try:
player_features = mlb.build_player_features(req.player, req.game_date)
features.update(player_features)
except Exception as e:
pass # gracefully degrade

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Log exceptions instead of silently ignoring them.

The try-except-pass pattern makes debugging impossible. At minimum, log the error for observability.

Proposed fix
     if req.event_id:
         try:
             player_features = mlb.build_player_features(req.player, req.game_date)
             features.update(player_features)
-        except Exception as e:
-            pass  # gracefully degrade
+        except Exception:
+            logger.warning(f"Failed to build MLB features for {req.player}", exc_info=True)
+            # Continue with empty features — graceful degradation

Add at top of file:

import logging
logger = logging.getLogger(__name__)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if req.event_id:
try:
player_features = mlb.build_player_features(req.player, req.game_date)
features.update(player_features)
except Exception as e:
pass # gracefully degrade
if req.event_id:
try:
player_features = mlb.build_player_features(req.player, req.game_date)
features.update(player_features)
except Exception:
logger.warning(f"Failed to build MLB features for {req.player}", exc_info=True)
# Continue with empty features — graceful degradation
🧰 Tools
🪛 GitHub Check: Codacy Static Code Analysis

[warning] 103-103: api/routes/predictions.py#L103
Try, Except, Pass detected.


[warning] 103-103: api/routes/predictions.py#L103
local variable 'e' is assigned to but never used (F841)

🪛 Ruff (0.15.6)

[error] 103-104: try-except-pass detected, consider logging the exception

(S110)


[warning] 103-103: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/routes/predictions.py` around lines 99 - 104, The try-except in the
predictions route silently swallows errors when calling
mlb.build_player_features(req.player, req.game_date); add a module-level logger
(import logging and logger = logging.getLogger(__name__)) and replace the bare
"except Exception as e: pass" with logging the exception (e.g., logger.exception
or logger.error(..., exc_info=True)) and then optionally continue graceful
degradation; reference mlb.build_player_features and features.update so the
logged message includes context (player, game_date, event_id) to aid debugging.

Comment thread api/routes/predictions.py
Comment on lines +203 to +218
try:
result = model.predict(
player=prop["player"],
prop_type=prop["market"],
features={},
book_prob=prop["implied_prob"],
line_value=prop["line"],
book_name=prop["book"],
persist=False,
)
result["event_id"] = event_id
result["home_team"] = event.get("home_team")
result["away_team"] = event.get("away_team")
all_predictions.append(result)
except Exception:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Log skipped predictions in live endpoint.

Silently continuing on exceptions hides systematic failures. Consider accumulating errors for the response or logging them.

Proposed fix
             try:
                 result = model.predict(
                     ...
                 )
                 ...
                 all_predictions.append(result)
-            except Exception:
-                continue
+            except Exception:
+                logger.debug(f"Skipping prop for {prop['player']}/{prop['market']}", exc_info=True)
+                continue
🧰 Tools
🪛 GitHub Check: Codacy Static Code Analysis

[warning] 217-217: api/routes/predictions.py#L217
Try, Except, Continue detected.

🪛 Ruff (0.15.6)

[error] 217-218: try-except-continue detected, consider logging the exception

(S112)


[warning] 217-217: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/routes/predictions.py` around lines 203 - 218, The try/except around
model.predict is currently swallowing all errors; update the block that calls
model.predict to catch Exception as e, log the error (including event_id and
prop["player"]/prop["market"]/prop["book"] and the traceback) via the existing
logger or Python logging, and also append a short error object (e.g.,
{"event_id": event_id, "prop": prop, "error": str(e)}) to a new errors list so
the live endpoint can return both all_predictions and errors; keep adding
successful results to all_predictions as before (refer to model.predict,
all_predictions, event_id, and prop in your changes).

Comment on lines +96 to +114
hits = stats.get("hits", 0)
doubles = stats.get("doubles", 0)
triples = stats.get("triples", 0)
homers = stats.get("home_runs", 0)
singles = hits - doubles - triples - homers

pts = (
singles * s["single"]
+ doubles * s["double"]
+ triples * s["triple"]
+ homers * s["home_run"]
+ stats.get("rbi", 0) * s["rbi"]
+ stats.get("runs", 0) * s["run"]
+ stats.get("walks", 0) * s["walk"]
+ stats.get("hbp", 0) * s["hbp"]
+ stats.get("stolen_bases", 0) * s["stolen_base"]
+ stats.get("strikeouts", 0) * s["strikeout_batter"]
)
return round(pts, 2)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard against negative singles count.

If hits is less than doubles + triples + homers (due to data inconsistencies), singles becomes negative, corrupting the score.

Proposed fix
         singles = hits - doubles - triples - homers
+        singles = max(0, singles)  # Guard against inconsistent data
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/dfs_tracker.py` around lines 96 - 114, The computed singles
variable can go negative when hits < doubles + triples + homers; clamp singles
to zero before using it in the points calculation (replace singles = hits -
doubles - triples - homers with a non-negative value, e.g. singles = max(0, hits
- doubles - triples - homers)), then proceed to compute pts using singles,
doubles, triples, homers and the stats/rules dictionaries as before so negative
singles cannot reduce the returned score.

Comment on lines +324 to +333
CONTEXT7_MCP_CONFIG = {
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp@latest"],
"env": {
"CONTEXT7_API_KEY": "ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"
}
}
}

@coderabbitai coderabbitai Bot Mar 20, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Remove hardcoded API key.

This constant embeds the same leaked Context7 API key. This code block appears to be documentation/config that doesn't belong in a service module.

Proposed fix

Remove this block entirely from the service file — it belongs in documentation or a separate config template:

-# ─────────────────────────────────────────────
-# Context7 integration setup (documentation)
-# ─────────────────────────────────────────────
-CONTEXT7_MCP_CONFIG = {
-    "mcpServers": {
-        "context7": {
-            "command": "npx",
-            "args": ["-y", "@upstash/context7-mcp@latest"],
-            "env": {
-                "CONTEXT7_API_KEY": "ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"
-            }
-        }
-    }
-}
🧰 Tools
🪛 Gitleaks (8.30.0)

[high] 330-330: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/dfs_tracker.py` around lines 324 - 333, Remove the hardcoded
CONTEXT7_MCP_CONFIG constant (the mcpServers/context7 block that includes the
leaked CONTEXT7_API_KEY) from dfs_tracker.py; instead, load MCP configuration
from a secure external source (environment variables or the app config) and
update any code that referenced CONTEXT7_MCP_CONFIG to read the config via that
secure accessor (e.g., settings.get("CONTEXT7_MCP_CONFIG") or
os.environ["CONTEXT7_API_KEY"]) so no secret literal remains in the service
file.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Micro-Learning Topic: Hard-coded API key (Detected by phrase)

Matched on "hardcoded API key"

What is this? (2min video)

Poor or missing authentication/authorization schemes allow an adversary to anonymously execute functionality within the mobile app or backend server used by the mobile app. Weaker authentication for mobile apps is fairly prevalent due to a mobile device's input form factor. To detect poor authentication schemes, testers can perform binary attacks against the mobile app while it is in 'offline' mode. Through the attack, the tester will force the app to bypass offline authentication and then execute functionality that should require offline authentication. To test for poor authorization schemes, testers can perform binary attacks against the mobile app and try to execute privileged functionality that should only be executable with a user of higher privilege while the mobile app is in 'offline' mode.

This kind of vulnerability occurs when the app uses a hardcoded API key to communicate to the server. It is possible for an attacker to use the API key and make direct calls to the server.

Try a challenge in Secure Code Warrior

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Comment on lines +172 to +176
class SelfCorrectionEngine:
"""
Analyzes prediction logs and fires alerts when systematic errors are detected.
Generates correction deltas that feed back into CalibrationLayer.
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Corrections from SelfCorrectionEngine are not integrated with CalibrationLayer.

SelfCorrectionEngine.run_analysis() computes correction deltas, but these are not fed back into CalibrationLayer._corrections (in prop_model.py). The CalibrationLayer loads corrections only from its SQLite error_patterns table via refresh_corrections().

This creates two parallel correction detection systems that don't communicate:

  1. SelfCorrectionEngine → JSONL-based, fires alerts but corrections are unused
  2. ErrorStore.detect_error_patterns() → SQLite-based, corrections applied to model

Would you like me to propose an integration pattern where SelfCorrectionEngine updates the SQLite error_patterns table, or where CalibrationLayer reads from both sources?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/error_logger.py` around lines 172 - 176,
SelfCorrectionEngine.run_analysis currently produces JSONL correction deltas but
never persists them to the shared store, so update run_analysis to persist its
correction deltas into the same SQLite error_patterns table used by
CalibrationLayer (or call an ErrorStore.insert_correction helper); ensure
persisted rows match the schema expected by
CalibrationLayer.refresh_corrections/CalibrationLayer._corrections, commit the
transaction, and then either call CalibrationLayer.refresh_corrections or emit
an event to trigger a refresh so corrections become active; touch
SelfCorrectionEngine.run_analysis, ErrorStore (add insert method if missing),
and ensure CalibrationLayer.refresh_corrections accepts and loads those new
rows.

Comment on lines +278 to +283
# L1: Bayesian posterior mean blended with raw
beta_mean = a / (a + b)
p_l1 = (a * p + b * beta_mean) / (a + b)

# L2: shrink toward efficient market (book line)
p_l2 = (1 - shrink) * p_l1 + shrink * book_p

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's see the full context around lines 278-283
sed -n '270,290p' api/services/prop_model.py

Repository: jaayslaughter-cpu/mework

Length of output: 803


🏁 Script executed:

# Let's also see what happens before - where a, b, p are defined
sed -n '260,283p' api/services/prop_model.py

Repository: jaayslaughter-cpu/mework

Length of output: 996


🏁 Script executed:

# Search for where 'a' and 'b' are assigned/calculated in this function
sed -n '200,283p' api/services/prop_model.py | grep -n "a\|b\|beta"

Repository: jaayslaughter-cpu/mework

Length of output: 3238


🏁 Script executed:

# Get broader context to understand the function structure
sed -n '240,300p' api/services/prop_model.py

Repository: jaayslaughter-cpu/mework

Length of output: 2799


🏁 Script executed:

# Find the full update method implementation
sed -n '298,350p' api/services/prop_model.py

Repository: jaayslaughter-cpu/mework

Length of output: 2182


🏁 Script executed:

# Search for any documentation or comments about the calibration formula design
grep -n "blended\|shrinkage\|weight" api/services/prop_model.py

Repository: jaayslaughter-cpu/mework

Length of output: 195


🏁 Script executed:

# Check if there are any tests or docstrings that explain the rationale
fd -e py -e md . --exec grep -l "calibrate\|p_l1\|beta.*shrink" {} \;

Repository: jaayslaughter-cpu/mework

Length of output: 124


Document or verify the L1 calibration formula rationale.

The formula p_l1 = (a * p + b * beta_mean) / (a + b) uses an unconventional shrinkage approach: it weights the raw prediction by success count and the historical mean by failure count. This diverges from standard Bayesian posterior estimation.

Either add a comment explaining why this custom weighting is intentional (e.g., empirically superior in backtests, domain-specific calibration requirement), or standardize to a conventional shrinkage formula. Verify this design produces the calibration behavior you expect before deployment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/services/prop_model.py` around lines 278 - 283, The L1 calibration uses
an unconventional weighting (p_l1 = (a * p + b * beta_mean) / (a + b)) that
gives more weight to the raw prediction when successes (a) are high and to the
historical mean when failures (b) are high; either document this rationale or
change to a standard shrinkage. Update the L1 block around variables beta_mean,
p_l1, a, b, and p in prop_model.py: either add a concise comment explaining why
this custom weighting was chosen (e.g., backtest results, domain constraint,
intent to weight by successes) and what calibration behavior it yields, or
replace the formula with a conventional posterior/shrinkage expression (e.g.,
weight by counts consistently toward the prior) and run/mention verification
tests to confirm expected calibration before merge.

Comment thread context7/setup.md
Comment on lines +6 to +10
## Your API Keys
```
ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e (primary)
ctx7sk-5c73433a-6430-4a2f-8df7-fe3f2c768d28 (backup)
```

@coderabbitai coderabbitai Bot Mar 20, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Remove hardcoded API keys from documentation.

Real API keys are committed to version control. These keys should be:

  1. Rotated immediately (consider them compromised)
  2. Replaced with placeholder values in documentation
🔐 Proposed fix
 ## Your API Keys
-```
-ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e   (primary)
-ctx7sk-5c73433a-6430-4a2f-8df7-fe3f2c768d28   (backup)
-```
+```text
+<YOUR_CONTEXT7_API_KEY>   (get from https://context7.com/settings)
+```

Update all config examples to use environment variable references:

       "env": {
-        "CONTEXT7_API_KEY": "ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"
+        "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}"
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Your API Keys
```
ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e (primary)
ctx7sk-5c73433a-6430-4a2f-8df7-fe3f2c768d28 (backup)
```
## Your API Keys
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 7-7: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@context7/setup.md` around lines 6 - 10, Remove the hardcoded Context7 API
keys from the documentation block and replace them with a placeholder (e.g.
<YOUR_CONTEXT7_API_KEY>) and an instruction to obtain the key from the Context7
settings, and update all examples to reference an environment variable (e.g.
CONTEXT7_API_KEY) instead; also mark the exposed keys as compromised so they are
rotated immediately. Locate the markdown code block that currently contains the
two keys (the block showing "ctx7sk-8e246594-..." and "ctx7sk-5c73433a-...") and
replace its contents with the placeholder text and a short note to use
process/env configuration for real keys. Ensure no real keys remain anywhere in
the file and add a reminder comment to rotate the leaked keys.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Micro-Learning Topic: Hard-coded API key (Detected by phrase)

Matched on "hardcoded API key"

What is this? (2min video)

Poor or missing authentication/authorization schemes allow an adversary to anonymously execute functionality within the mobile app or backend server used by the mobile app. Weaker authentication for mobile apps is fairly prevalent due to a mobile device's input form factor. To detect poor authentication schemes, testers can perform binary attacks against the mobile app while it is in 'offline' mode. Through the attack, the tester will force the app to bypass offline authentication and then execute functionality that should require offline authentication. To test for poor authorization schemes, testers can perform binary attacks against the mobile app and try to execute privileged functionality that should only be executable with a user of higher privilege while the mobile app is in 'offline' mode.

This kind of vulnerability occurs when the app uses a hardcoded API key to communicate to the server. It is possible for an attacker to use the API key and make direct calls to the server.

Try a challenge in Secure Code Warrior

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Comment thread context7/setup.md
Comment on lines +99 to +118
```bash
curl -X GET "https://context7.com/api/v2/libs/search?libraryName=next.js&query=app+router+ssr" \
-H "Authorization: Bearer ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"
```

```python
# In your Tasklet agent or ETL pipeline
import requests

def get_docs(library: str, query: str) -> str:
resp = requests.get(
"https://context7.com/api/v2/libs/search",
params={"libraryName": library, "query": query},
headers={"Authorization": "Bearer ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"},
timeout=10,
)
if resp.status_code == 200:
return resp.json()
return {}
```

@coderabbitai coderabbitai Bot Mar 20, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove hardcoded API key from code examples.

The REST API and Python examples embed the same leaked key. Use environment variable references instead.

Proposed fix
 ```bash
 curl -X GET "https://context7.com/api/v2/libs/search?libraryName=next.js&query=app+router+ssr" \
-  -H "Authorization: Bearer ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"
+  -H "Authorization: Bearer $CONTEXT7_API_KEY"
# In your Tasklet agent or ETL pipeline
+import os
import requests

def get_docs(library: str, query: str) -> str:
    resp = requests.get(
        "https://context7.com/api/v2/libs/search",
        params={"libraryName": library, "query": query},
-        headers={"Authorization": "Bearer ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"},
+        headers={"Authorization": f"Bearer {os.environ['CONTEXT7_API_KEY']}"},
        timeout=10,
    )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@context7/setup.md` around lines 99 - 118, Replace the hardcoded API key in
both the curl example and the Python get_docs function with an environment
variable reference; update the curl Authorization header to use
$CONTEXT7_API_KEY and modify get_docs to read the key from os.environ (add an
import for os) and use f"Bearer {os.environ['CONTEXT7_API_KEY']}" for the
headers, ensuring no literal keys remain in the examples.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Micro-Learning Topic: Hard-coded API key (Detected by phrase)

Matched on "hardcoded API key"

What is this? (2min video)

Poor or missing authentication/authorization schemes allow an adversary to anonymously execute functionality within the mobile app or backend server used by the mobile app. Weaker authentication for mobile apps is fairly prevalent due to a mobile device's input form factor. To detect poor authentication schemes, testers can perform binary attacks against the mobile app while it is in 'offline' mode. Through the attack, the tester will force the app to bypass offline authentication and then execute functionality that should require offline authentication. To test for poor authorization schemes, testers can perform binary attacks against the mobile app and try to execute privileged functionality that should only be executable with a user of higher privilege while the mobile app is in 'offline' mode.

This kind of vulnerability occurs when the app uses a hardcoded API key to communicate to the server. It is possible for an attacker to use the API key and make direct calls to the server.

Try a challenge in Secure Code Warrior

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Comment thread requirements.txt
Comment on lines +25 to +27
requests==2.31.0
httpx==0.27.0
aiohttp==3.9.3

@coderabbitai coderabbitai Bot Mar 20, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What are the latest stable versions of aiohttp, requests, and scikit-learn Python packages in March 2026?

💡 Result:

As of March 2026, the latest stable versions are: - aiohttp: 3.13.3 (released January 3, 2026) - requests: 2.32.5 (released August 18, 2025) - scikit-learn: 1.8.0 (released December 10, 2025)

Citations:


🏁 Script executed:

# Check if we can find any references to the CVEs mentioned in the comment
# to verify they are real and associated with the correct versions
echo "Searching for CVE references mentioned in the review comment..."

# Search for the CVE identifiers mentioned
rg "CVE-2024-35195|CVE-2024-47081|CVE-2024-5206|GHSA-8495-4g3g-x7pr|GHSA-7gpw-8wmc-pm8g" 2>/dev/null || echo "No CVE references found in codebase"

# Check the actual requirements.txt file to confirm current versions and dependencies
echo -e "\n--- Checking requirements.txt ---"
if [ -f requirements.txt ]; then
  cat -n requirements.txt | grep -E "aiohttp|requests|scikit-learn|httpx"
fi

Repository: jaayslaughter-cpu/mework

Length of output: 317


🌐 Web query:

CVE-2024-35195 CVE-2024-47081 requests Python security vulnerability

💡 Result:

CVE-2024-35195 and CVE-2024-47081 are security vulnerabilities in the Python Requests HTTP library. CVE-2024-35195 (published May 20, 2024): In Requests prior to 2.32.0, using a Session where the first request to a host has verify=False causes all subsequent requests to that host in the same session to ignore certificate verification, due to connection pooling behavior. This can lead to man-in-the-middle attacks. CVSS v3.1: 5.6 (Medium). Fixed in Requests 2.32.0. Official advisory: GHSA-9wx4-h78v-vm56. Mitigation: Upgrade to >=2.32.0, avoid verify=False on first request, or close the session after such requests. CVE-2024-47081 (published June 9, 2025): In Requests prior to 2.32.4, a URL parsing flaw allows leakage of .netrc credentials to unintended hosts via malicious URLs (e.g., http://example.com:`@evil.com/`). Requires trust_env=True (default) and .netrc usage. CVSS v3.1: 5.3 (Medium). Fixed in Requests 2.32.4. Official advisory: GHSA-9hjg-9r4m-mvj7. Mitigation: Upgrade to >=2.32.4 or set trust_env=False on Session. Both are fixed in latest Requests 2.32.5 (Aug 2025). Upgrade immediately if using affected versions. No other major Requests vulnerabilities in 2024 match the query.

Citations:


🌐 Web query:

GHSA-8495-4g3g-x7pr GHSA-7gpw-8wmc-pm8g aiohttp security vulnerability

💡 Result:

GHSA-8495-4g3g-x7pr and GHSA-7gpw-8wmc-pm8g are two distinct security vulnerabilities in the aiohttp Python library. GHSA-8495-4g3g-x7pr (CVE-2024-52304): HTTP request smuggling due to incorrect parsing of newlines in chunk extensions by the pure Python parser. Affects versions up to 3.10.10, particularly when using pure Python aiohttp (without C extensions) or with AIOHTTP_NO_EXTENSIONS enabled. Severity: Medium (CVSS 6.3). Fixed in 3.10.11 via commit 259edc369075de63e6f3a4eaade058c62af0df71. GHSA-7gpw-8wmc-pm8g (CVE-2024-27306): Cross-site scripting (XSS) on index pages for static file handling when using web.static(..., show_index=True) and allowing arbitrary filenames. Users using a reverse proxy like nginx are unaffected. Affects versions up to 3.9.3. Severity: Medium (CVSS 6.1). Fixed in 3.9.4 via commit 28335525d1eac015a7e7584137678cbb6ff19397. Both are published in the GitHub Advisory Database and tracked by OSV/NVD. As of 2026-03-20, upgrade to aiohttp 3.10.11 or later (latest is 3.13.3) to mitigate these and other recent vulnerabilities.

Citations:


🌐 Web query:

CVE-2024-5206 scikit-learn security vulnerability

💡 Result:

CVE-2024-5206 is a medium-severity information disclosure vulnerability in scikit-learn's TfidfVectorizer (and CountVectorizer). In affected versions up to 1.4.1.post1, the stop_words_ attribute unexpectedly stored all tokens from the training data, including those discarded due to min_df or max_df thresholds. This could leak sensitive information like passwords or API keys if present in the training data and the trained model is exposed. CVSS v3.1 base score: 4.7 (MEDIUM), vector AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N. Published: June 6, 2024. Fixed in scikit-learn 1.5.0 (May 2024) via commit 70ca21f106b603b611da73012c9ade7cd8e438b8. Mitigation: Upgrade to scikit-learn >= 1.5.0 and retrain affected models. No known exploits.

Citations:


Update dependencies with known security vulnerabilities.

Static analysis flagged several MEDIUM severity CVEs:

  • aiohttp==3.9.3: HTTP request smuggling (GHSA-8495-4g3g-x7pr, CVSS 6.3) and XSS on static file indexes (GHSA-7gpw-8wmc-pm8g, CVSS 6.1). Update to ≥3.13.3.
  • requests==2.31.0: Certificate verification bypass (CVE-2024-35195, CVSS 5.6) and .netrc credential leak (CVE-2024-47081, CVSS 5.3). Update to ≥2.32.5.
  • scikit-learn==1.4.1: TfidfVectorizer sensitive data leak (CVE-2024-5206, CVSS 4.7). Update to ≥1.8.0.

Also, httpx==0.27.0 is duplicated on lines 26 and 49—remove one instance.

🔒 Proposed fix
-requests==2.31.0
+requests==2.32.5
 httpx==0.27.0
-aiohttp==3.9.3
+aiohttp==3.13.3
-scikit-learn==1.4.1
+scikit-learn==1.8.0

Remove duplicate httpx==0.27.0 from line 49.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
requests==2.31.0
httpx==0.27.0
aiohttp==3.9.3
requests==2.32.5
httpx==0.27.0
aiohttp==3.13.3
🧰 Tools
🪛 GitHub Check: Codacy Static Code Analysis

[warning] 25-25: requirements.txt#L25
Insecure dependency pypi/requests@2.31.0 (CVE-2024-35195: requests: subsequent requests to the same host ignore cert verification) (update to 2.32.0)


[warning] 25-25: requirements.txt#L25
Insecure dependency pypi/requests@2.31.0 (CVE-2024-47081: requests: Requests vulnerable to .netrc credentials leak via malicious URLs) (update to 2.32.4)


[warning] 27-27: requirements.txt#L27
Insecure dependency pypi/aiohttp@3.9.3 (CVE-2024-27306: aiohttp: XSS on index pages for static file handling) (update to 3.9.4)

🪛 OSV Scanner (2.3.3)

[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP vulnerable to brute-force leak of internal static file path components

(GHSA-54jq-c3m8-4m76)


[HIGH] 27-27: aiohttp 3.9.3: aiohttp vulnerable to Denial of Service when trying to parse malformed POST requests

(GHSA-5m98-qgg9-wh84)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP's unicode processing of header values could cause parsing discrepancies

(GHSA-69f9-5gxw-wvc2)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP vulnerable to denial of service through large payloads

(GHSA-6jhg-hg63-jvvf)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP's HTTP Parser auto_decompress feature is vulnerable to zip bomb

(GHSA-6mq8-rvhq-8wgg)


[HIGH] 27-27: aiohttp 3.9.3: aiohttp Cross-site Scripting vulnerability on index pages for static file handling

(GHSA-7gpw-8wmc-pm8g)


[HIGH] 27-27: aiohttp 3.9.3: aiohttp allows request smuggling due to incorrect parsing of chunk extensions

(GHSA-8495-4g3g-x7pr)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP is vulnerable to HTTP Request/Response Smuggling through incorrect parsing of chunked trailer sections

(GHSA-9548-qrrj-x5pj)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP Vulnerable to Cookie Parser Warning Storm

(GHSA-fh55-r93g-j68g)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP vulnerable to DoS through chunked messages

(GHSA-g84x-mcqj-x9qq)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP vulnerable to DoS when bypassing asserts

(GHSA-jj3x-wxrx-4x23)


[HIGH] 27-27: aiohttp 3.9.3: AIOHTTP has unicode match groups in regexes for ASCII protocol elements

(GHSA-mqqc-3gqh-h2x8)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@requirements.txt` around lines 25 - 27, The requirements file lists
vulnerable and duplicated dependencies: update aiohttp to >=3.13.3, requests to
>=2.32.5, and scikit-learn to >=1.8.0 by changing the version pins for aiohttp,
requests, and scikit-learn respectively, and remove the duplicated httpx==0.27.0
entry (keep a single httpx line if needed, consider bumping httpx if a newer
safe version exists); ensure the changes replace the existing pins for aiohttp,
requests, scikit-learn and eliminate the duplicate httpx entry.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Micro-Learning Topic: Cross-site scripting (Detected by phrase)

Matched on "Cross-site scripting"

Cross-site scripting vulnerabilities occur when unescaped input is rendered into a page displayed to the user. When HTML or script is included in the input, it will be processed by a user's browser as HTML or script and can alter the appearance of the page or execute malicious scripts in their user context.

Try a challenge in Secure Code Warrior

Helpful references

Micro-Learning Topic: Denial of service (Detected by phrase)

Matched on "Denial of Service"

The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed. There are many ways to make a service unavailable for legitimate users by manipulating network packets, programming, logical, or resources handling vulnerabilities, among others. Source: https://www.owasp.org/index.php/Denial_of_Service

Try a challenge in Secure Code Warrior

Micro-Learning Topic: Information disclosure (Detected by phrase)

Matched on "information disclosure"

Many web applications and APIs do not properly protect sensitive data, such as financial, healthcare, and PII. Attackers may steal or modify such weakly protected data to conduct credit card fraud, identity theft, or other crimes. Sensitive data may be compromised without extra protection, such as encryption at rest or in transit, and requires special precautions when exchanged with the browser. Source: https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project

Try a challenge in Secure Code Warrior

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skipped: comment is from another GitHub bot.

Comment thread requirements.txt
# ── Testing ─────────────────────────────────
pytest==8.1.1
pytest-asyncio==0.23.5
httpx==0.27.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate httpx entry.

httpx==0.27.0 is already declared on line 26.

Proposed fix
 # ── Testing ─────────────────────────────────
 pytest==8.1.1
 pytest-asyncio==0.23.5
-httpx==0.27.0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
httpx==0.27.0
# ── Testing ─────────────────────────────────
pytest==8.1.1
pytest-asyncio==0.23.5
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@requirements.txt` at line 49, Remove the duplicate dependency entry for
"httpx==0.27.0" in requirements.txt by deleting the redundant line so only one
declaration remains (keep the existing single correct occurrence and remove the
second one).

@secure-code-warrior-for-github

Copy link
Copy Markdown

Micro-Learning Topic: Hard-coded API key (Detected by phrase)

Matched on "hardcoded API key"

What is this? (2min video)

Poor or missing authentication/authorization schemes allow an adversary to anonymously execute functionality within the mobile app or backend server used by the mobile app. Weaker authentication for mobile apps is fairly prevalent due to a mobile device's input form factor. To detect poor authentication schemes, testers can perform binary attacks against the mobile app while it is in 'offline' mode. Through the attack, the tester will force the app to bypass offline authentication and then execute functionality that should require offline authentication. To test for poor authorization schemes, testers can perform binary attacks against the mobile app and try to execute privileged functionality that should only be executable with a user of higher privilege while the mobile app is in 'offline' mode.

This kind of vulnerability occurs when the app uses a hardcoded API key to communicate to the server. It is possible for an attacker to use the API key and make direct calls to the server.

Try a challenge in Secure Code Warrior

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

16 issues found across 8 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="api/services/prop_model.py">

<violation number="1" location="api/services/prop_model.py:230">
P2: `rows` from `calibration_store` is fetched into memory but never used — the full table is loaded and immediately discarded. Every subsequent `calibrate()` call queries the DB again via `_get_beta_params()`. Either cache the data here or remove the unnecessary query.</violation>

<violation number="2" location="api/services/prop_model.py:280">
P1: The L1 Bayesian shrinkage formula has asymmetric weighting that doesn't scale with sample size. With balanced hit/miss rates, the shrinkage is identical whether you have 4 or 10,000 observations. A standard blend would weight by total evidence:
```python
n = a + b - self.prior_alpha - self.prior_beta  # effective observations
w = n / (n + self.prior_alpha + self.prior_beta)
p_l1 = w * beta_mean + (1 - w) * p
```</violation>

<violation number="3" location="api/services/prop_model.py:352">
P1: Feature names returned by `build_player_features()` (e.g. `hits_avg_7`, `hr_avg_7`, `k_avg_7`) do not match the keys expected by the `_raw_predict()` fallback heuristic (`recent_avg`, `season_avg`, `park_factor`, `pitcher_era`, `is_home`). When XGBoost is unavailable and the route auto-enriches features via `build_player_features`, all `.get()` calls here fall back to defaults (0, 1.0, etc.), and the computed rolling averages are silently ignored.</violation>

<violation number="4" location="api/services/prop_model.py:364">
P1: XGBoost `predict_proba` requires features in the same column order as training data. Creating a DataFrame from a dict does not guarantee column ordering matches what the model was trained on, which can silently produce incorrect predictions. Reindex the DataFrame to match `self._xgb_model.get_booster().feature_names` before predicting.</violation>
</file>

<file name="requirements.txt">

<violation number="1" location="requirements.txt:26">
P3: `httpx` is declared twice in requirements; keep a single entry to avoid dependency drift and maintenance errors.</violation>

<violation number="2" location="requirements.txt:27">
P1: Update dependencies with known security vulnerabilities: `aiohttp==3.9.3` has multiple HIGH severity advisories (HTTP request smuggling, DoS, XSS — update to ≥3.13.3), `requests==2.31.0` has CVE-2024-35195 cert verification bypass and CVE-2024-47081 .netrc credential leak (update to ≥2.32.5), and `scikit-learn==1.4.1` has CVE-2024-5206 sensitive data leak (update to ≥1.5.0).</violation>
</file>

<file name="context7/setup.md">

<violation number="1" location="context7/setup.md:8">
P0: Remove hardcoded API keys from the committed setup guide and replace them with placeholders/env-var references.</violation>
</file>

<file name="api/routes/predictions.py">

<violation number="1" location="api/routes/predictions.py:104">
P2: Broad `except Exception as e: pass` silently swallows all errors from feature building, including unexpected bugs. At minimum, log the exception so failures are observable. The captured `e` is also unused.</violation>

<violation number="2" location="api/routes/predictions.py:133">
P1: Kelly criterion is fed the vig-removed `book_prob` instead of the raw implied probability `over_raw`. Since `kelly_criterion` derives payout odds from its `book_prob` parameter, removing the vig first makes the odds look more favorable than they actually are, systematically over-sizing bet recommendations.</violation>
</file>

<file name="api/services/mlb_data.py">

<violation number="1" location="api/services/mlb_data.py:393">
P1: `get_pitcher_context()` returns early when batting game logs are missing, which drops available season pitching stats (ERA/WHIP/K9) for many pitchers.</violation>
</file>

<file name="api/services/odds_fetcher.py">

<violation number="1" location="api/services/odds_fetcher.py:32">
P0: Real API keys are hardcoded as default values. These secrets will be permanently in the repository history even if later removed. Use empty-string defaults (or raise on missing) and keep secrets in `.env` / a secret manager only.</violation>

<violation number="2" location="api/services/odds_fetcher.py:46">
P0: Missing `Any` import causes a runtime `NameError`. `Any` is used in the `Tuple[float, Any]` type annotation on this line but is not included in the `typing` import statement.</violation>
</file>

<file name="api/services/dfs_tracker.py">

<violation number="1" location="api/services/dfs_tracker.py:100">
P2: Guard against negative `singles` count. If input `stats` are inconsistent (e.g., `hits < doubles + triples + homers` due to data errors), `singles` becomes negative, corrupting the DFS score calculation.</violation>

<violation number="2" location="api/services/dfs_tracker.py:330">
P0: Remove the hardcoded API key from source and read it from environment variables.</violation>
</file>

<file name="api/services/error_logger.py">

<violation number="1" location="api/services/error_logger.py:84">
P2: Traceback capture uses `traceback.format_exc()` instead of the provided exception object, which can log empty/incorrect stack traces.</violation>

<violation number="2" location="api/services/error_logger.py:134">
P2: Malformed timestamp values can crash error-log reads because `ValueError` is not caught.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread context7/setup.md

## Your API Keys
```
ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e (primary)

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P0: Remove hardcoded API keys from the committed setup guide and replace them with placeholders/env-var references.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At context7/setup.md, line 8:

<comment>Remove hardcoded API keys from the committed setup guide and replace them with placeholders/env-var references.</comment>

<file context>
@@ -0,0 +1,146 @@
+
+## Your API Keys
+```
+ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e   (primary)
+ctx7sk-5c73433a-6430-4a2f-8df7-fe3f2c768d28   (backup)
+```
</file context>
Fix with Cubic

# Config
# ─────────────────────────────────────────────
API_KEYS = [
os.getenv("ODDS_API_KEY_1", "e4e30098807a9eece674d85e30471f03"),

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P0: Real API keys are hardcoded as default values. These secrets will be permanently in the repository history even if later removed. Use empty-string defaults (or raise on missing) and keep secrets in .env / a secret manager only.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/services/odds_fetcher.py, line 32:

<comment>Real API keys are hardcoded as default values. These secrets will be permanently in the repository history even if later removed. Use empty-string defaults (or raise on missing) and keep secrets in `.env` / a secret manager only.</comment>

<file context>
@@ -0,0 +1,422 @@
+# Config
+# ─────────────────────────────────────────────
+API_KEYS = [
+    os.getenv("ODDS_API_KEY_1", "e4e30098807a9eece674d85e30471f03"),
+    os.getenv("ODDS_API_KEY_2", "673bf195062e60e666399be40f763545"),
+]
</file context>
Fix with Cubic

"command": "npx",
"args": ["-y", "@upstash/context7-mcp@latest"],
"env": {
"CONTEXT7_API_KEY": "ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P0: Remove the hardcoded API key from source and read it from environment variables.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/services/dfs_tracker.py, line 330:

<comment>Remove the hardcoded API key from source and read it from environment variables.</comment>

<file context>
@@ -0,0 +1,334 @@
+            "command": "npx",
+            "args": ["-y", "@upstash/context7-mcp@latest"],
+            "env": {
+                "CONTEXT7_API_KEY": "ctx7sk-8e246594-e35e-44f1-b8df-bd2416b8831e"
+            }
+        }
</file context>
Fix with Cubic

# ─────────────────────────────────────────────
class SimpleCache:
def __init__(self, ttl: int = CACHE_TTL_SECONDS):
self._store: Dict[str, Tuple[float, Any]] = {}

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P0: Missing Any import causes a runtime NameError. Any is used in the Tuple[float, Any] type annotation on this line but is not included in the typing import statement.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/services/odds_fetcher.py, line 46:

<comment>Missing `Any` import causes a runtime `NameError`. `Any` is used in the `Tuple[float, Any]` type annotation on this line but is not included in the `typing` import statement.</comment>

<file context>
@@ -0,0 +1,422 @@
+# ─────────────────────────────────────────────
+class SimpleCache:
+    def __init__(self, ttl: int = CACHE_TTL_SECONDS):
+        self._store: Dict[str, Tuple[float, Any]] = {}
+        self.ttl = ttl
+
</file context>
Fix with Cubic


# L1: Bayesian posterior mean blended with raw
beta_mean = a / (a + b)
p_l1 = (a * p + b * beta_mean) / (a + b)

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: The L1 Bayesian shrinkage formula has asymmetric weighting that doesn't scale with sample size. With balanced hit/miss rates, the shrinkage is identical whether you have 4 or 10,000 observations. A standard blend would weight by total evidence:

n = a + b - self.prior_alpha - self.prior_beta  # effective observations
w = n / (n + self.prior_alpha + self.prior_beta)
p_l1 = w * beta_mean + (1 - w) * p
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/services/prop_model.py, line 280:

<comment>The L1 Bayesian shrinkage formula has asymmetric weighting that doesn't scale with sample size. With balanced hit/miss rates, the shrinkage is identical whether you have 4 or 10,000 observations. A standard blend would weight by total evidence:
```python
n = a + b - self.prior_alpha - self.prior_beta  # effective observations
w = n / (n + self.prior_alpha + self.prior_beta)
p_l1 = w * beta_mean + (1 - w) * p
```</comment>

<file context>
@@ -0,0 +1,533 @@
+
+        # L1: Bayesian posterior mean blended with raw
+        beta_mean = a / (a + b)
+        p_l1 = (a * p + b * beta_mean) / (a + b)
+
+        # L2: shrink toward efficient market (book line)
</file context>
Fix with Cubic

Comment thread api/routes/predictions.py
player_features = mlb.build_player_features(req.player, req.game_date)
features.update(player_features)
except Exception as e:
pass # gracefully degrade

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Broad except Exception as e: pass silently swallows all errors from feature building, including unexpected bugs. At minimum, log the exception so failures are observable. The captured e is also unused.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/routes/predictions.py, line 104:

<comment>Broad `except Exception as e: pass` silently swallows all errors from feature building, including unexpected bugs. At minimum, log the exception so failures are observable. The captured `e` is also unused.</comment>

<file context>
@@ -0,0 +1,286 @@
+            player_features = mlb.build_player_features(req.player, req.game_date)
+            features.update(player_features)
+        except Exception as e:
+            pass  # gracefully degrade
+
+    # Apply request overrides
</file context>
Fix with Cubic

doubles = stats.get("doubles", 0)
triples = stats.get("triples", 0)
homers = stats.get("home_runs", 0)
singles = hits - doubles - triples - homers

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Guard against negative singles count. If input stats are inconsistent (e.g., hits < doubles + triples + homers due to data errors), singles becomes negative, corrupting the DFS score calculation.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/services/dfs_tracker.py, line 100:

<comment>Guard against negative `singles` count. If input `stats` are inconsistent (e.g., `hits < doubles + triples + homers` due to data errors), `singles` becomes negative, corrupting the DFS score calculation.</comment>

<file context>
@@ -0,0 +1,334 @@
+        doubles = stats.get("doubles", 0)
+        triples = stats.get("triples", 0)
+        homers = stats.get("home_runs", 0)
+        singles = hits - doubles - triples - homers
+
+        pts = (
</file context>
Suggested change
singles = hits - doubles - triples - homers
singles = max(0, hits - doubles - triples - homers)
Fix with Cubic

r = json.loads(line.strip())
if datetime.fromisoformat(r["ts"]) >= cutoff:
records.append(r)
except (json.JSONDecodeError, KeyError):

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Malformed timestamp values can crash error-log reads because ValueError is not caught.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/services/error_logger.py, line 134:

<comment>Malformed timestamp values can crash error-log reads because `ValueError` is not caught.</comment>

<file context>
@@ -0,0 +1,347 @@
+                    r = json.loads(line.strip())
+                    if datetime.fromisoformat(r["ts"]) >= cutoff:
+                        records.append(r)
+                except (json.JSONDecodeError, KeyError):
+                    continue
+        return records
</file context>
Fix with Cubic

"error_type": error_type,
"message": message,
"context": context or {},
"traceback": traceback.format_exc() if exc else None,

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Traceback capture uses traceback.format_exc() instead of the provided exception object, which can log empty/incorrect stack traces.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api/services/error_logger.py, line 84:

<comment>Traceback capture uses `traceback.format_exc()` instead of the provided exception object, which can log empty/incorrect stack traces.</comment>

<file context>
@@ -0,0 +1,347 @@
+            "error_type": error_type,
+            "message": message,
+            "context": context or {},
+            "traceback": traceback.format_exc() if exc else None,
+        }
+        self._write(ERROR_LOG_FILE, record)
</file context>
Suggested change
"traceback": traceback.format_exc() if exc else None,
"traceback": "".join(traceback.format_exception(type(exc), exc, exc.__traceback__)) if exc else None,
Fix with Cubic

Comment thread requirements.txt

# ── HTTP / Scraping ─────────────────────────
requests==2.31.0
httpx==0.27.0

@cubic-dev-ai cubic-dev-ai Bot Mar 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: httpx is declared twice in requirements; keep a single entry to avoid dependency drift and maintenance errors.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At requirements.txt, line 26:

<comment>`httpx` is declared twice in requirements; keep a single entry to avoid dependency drift and maintenance errors.</comment>

<file context>
@@ -0,0 +1,49 @@
+
+# ── HTTP / Scraping ─────────────────────────
+requests==2.31.0
+httpx==0.27.0
+aiohttp==3.9.3
+beautifulsoup4==4.12.3
</file context>
Fix with Cubic

@secure-code-warrior-for-github

Copy link
Copy Markdown

Micro-Learning Topic: Cross-site scripting (Detected by phrase)

Matched on "XSS"

Cross-site scripting vulnerabilities occur when unescaped input is rendered into a page displayed to the user. When HTML or script is included in the input, it will be processed by a user's browser as HTML or script and can alter the appearance of the page or execute malicious scripts in their user context.

Try a challenge in Secure Code Warrior

Helpful references

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.

1 participant