> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heymilo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Interpreting Cheat Detection Results

> How to read HeyMilo's cheat detection output — what each finding means, how confident the system is, what action it suggests, and how to tune sensitivity to your role.

> **Who this is for:** recruiters, hiring managers, and integrity teams reading the output of HeyMilo's interview cheat detection (V2).

***

## Read a result in 30 seconds

Every analysis returns one **overall verdict** plus a list of individual **findings** (called *breaches*). Start at the top:

| Look at                               | It tells you                                                                    |
| ------------------------------------- | ------------------------------------------------------------------------------- |
| `risk_summary.recommended_action`     | The one-word call: **Proceed**, **Review**, or **Reject**                       |
| `risk_summary.headline`               | A plain-English one-liner you can paste into notes                              |
| `risk_summary.compromised_percentage` | How much of the interview showed serious (high-severity) problems               |
| `breaches[]`                          | The individual findings, each with its own severity, timestamp, and explanation |

<Note>
  **Golden rule:** the system assists a human decision — it does not auto-fail candidates. Treat **Review** and any single finding as "a human should look at this clip," not "this candidate cheated."
</Note>

***

## Reading the `risk_summary`

This is the top-of-report banner — the verdict and its calibration.

### `recommended_action` — the overall call

| Value            | Meaning                                  | What to do                                      |
| ---------------- | ---------------------------------------- | ----------------------------------------------- |
| `proceed`        | No meaningful integrity concern found    | Continue as normal                              |
| `further_review` | Findings exist and warrant a human look  | Watch the flagged clips before deciding         |
| `reject`         | Strong, sustained high-severity evidence | Likely disqualify — but confirm the clips first |

<Note>
  This is a **recommendation**, not an automatic decision. The final call is always yours.
</Note>

### How the overall call is computed

The verdict is based on **how much of the interview** was compromised, not just the count of findings:

| Condition                                                                                  | Overall verdict  |
| ------------------------------------------------------------------------------------------ | ---------------- |
| High-severity findings cover **≥ `rejection_threshold`%** of the session (default **10%**) | `reject`         |
| High + medium findings cover **≥ 20%** of the session                                      | `further_review` |
| Otherwise                                                                                  | `proceed`        |

<Info>
  **Why duration, not count?** A single 2-second false blip shouldn't fail a candidate, and ten tiny flags shouldn't outweigh one sustained, serious breach. Measuring the share of the session keeps the verdict proportional. You control the reject cutoff via `rejection_threshold`.
</Info>

### Calibration fields

| Field                      | Meaning                                                           |
| -------------------------- | ----------------------------------------------------------------- |
| `session_duration_sec`     | Total interview length analysed                                   |
| `compromised_duration_sec` | Seconds covered by high-severity findings (overlaps counted once) |
| `compromised_percentage`   | `compromised_duration_sec` divided by session length, as a 0–100% |
| `total_breach_events`      | How many findings were confirmed                                  |

<Info>
  **Important:** `compromised_percentage` counts **only high-severity** findings. Medium and low findings are real but advisory — they appear in the breakdowns and `breaches[]`, but don't inflate this headline number. So "0% compromised" can still come with medium/low findings worth a glance.
</Info>

### Composition fields

* **`severity_breakdown`** — how much time fell into high/medium/low buckets (count + duration + % each). Always shows all three buckets, even at zero.
* **`category_breakdown`** — which kinds of issues appeared (identity, external assistance, etc.), biggest offender first.

***

## Reading an individual `breach`

Each finding looks like this:

```json theme={null}
{
  "category": "external_assistance_integrity",
  "breach_type": "unauthorized_aid_object_present",
  "severity": "medium",
  "confidence": 0.6,
  "time_range_sec": { "start": 122.0, "end": 130.0 },
  "comments": "A phone is visible in the candidate's hand during this answer; active reading can't be fully confirmed from the frames.",
  "recommended_action": "further_review",
  "evidence": { "metadata": { "...": "field varies by breach" } }
}
```

| Field                | How to read it                                                                  |
| -------------------- | ------------------------------------------------------------------------------- |
| `breach_type`        | What was detected (see the catalog below)                                       |
| `category`           | The integrity dimension it belongs to                                           |
| `severity`           | How serious — see the ladder below                                              |
| `confidence`         | How sure the system is (0–1). See note below                                    |
| `time_range_sec`     | When in the interview — scrub here to watch it                                  |
| `comments`           | A plain-English explanation of what's happening and why it was flagged          |
| `recommended_action` | The suggested action for this specific finding                                  |
| `evidence.metadata`  | Supporting detail (e.g. the answer text, the object class, a cited observation) |

### The severity ladder

| Severity   | What it means                                                                                                                            | Typical reading                                |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| **High**   | Evidence clearly shows an unfair advantage (visibly reading from a phone, a second person answering)                                     | Strong concern — review promptly               |
| **Medium** | A behavior that could help cheating but can't be fully confirmed from the evidence. **This is the default when the reviewer is unsure.** | Worth a human look; don't over-read it         |
| **Low**    | A confirmed but weak or borderline signal                                                                                                | Usually benign; note it, don't act on it alone |

