All work AI SYSTEMS / TRUST & SAFETY prototype

09  /  AI SYSTEMS / TRUST & SAFETY

WorkVisa Finder

One scam listing costs a migrant worker more than an empty page, so the board shows nothing instead.

June 2026Python 3.12FastAPIPydantic v2PostgreSQL + PostGISAnthropic SDKNext.js 14TypeScriptGitHub Actions

The challenge

A worker in Pakistan or Nepal looking for a job abroad has no safe place to look. The alternative is a grey market of unlicensed agents and WhatsApp forwards that charge illegal fees, route people out on tourist visas, and leave them stranded in debt. Scraping the job boards does not fix it. On my own working estimate, roughly 70% of the target South Asia volume, the Gulf and the UK, has no job board at all, because those corridors allocate work through licensed intermediaries by design. And the feature everyone asks me for first, an eligibility checker that tells you which visa you qualify for, is unlicensed immigration advice, which is a crime in the UK, Australia and Canada.

What I built

I built a Python ingestion pipeline and a Next.js PWA, contract-first, so the safety rules live in code rather than in a policy document. Nine connectors feed a normalise, trust, serve pipeline. A listing reaches a user only after provenance, recruiter verification against a national licence register, and a scam classifier have all cleared it. I model the two corridor shapes separately: countries with real public feeds are aggregated as vacancies, while the Gulf and the UK ship as verified directories checked against the sending country's own register. Nine stop-the-line gates run in CI as executable scripts and fail closed.

How it works

EVERY CHECK MUST CLEAR Provenancewhere the listing came from Licence registerof the sending country Hard rules firstfees, fast visas, passports The classifieradds doubt, never clears it HUMAN Amber, human reviewno green card anywhere FAIL-CLOSED Fail any of these three and the listing is never served if no register resolves, the job quarantines instead of appearing EMPTY, NEVER WRONG
The mechanism, drawn from the build.

What it looks like

WorkVisa Finder — screenshot
Running locallyAI SYSTEMS / TRUST & SAFETY

The detail

01

Gates, not guidelines

I wrote the safety rules as nine executable scripts in infra/gates/, wired into CI, each failing closed. G-FEE blocks any listing carrying a worker-paid fee three times over: a database CHECK constraint on jobs.worker_pays_flag, a Pydantic model validator that refuses to let a fee-bearing job hold verified status, and a trust resolver that quarantines it before it can be served. G-EGRESS flags httpx calls, raw sockets and source-domain URLs in any ingestion, alerts or llm module that does not go through the require_live() guard.

02

One switch

I gave it exactly one environment variable, BUILD_MODE, with two values, and safe is both the CI default and the fail-closed default. Under safe, connectors read recorded fixtures, no source domain is contacted, live secrets never load, and the notifier binds to a mock that records intent and sends nothing. Any real fetch or send has to route through config.require_live(), which raises; the CI workflow hard-codes safe and fails any job that tries to override it.

03

The origin register

Saudi Musaned, UAE MOHRE and the UK Seasonal Worker scheme have no public vacancy board to crawl, so I model those corridors as verified directories instead. trust/registers.py resolves each listing against the licence register of the sending country rather than the destination: a Musaned job routed via a Pakistani agent is checked against pk_beoe, a Nepali agent against np_dofe, across six register mirrors. If no register resolves, the job earns a hard unverified_recruiter flag and quarantines, so a missing register degrades a corridor to empty, never to wrong.

04

Suspicion is one-way

Deterministic regex rules run first and are authoritative: worker fees, fast-visa timeline language, tourist-visa substitution, off-platform payment, passport surrender. The Anthropic classifier only augments. It can contribute new flags or raise a soft score, but it can never unset a fired hard rule and can never promote a listing to green; if it errors or times out, classifier_available flips to False and the job routes to amber and human review. I made the demo show the rule biting rather than describe it: because the classifier is mocked under BUILD_MODE=safe, every served job renders the amber "Caution — we are checking this" badge and there is no green card anywhere.

05

Refusing to advise

Unlicensed immigration advice carries criminal liability in the UK, Australia and Canada, so my API refuses to give any. A request carrying advice-shaped parameters, passport and passport_number among them, receives a 451 unavailable_legal with an information-not-advice disclaimer instead of a verdict, and the G-ADVICE gate scans the codebase for personalised-advice strings. I deliberately never built the eligibility checker everyone asks for first. What ships is a generic informational filter that says a route is open to nationals of a given country, and nothing more.

The outcome

A prototype that runs on localhost and that I never deployed. I verified it by running it: 529 backend tests pass, all nine stop-the-line gates are green, and the demo sweep serves 51 jobs across seven destination countries into the PWA, entirely from recorded fixtures. A live path exists for the German and Canadian national employment APIs behind BUILD_MODE, but the demo default is fixtures, and every served job fail-closes to amber because the classifier is unavailable under safe mode. Nineteen commits over three days produced a 25-table schema, nine connectors and roughly 11k lines of backend Python against 7k lines of tests, built by a fleet of coding agents against a frozen contract spine: parallel fan-out across git worktrees under a file-ownership map, adversarial verification by a different agent than the author, merge only when green.