# Understanding the Fit Evaluation Process: Structural Gates in AI Job Search

> Discover the fit evaluation process in AI job search, featuring Eligibility and Language structural gates. Filter job postings effectively and advance viable candidates.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: deep-dive
- Published: 2026-08-26

---

**The fit evaluation process uses two mandatory structural gates—Eligibility and Language—to filter job postings before quantitative scoring, ensuring only viable candidates proceed to the ranking stage.**

The fit evaluation process in the `MadsLorentzen/ai-job-search` repository implements a rigid pipeline that screens every scraped posting before any application material is generated. Defined in [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md), this framework enforces hard constraints through sequential gates that veto mismatches before numeric fit ratings are calculated.

## How the Fit Evaluation Pipeline Works

The pipeline processes postings through a strict chronological sequence. First, the **`/scrape`** command gathers raw job data from portal skills. Each posting then enters the fit-evaluation skill where two structural gates execute in series. Only after both gates return acceptable statuses does the system compute five quantitative dimensions—skills, experience, behavioral fit, salary, and others—to produce a final **fit rating** between 0 and 100.

This architecture ensures that "un-fit" postings are eliminated early, preventing wasted compute cycles and user attention on irrelevant positions.

## The Two Structural Gates

The structural gates act as binary or ternary filters that compare job requirements against the candidate profile defined in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md).

### Eligibility Gate: The First Filter

The **Eligibility Gate** runs immediately upon entry into the fit evaluation, before any scoring occurs (see line 9 of [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md)). This gate reads the posting content and classifies it against the candidate profile, specifically checking for experience levels, required skills, and declared deal-breakers.

If the gate detects a **hard mismatch**—such as a required certification the candidate lacks or a location constraint that violates the profile—it returns **FAIL**. This outcome triggers immediate exclusion from further ranking; the posting never reaches the quantitative scoring phase. Any result other than FAIL allows the posting to proceed to the Language Gate.

### Language Gate: The Second Filter

The **Language Gate** executes only after the Eligibility Gate passes. This comparator analyzes the posting’s required languages against the **Languages** table defined in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) (lines 33-35 of the evaluation file). Unlike the binary Eligibility Gate, this filter supports three distinct outcomes:

- **FAIL** — The posting is vetoed from the shortlist entirely due to unmet language requirements.
- **FLAG** — The posting is retained but highlighted with a warning (for example, "requires fluent English" when the candidate declared B1 proficiency).
- **PASS** — The posting proceeds to normal fit scoring without annotation.

The specific verdict (`language_gate`) and any explanatory notes (`language_note`) are persisted to [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json) for downstream consumption.

## Gate Integration and Workflow

The structural gates integrate into the broader automation workflow through specific command handoffs:

1. **`/scrape`** collects raw postings from job portals.
2. Each posting feeds into the **fit-evaluation skill** ([`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md)).
3. The **Eligibility Gate** executes; a FAIL drops the posting outright.
4. Upon passing, the **Language Gate** runs and stores its verdict in [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json).
5. Successful postings continue to the five quantitative dimensions and receive a numeric fit rating.

According to the repository's workflow diagram in [`README.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/README.md) (lines 44-58), this evaluation step sits precisely between data collection and application generation, acting as the critical filtering layer.

## Downstream Commands and Gate Usage

Subsequent commands in the pipeline reference the gate results stored in [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json) to modify their behavior:

- **`/rank`** — Records the `language_gate` status and `language_note` in its output matrix. A FAIL status acts as a shortlist veto, preventing the posting from appearing in candidate rankings (validated in [`tests/test_rank_command.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/tests/test_rank_command.py)).
- **`/apply`** — Consults the language gate when drafting cover letters, allowing the system to proactively address language requirements or deficiencies.
- **`/outcome`** — Uses the gate verdict to generate explanations for why specific postings were never pursued, providing auditability to the filtering decisions.

## Practical Code Examples

Run the complete fit-evaluation pipeline on a specific posting using the apply command:

```bash

# Automatically triggers both gates before generating application materials

/apply https://jobindex.dk/job/1234567

```

Inspect a ranked entry after gate execution completes:

```json
{
  "url": "https://jobindex.dk/job/1234567",
  "fit_rating": 78,
  "language_gate": "FLAG",
  "language_note": "Fluent English required (you declared B1)",
  "strengths": ["Python, data pipelines", "Remote-first culture"],
  "gaps": ["5-year experience with Azure"]
}

```

For debugging or manual verification, invoke the gate checks directly:

```bash

# Run gate evaluation against a specific posting and profile

python -m job_application_assistant.evaluate_gate \
    --posting path/to/posting.html \
    --profile CLAUDE.md

```

## Summary

- The fit evaluation process relies on two sequential **structural gates** defined in [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md) to enforce hard constraints before numeric scoring.
- The **Eligibility Gate** (line 9) performs binary filtering against candidate profiles, excluding hard mismatches immediately.
- The **Language Gate** (lines 33-35) performs ternary evaluation (FAIL/FLAG/PASS) against language requirements stored in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md).
- Gate results persist in [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json) and influence downstream commands including **`/rank`**, **`/apply`**, and **`/outcome`**.
- Only postings passing both gates receive the five-dimensional quantitative scoring that produces the final 0-100 fit rating.

## Frequently Asked Questions

### What happens if a job posting fails the Eligibility Gate?

If the Eligibility Gate returns **FAIL**, the posting is excluded from further ranking immediately. According to the logic in [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md) at line 9, this hard mismatch prevents the posting from ever reaching the quantitative scoring dimensions or appearing in application shortlists.

### How does the Language Gate determine if a posting is a match?

The Language Gate compares the posting's required languages against the **Languages** table in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md). It returns **PASS** if requirements are met, **FLAG** if there is a minor mismatch that should be noted, or **FAIL** if there is a hard mismatch that vetoes the posting from the shortlist (as documented in lines 33-35 of the evaluation file).

### Where are the gate results stored for later use?

Both gates write their verdicts to [`seen_jobs.json`](https://github.com/MadsLorentzen/ai-job-search/blob/main/seen_jobs.json). Specifically, the Language Gate stores `language_gate` (PASS/FAIL/FLAG) and `language_note` fields, which downstream commands like `/rank` and `/apply` read to modify their behavior and cover letter generation.

### Can I run the fit evaluation without triggering the full application process?

Yes. You can execute the gate checks independently using the `evaluate_gate` module. The command `python -m job_application_assistant.evaluate_gate --posting path/to/posting.html --profile CLAUDE.md` runs both structural gates against a specific posting without generating application materials.