# How Bonus Points and Deductions Are Calculated in Hiring Agent: A Complete Guide

> Learn how bonus points and deductions are calculated in Hiring Agent. Understand the scoring system to optimize your hiring process.

- Repository: [HackerRank/hiring-agent](https://github.com/interviewstreet/hiring-agent)
- Tags: how-to-guide
- Published: 2026-07-21

---

**Bonus points and deductions in Hiring Agent are calculated by adding up to 20 bonus points to the sum of four category scores, then subtracting any deduction points, with the final result clamped to a maximum of the base max score plus 20.**

Hiring Agent is an open-source résumé evaluation tool that uses a nuanced scoring system to assess candidate profiles. Understanding how bonus points and deductions are calculated in Hiring Agent is essential for interpreting evaluation results and customizing the scoring pipeline. The system combines capped category scores with discretionary adjustments to produce the final composite score displayed in the CLI.

## Data Models for Bonus Points and Deductions

The scoring adjustments are defined as structured data classes in [`main/models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/main/models.py), ensuring type safety and validation constraints throughout the evaluation pipeline.

### BonusPoints Class (models.py)

The `BonusPoints` class represents additional points awarded for exceptional achievements beyond the standard category criteria.

- **`total`**: An integer constrained to **0 ≤ total ≤ 20**, representing the maximum 20-point bonus cap.
- **`breakdown`**: A free-form string field that explains the rationale behind the points awarded, providing transparency for hiring decisions.

According to the Hiring Agent source code, these points are added directly to the raw total of the four category scores (Open-Source, Self-Projects, Production, and Technical Skills).

### Deductions Class (models.py)

The `Deductions` class captures penalties applied for missing information or substandard portfolio elements.

- **`total`**: An integer **≥ 0** stored as a positive number but interpreted as a negative value during calculation.
- **`reasons`**: A descriptive string field documenting why specific points were removed from the candidate's evaluation.

As implemented in `interviewstreet/hiring-agent`, the deduction total is subtracted from the running sum after bonus points have been applied.

## Scoring Flow and Calculation Logic

The mathematical operations combining these components occur in [`main/score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/main/score.py) within the evaluation results formatting routine.

### The print_evaluation_results Function (score.py)

The `print_evaluation_results` function implements a four-step scoring algorithm:

1. Compute each category's **capped** score against its category-specific maximum.
2. Add `evaluation.bonus_points.total` to the running sum of category scores.
3. Subtract `evaluation.deductions.total` from the combined total.
4. Clamp the final value to the maximum possible overall score (`max_score + 20`).

This logic ensures that bonus points reward extra achievements while deductions penalize gaps, without allowing the final score to exceed the theoretical maximum.

### Final Score Clamping Logic

The maximum possible overall score is explicitly defined as **`max_score + 20`** because the bonus cap is 20 points. This clamping prevents calculation anomalies if an LLM evaluator returns inconsistent values.

The CLI output format displays these calculations transparently:

```

🎯 OVERALL SCORE: 87.5/100
⭐ BONUS POINTS: 12
⚠️  DEDUCTIONS: -3

```

## Working with EvaluationData Objects

Both bonus points and deductions populate the `EvaluationData` object returned by the LLM evaluator. You can construct these manually for testing or integration purposes:

```python
from models import (
    CategoryScore,
    Scores,
    BonusPoints,
    Deductions,
    EvaluationData,
)

# Example category scores (already capped to their max)

scores = Scores(
    open_source=CategoryScore(score=30, max=35, evidence="Contributed to 3 OSS projects"),
    self_projects=CategoryScore(score=25, max=30, evidence="Built 2 personal apps"),
    production=CategoryScore(score=20, max=25, evidence="2 years at Acme Corp"),
    technical_skills=CategoryScore(score=8, max=10, evidence="Proficient in Python, Go")
)

# Bonus points earned (max 20)

bonus = BonusPoints(total=12, breakdown="Extra points for open‑source leadership")

# Deductions applied (positive number, interpreted as negative)

deductions = Deductions(total=3, reasons="Missing portfolio link")

evaluation = EvaluationData(
    scores=scores,
    bonus_points=bonus,
    deductions=deductions,
    key_strengths=["Strong problem‑solving", "Team player"],
    areas_for_improvement=["Documentation", "Testing"]
)

# The `print_evaluation_results` function will display the final combined score.

```

To execute the full scoring routine from the command line:

```bash
python score.py path/to/candidate_resume.pdf

```

This script extracts the résumé content, invokes the LLM evaluator to generate the `EvaluationData` instance, and applies the bonus and deduction arithmetic before rendering the final report.

## Summary

- **Bonus points** are capped at 20 points and defined in [`main/models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/main/models.py) within the `BonusPoints` class, requiring a non-negative total and descriptive breakdown.
- **Deductions** are stored as positive integers in the `Deductions` class but applied as negative values during the final calculation.
- The scoring logic resides in [`main/score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/main/score.py), specifically in the `print_evaluation_results` function, which adds bonuses then subtracts deductions before clamping to `max_score + 20`.
- Both adjustments flow through the `EvaluationData` object, which serves as the contract between the LLM evaluator and the scoring display layer.

## Frequently Asked Questions

### What is the maximum number of bonus points in Hiring Agent?

The maximum bonus points is **20**. This limit is enforced in the `BonusPoints` class in [`main/models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/main/models.py), where the `total` field must satisfy `0 <= total <= 20`. The final score calculation in [`score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/score.py) accounts for this by setting the absolute maximum possible score to `max_score + 20`.

### How are deductions represented in the data model versus the final score?

In the `Deductions` class in [`main/models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/main/models.py), the `total` field is stored as a **positive integer** greater than or equal to zero. However, during the calculation phase in `print_evaluation_results`, this value is **subtracted** from the running total, effectively treating it as a negative adjustment in the final score display.

### Where is the final score calculation performed in the codebase?

The final score calculation occurs in [`main/score.py`](https://github.com/interviewstreet/hiring-agent/blob/main/main/score.py) within the `print_evaluation_results` function. This routine computes capped category scores, applies the bonus addition, performs the deduction subtraction, and clamps the result to the maximum allowable score before printing the formatted results to the CLI.

### Can bonus points and deductions be customized for specific evaluations?

Yes. Since the LLM evaluator generates the `EvaluationData` object—including the `bonus_points` and `deductions` fields—you can customize these values by modifying the evaluator prompts or manually constructing `EvaluationData` instances for testing. The `BonusPoints` and `Deductions` classes accept arbitrary string descriptions in their `breakdown` and `reasons` fields, allowing flexible justification for any point adjustments.