<Info>
  **Most "uncertain" findings land at medium on purpose.** The system surfaces plausible signals at medium so a human can decide, rather than hiding them or over-calling them high.
</Info>

### About `confidence`

`confidence` (0–1) is a display signal of how strong the underlying detection was — it does **not** drive the verdict (severity and duration do). Read it as a rough "how strong is the signal," not a probability of cheating.

***

## Breach catalog — what each finding means

Findings are grouped into five **integrity dimensions** (categories). Below is what each finding means, what triggers it, and how to interpret it.

### 1. Identity Authenticity Integrity

*Is the person on camera really the enrolled candidate?*

**`identity_authenticity_risk`** — the face on camera doesn't match the enrolled candidate, or the identity changes mid-interview.

* **Triggers on:** a face that clusters differently from the enrollment photo, or an abrupt person-switch.
* **Interpret:** high = a clear mismatch or swap; medium = ambiguous (pose, lighting, low video quality). Genuine network/camera-quality artifacts are meant to be discarded — if you see this at medium, check whether it's just a bad frame.

### 2. Presence and Participation Integrity

*Is the candidate continuously present and observable?*

**`candidate_absence_or_unverifiable_presence`** — the candidate leaves frame or becomes unidentifiable for a sustained stretch.

* **Triggers on:** the face being missing/untrackable for longer than the configured floor.
* **Interpret:** high = prolonged total absence; medium = partial or hard-to-verify presence. A brief look-away is meant to be ignored.

### 3. External Assistance Integrity

*Is the candidate getting outside help?*

**`unauthorized_aid_object_present`** — a phone, tablet, second screen, book, or notes is visible/usable.

* **Triggers on:** detection of a monitored object class (configurable).
* **Interpret:** presence alone is medium at most; high requires visible use (reading from, typing on, or repeatedly glancing at it).

**`external_voice_assistance_detected`** — a non-candidate voice is coaching or supplying answers.

* **Triggers on:** a second speaker overlapping the candidate's answer windows.
* **Interpret:** high = the voice clearly shapes the answer; medium = another voice is present but its role is unclear (could be background noise).

**`offscreen_reference_pattern`** — sustained gaze off-camera while answering (a second monitor, side notes, prompts).

* **Triggers on:** gaze held beyond an angle/duration threshold — distinct from natural thinking glances.
* **Interpret:** high = appears to be reading from an off-camera source (often corroborated by other findings); low/medium = sustained but ambiguous. Brief or natural glances are discarded.

**`multiple_people_presence`** — more than one person in frame.

* **Triggers on:** a second person detected with persistence.
* **Interpret:** high = a second person appears to assist; medium = present but role unclear. Reflections, posters, and people passing by are meant to be discarded.

**`covert_response_sync_pattern`** — a repeated long-pause-then-immediate-answer rhythm suggesting an external prompt loop.

* **Triggers on:** the delay between the question ending and the answer starting exceeding the configured limit.
* **Interpret:** high = timing clearly synced to an external cue; medium/low = suspicious but explainable by normal thinking time. Slow-but-genuine thinkers can trip this — tune the delay for your role.

### 4. Session Trust Integrity

*Is the session itself trustworthy (not spoofed or looped)?*

**`session_tampering_suspected`** — video feed spoofing, looping, or audio/video desync.

* **Status:** On the roadmap — not yet active in detection. The category exists for forward-compatibility; you won't see findings for it today.

### 5. Response Authenticity Integrity

*Are the answers the candidate's own, in real time?*

**`synthetic_response_generation_suspected`** — an answer reads as AI-generated.

* **Triggers on:** the AI-text probability of a qualifying answer crossing the threshold.
* **Interpret:** high = strongly AI-like; medium = polished but could be genuine. The finding cites the answer in `evidence.metadata`.

