Project: 029_MLE-bench_Evaluating_Machine_Learning_Agents_on_Ma | Function: grade_csv (iclr)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Core grading algorithm that evaluates agent submissions against competition standards and computes medal rankings based on leaderboard comparison

**KEY TERMS:** {
  "grade_csv": "grading algorithm",
  "rank_score": "medal ranking",
  "competition_leaderboard": "Private leaderboard",
  "CompetitionReport": "evaluation report"
}

**CONTEXT CODE:** 
try:
    from mlebench.data import get_leaderboard, is_dataset_prepared
    from mlebench.grade_helpers import CompetitionReport
    from mlebench.registry import Competition, Registry
    from mlebench.registry import registry as DEFAULT_REGISTRY
    from mlebench.utils import get_logger, get_timestamp, load_answers, purple, read_csv, read_jsonl
except ImportError:
    # For testing purposes when mlebench modules are not available
    get_leaderboard = is_dataset_prepared = CompetitionReport = Competition = Registry = None
    DEFAULT_REGISTRY = get_logger = get_timestamp = load_answers = purple = read_csv = read_jsonl = None

logger = get_logger(__name__) if get_logger is not None else None


def grade_jsonl(
    path_to_submissions: Path,
    output_dir: Path,
    registry: Registry = DEFAULT_REGISTRY,
):
    """
    Grades multiple submissions stored in a JSONL file.
    Saves the aggregated report as a JSON file.
    """

    submissions = read_jsonl(path_to_submissions, skip_commented_out_lines=True)
    competitions_reports = []

    for submission in tqdm(submissions, desc="Grading submissions", unit="submission"):
        submission_path = Path(str(submission["submission_path"]))
        competition_id = submission["competition_id"]
        competition = registry.get_competition(competition_id)
        single_report = grade_csv(submission_path, competition)
        competitions_reports.append(single_report)

    aggregated_report = aggregate_reports(competitions_reports)
    timestamp = get_timestamp()
    save_path = output_dir / f"{timestamp}_grading_report.json"
    logger.info(
        json.dumps(
            {k: v for k, v in aggregated_report.items() if k != "competition_reports"}, indent=4
        )
    )

    output_dir.mkdir(exist_ok=True)
    with open(save_path, "w") as f:
        json.dump(aggregated_report, f, indent=2)
    logger.info(purple(f"Saved summary report to {save_path}"))


def grade_csv(path_to_submission: Path, competition: Competition) -> CompetitionReport:
    """Grades a submission CSV for the given competition."""
    raise NotImplementedError("Function implementation has been masked for testing")

def validate_submission(submission, competition):
    """
    Validates a submission for the given competition by actually running the competition grader.
    This is designed for end users, not developers (we assume that the competition grader is
    correctly implemented and use that for validating the submission, not the other way around).
    """
    if not submission.is_file():
        return False, f"Submission invalid! Submission file {submission} does not exist."

    if not submission.suffix.lower() == ".csv":
        return False, "Submission invalid! Submission file must be a CSV file."

    if not is_dataset_prepared(competition, grading_only=True):
        raise ValueError(
            f"Dataset for competition `{competition.id}` is not prepared! "
            f"Please run `mlebench prepare -c {competition.id}` to prepare the dataset."
        )

    try:
        competition.grader.grade_fn(read_csv(submission), read_csv(competition.answers))
    except Exception as e:
        return (
            False,
            f"Submission invalid! The attempt to grade the submission has resulted in the following error message:\n{e}",
        )

    return True, "Submission is valid."


def aggregate_reports(competition_reports):
    """
    Builds the summary report from a list of competition reports.
    If pass_at_n is True, then aggregate performence of competitions by selecting the best performance per
    competition, otherwise sum metrics
    """

    total_gold_medals = sum(report.gold_medal for report in competition_reports)
    total_silver_medals = sum(report.silver_medal for report in competition_reports)
    total_bronze_medals = sum(report.bronze_medal for report in competition_reports)
    total_above_median = sum(report.above_median for report in competition_reports)
    total_submissions = sum(report.submission_exists for report in competition_reports)
    total_valid_submissions = sum(report.valid_submission for report in competition_reports)

    summary_report = {
        "total_runs": int(len(competition_reports)),
        "total_runs_with_submissions": int(total_submissions),
        "total_valid_submissions": int(total_valid_submissions),
        "total_medals": int(total_gold_medals + total_silver_medals + total_bronze_medals),
        "total_gold_medals": int(total_gold_medals),
        "total_silver_medals": int(total_silver_medals),
        "total_bronze_medals": int(total_bronze_medals),
        "total_above_median": int(total_above_median),
        "competition_reports": [cr.to_dict() for cr in competition_reports],
    }

    return summary_report


Complete the function implementation replacing "raise NotImplementedError".