JSJorge Sebastián Soriano ES

Case study · Rules engine

Explainable job offer triage

A personal system that gathers job offers from public sources, standardises them and assesses them with rules that can be read and discussed. It does not send applications: it prepares a prioritised report and leaves every decision to a person.

Where it's used
Personal use
Status
In use · runs every two days
My role
Criteria, integration, validation with real cases and maintenance. Code with AI
Technologies
Python (standard library), SQLite, IMAP, RSS, Windows scheduled tasks
Dashboard of assessed offers with score and status
Demo: 52 made-up offers, each with its decision and reason. Fictitious profile.

The problem

Reviewing offers by hand always runs into the same problems:

  • The decisive detail is not in the ad's fields: the salary appears in the text, mixed with the variable part, or not at all.
  • The ad contradicts itself: “permanent” in the contract field and “six months” in the description.
  • A “remote” ad only accepts residents of another country.
  • The same offer arrives by several routes and shows up again after being rejected.

What it does

Public sourcesAPIs, RSS, alertsNormaliseand deduplicateRules engine6 factors + 5 checksReportprioritised by statusTracking14 statuses, undo

Each offer gets a score from 0 to 100 with its reasons, five independent checks (salary, location, contract, English and travel) and a status. The report sorts first by status and then by score.

Why an offer ends up conditional

Data honesty

If an ad does not state a requirement, that does not mean it is met: it is marked “to be confirmed”. And when there is a contradiction, the engine does not keep the most favourable value.

  • Six weighted factors: role (25), skills (30), experience (20), sector (10), growth (10) and language (5).
  • Statuses separate from the score. An offer with 83 points can end up conditional if a decisive detail is missing.
  • Salary read with care. A figure in the text only counts if it sits next to salary vocabulary and falls within a plausible annual range. Variable pay does not count as fixed.
  • Rules instead of a model. There are few cases and every decision has consequences. I prefer rules that can be read, tested and discussed.

What it does not do

  • It does not send applications or write to the mailbox: email is read in read-only mode.
  • It only uses public job board APIs, RSS and email alerts. It does not access pages that require a login.
  • The dashboard is only accessible from the machine itself, with a backup before every cycle.

What is real and what is demo

PartIn the demoDetail
Offers, companies and salariesSynthetic52 made-up ads; 22 are deliberate test cases.
Candidate profile and applicationsSyntheticFictitious: they are not the author's criteria.
Assessment engineRealA JavaScript recreation of the original logic.
Original code, database and emailsNot includedNot published.

Results

157tests in the original systemunittest with mocked transports
12public sources38 queries per cycle
349demo checksdata and planted cases

Limitations and next steps

  • Skill detection is vocabulary-based: it recognises mentions, not the level required.
  • Next step: measure which recommended offers turn out to be interesting and adjust the weights with that data.

Demo screenshots

All with synthetic data. The demo interface is in Spanish.

Assessed offers with an editable profile
Assessed offers with an editable profile
Contract contradiction detected
Contract contradiction detected
Changing the profile changes the decisions
Changing the profile changes the decisions
Cycle report
Cycle report
Tracking with statistics from the history
Tracking with statistics from the history
Mobile view
Mobile view