**`paraphrased_response_suspected`** — an answer reads as AI-reworded (the candidate's draft polished by an AI assistant).

* **Triggers on:** the paraphrase probability crossing its (separate) threshold.
* **Interpret:** distinct from synthetic — "AI helped rewrite" vs "AI wrote it." Tune the two thresholds independently.

***

## Policy parameters — tuning sensitivity

These knobs let you tune the system to your role and risk tolerance. They live in your **policy** (set per role/job). Anything you don't set uses the default below.

### Global knobs (apply everywhere)

| Parameter                        | Default | Range | What it does                                                                               | Tune it when...                                                             |
| -------------------------------- | ------- | ----- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
| `rejection_threshold`            | 10%     | 0–50  | Share of the session (high-severity) above which the overall verdict becomes **Reject**    | Lower for a stricter posture; raise to tolerate brief high-severity moments |
| `min_continuous_breach_time_sec` | 5s      | 0–60  | How long a problem must hold continuously before it counts (suppresses split-second blips) | Raise to cut jitter/noise; lower for stricter monitoring                    |
| `max_alerts_per_breach`          | 10      | 1–20  | Max findings kept per breach type per session (keeps reports readable)                     | Lower to declutter; raise if you want every instance                        |

<Info>
  These can also be set per **category** or per **breach type** — a more specific setting overrides a broader one.
</Info>

### Per-breach knobs

| Breach                                    | Parameter                                        | Default                            | What it does                                                        | Tuning                                                          |
| ----------------------------------------- | ------------------------------------------------ | ---------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------- |
| `identity_authenticity_risk`              | `cluster_threshold`                              | 0.7                                | How different two faces must look to be treated as different people | Lower = stricter; raise = more lenient                          |
| `unauthorized_aid_object_present`         | `aid_object_detection_confidence_threshold`      | 0.5                                | Detector confidence needed to consider an object                    | Raise to cut false objects; lower to catch faint ones           |
| `unauthorized_aid_object_present`         | `aid_object_types`                               | `cell_phone, tablet, laptop, book` | Which object types count as aids                                    | Add/remove per what's disallowed for the role                   |
| `offscreen_reference_pattern`             | `offscreen_angle_deg`                            | 30°                                | How far off-center a held gaze must be to count as off-camera       | Lower = catches subtle glances; raise = only obvious head-turns |
| `multiple_people_presence`                | `secondary_person_presence_confidence_threshold` | 0.5                                | Detector confidence needed to count a second person                 | Raise to ignore reflections/posters                             |
| `covert_response_sync_pattern`            | `max_acceptable_delay`                           | 5s                                 | Longest answer-start delay considered normal                        | Raise for technical roles; lower for fast-paced roles           |
| `synthetic_response_generation_suspected` | `ai_text_probability_threshold`                  | 0.7                                | AI-text probability needed to flag an answer                        | Raise (\~0.8) for precision; lower (\~0.4) for recall           |
| `paraphrased_response_suspected`          | `paraphrased_text_probability_threshold`         | 0.7                                | AI-paraphrase probability needed to flag an answer                  | Tune separately from the synthetic threshold                    |

<Info>
  You can also turn whole **categories** or individual **breach types** on or off via their `enabled` flag — e.g. a voice-only screening can disable all video breaches.
</Info>

***

## Worked examples

### Example A — "Proceed with a note"

```json theme={null}
{
  "recommended_action": "proceed",
  "compromised_percentage": 0,
  "breaches": [
    { "breach_type": "offscreen_reference_pattern", "severity": "low", "confidence": 0.4 }
  ]
}
```

**Read it as:** No high-severity time, so the overall call is Proceed. There's one low-severity gaze finding — the candidate glanced away, but it's weak and unconfirmed. Glance at the clip if you like; not a basis to act.

### Example B — "Review"

```json theme={null}
{
  "recommended_action": "further_review",
  "compromised_percentage": 0,
  "severity_breakdown": { "high": 0, "medium": 2, "low": 1 },
  "breaches": [
    { "breach_type": "unauthorized_aid_object_present", "severity": "medium" },
    { "breach_type": "covert_response_sync_pattern", "severity": "medium" }
  ]
}
```

**Read it as:** No high-severity time (so 0% compromised), but two medium findings pushed the combined share past the review line. A phone was visible (use unconfirmed) and answers came after long pauses. Watch both clips — together they may tell a story, or both may be innocent.

### Example C — "Reject"

```json theme={null}
{
  "recommended_action": "reject",
  "compromised_percentage": 18,
  "breaches": [
    { "breach_type": "external_voice_assistance_detected", "severity": "high" },
    { "breach_type": "identity_authenticity_risk", "severity": "high" }
  ]
}
```

**Read it as:** High-severity findings cover 18% of the session — over the reject threshold. A second voice was supplying answers and the face didn't match enrollment. Confirm the clips, then disqualify if they hold up.

***

## FAQ

**Q: Why was something flagged but the verdict is still "Proceed"?**
Because the verdict measures the share of the session covered by high-severity findings against your `rejection_threshold`. A short or medium/low finding won't move the overall call — but it's still listed in `breaches[]` for your awareness.

**Q: Why is `compromised_percentage` 0% when there are findings?**
That number counts **high-severity only**. Medium/low findings are intentionally excluded so the headline reflects confirmed serious compromise. Check `severity_breakdown` and `breaches[]` for the rest.

**Q: What does "medium" really mean — did they cheat?**
Medium means plausible but unconfirmed. The reviewer saw something that could enable cheating but couldn't be sure from the evidence. It's an invitation to look, not a conclusion.

**Q: Can the system reject a candidate on its own?**
No. It produces a recommendation. A human always makes the final call.

***

## What this system does not do

* Does **not** make hiring decisions — it surfaces evidence for a human
* Does **not** prove intent — a flag is "worth reviewing," not "guilty"
* Does **not** catch everything — coverage is bounded by what's visible in sampled evidence
* Is **not** a biometric identity service — identity findings compare against the enrollment you provided, for integrity purposes only

<Note>
  **Use it as a force-multiplier for reviewers:** it points you to the 30 seconds worth watching in a 45-minute interview, explains why, and tells you how confident it is — so your time goes to judgement, not scrubbing.
</Note>

***

## Back to setup

* [Interview Integrity (Cheat Detection)](interview-integrity) — Configure detection settings
* [Reviewing Candidates](../../getting-started/log-in/reviewing-candidates) — Score reports and candidate profiles
