Evaluation engineer · RL environments · verifiers

I build the tasks that tell you whether a model actually got better.

Reinforcement-learning environments and coding evaluations for frontier labs, with deterministic graders, calibrated difficulty, and a written record of every task a stronger agent broke and why.

Johannesburg · UTC+2Overlaps US East and EU hoursContractor since 2019

How a task is calibrated

oracle
1.000
reference
0.500
frontier agent
0.265
naive policies
0.000
The oracle must score exactly 1.0 under the grader the agents face. A fair same-information reference sits at 0.5. The task ships only if the strongest available agent stays under the ceiling. Numbers shown are from a task that held.

What I build

RL environments with deterministic graders, multi-turn coding evaluations, and verification tasks over synthetic data. MuJoCo, Python, rubric design.

How I measure

Oracle at exactly 1.0, a fair reference at 0.5, naive policies at 0, then an attack by the strongest available agent before any review. Difficulty is a number, not an opinion.

Where it has been used

Frontier-model training data via Alignerr (2026), a frontier model's evaluation at Turing (2025), and a production operations platform run by a non-technical client, and my own startup, AI Securewatch. Remote, UTC+2.

8
case studies below, each with its measured numbers
0.265
frontier-agent score on the one task structure that held
1.000
required oracle score, verified by harness, on every RL task
20–50%
target model pass band on the Gemini evaluation tasks

Work

Case studies

Each entry opens into the full account: what the task asked, how the oracle and reference were anchored, how it was attacked, what the numbers were, and what changed as a result. Tasks for lab clients are described at the level of mechanism and measurement; internals stay with the client.

Wall-bracing chimney climber

A planar robot that climbs a chimney by pressing two pads against opposite walls and inch-worming upward. Friction is the only support; release both pads and it falls.

shippedMuJoCocontact · frictionhidden parameters
Open case ↓Close ↑

The task

Four continuous actions: press force and lift for each pad. Physics at 2 kHz, control at 50 Hz, 22 seconds per episode. The difficulty axis is climb completeness: execute a coordinated multi-phase gait to a tall target without ever letting both pads slip at once.

Anchoring

The oracle is a hand-written inchworm gait that reaches the target and scores 1.0 after calibration. The reference is the same gait told to secure only the lower half, then hold; it lands at 0.500 and is rock-stable across seeds. Naive policies (push everything, greedy timer, random, lift-only) all land at 0.000, which is the honesty gate: a task where a trivial policy scores anything is mis-anchored.

What makes it hold

Friction coefficient, body mass and gravity are drawn from hidden ranges per episode. A policy cannot pre-compute a press schedule; it has to sense slip and respond. Twelve hidden grading scenarios, bit-identical determinism, about fourteen seconds per full battery.

What I took from it

Calibration is piecewise-linear from measured raw scores (floor, reference, oracle), never from a guess. Build the reference from the oracle's own code with one knob turned down, so the 0.5 anchor is a legal policy under the same information, not a hand-tuned number.

Quadrotor with a slung load through a ring gauntlet

A 3-D quadrotor carries a payload on a flexible multi-link cable and must thread it through narrow rings while keeping the swing quiet. Everything cleared until the strongest agent solved it outright.

cracked · retiredMuJoCoflexible cablepost-mortem
Open case ↓Close ↑

What happened

Design review, adversarial review, runtime scorer and ground truth all passed. At the agent-attack stage a frontier coding agent scored 0.917 against a 0.5 ceiling. Not an exploit: it threaded 91% of rings with a mean miss of 2.5 cm.

What the agent wrote, unprompted

A 313-line differential-flatness cascade: a quintic payload trajectory in the flat output, zero-vibration input shaping tuned to one compromise frequency, a geometric attitude loop, a payload-plus-drone cascaded PD, and a per-segment linear regression that learned the systematic crossing bias and pre-compensated it. It tuned its own parameters with an offline coordinate search. It even set the cable length wrong and still scored 0.917.

Why it died

  • Nothing hidden was load-bearing. The plant file was public and the swing fully observable, so the agent could replicate the oracle's own workflow.
  • The anisotropic cable stiffness did not force a multi-mode controller; a single shaper spanned both regimes. The oracle itself proved that by scoring 1.0 with a scalar shaper.
  • I had dropped the hidden-time gusts because they broke the 0.5 reference. That removed the one layer that punishes a clean pre-planned trajectory.

The salvage, measured and declined

I re-used the agent's own captured policy as the attacker and escalated gusts. At every level that pushed the agent under 0.4, the blind reference was already near 0.18. Reference and agent share information, so the disturbance hurts the weaker controller more. No level existed where oracle 1.0, reference 0.5 and agent under 0.4 coexist. The family was closed rather than patched.

Quadrotor balancing a free stick through hoops

An underactuated quadrotor keeps a 0.9 m stick upright on a two-axis hinge while threading the stick's tip through nine hoops under hidden gusts. The agent's controller was better than mine.

beaten by the agentMuJoCounderactuatedceiling arithmetic
Open case ↓Close ↑

What happened

All nine quality stages passed. The agent then scored 1.000. Running its policy through my own scorer on the 40 grading episodes: raw 0.769 against my oracle's 0.615. It threaded 7.97 hoops of 9 to my 7.22, with a worst-case miss of 9.6 cm to my 24 cm. It also arrived at the lean-reconstruction insight the task was built around without being told.

The arithmetic this exposed

With a linear calibration from reference to oracle, an agent clears the ceiling unless the reference is at least 1.25 times weaker than the agent in raw score. If your oracle is only 4% better than what a strong agent writes in an afternoon, no scorer geometry can save the task. On an actively balanced inverted system, feedback erases trajectory history, so planning was worth nothing and the whole difficulty rested on controller quality.

What changed in how I work

  • Attack the task with the strongest agent available before any other review, and keep the agent's policy as a permanent regression test.
  • Measure the raw gap between oracle and best-known attack, and treat anything under about 1.5 times as not a task yet.
  • Seven follow-up levers were tested on this plant; all negative, each recorded with numbers so nobody rebuilds it.

What actually holds: a contact-coupled balance task under delay

To find out what survives a frontier agent, I probed a known-passing task with a real agent run and then built three look-alikes to isolate the mechanism. The original held at 0.265; all three copies broke.

held · 0.265measurementpartial observabilitydelay
Open case ↓Close ↑

The experiment

A heavy ball on a beam between two rigid decks joined by a stiff, well-damped flexure, with delayed, noisy, partially observed sensing and a weakest-case cap over the grading families. I built a leak-clean public bundle, let a frontier agent write its policy from that alone, and scored it on the grader-private cases.

The result

Headline 0.265, a miss. The agent's controller was strong: calibrated 0.702 before the cap, acing nominal tracking (0.886), plant transfer (0.897) and sensor degradation (0.864). What it could not do was recover the ball from the rail limits through the underactuation chain under delay, and the weakest-row cap made that one family decisive.

The three proxies, and why they all broke

  • A clean re-implementation of the same structure: cracked at 1.0. The public surface leaked the mechanism.
  • A regime-gap variant that hid which regime was active: 0.645. The agent hedged optimally across regimes.
  • A task designed to need a messy integrated stack (three-mass chain, two actuator faults, 250 ms delay, impulse kicks): 0.711. The agent wrote a 15-state extended Kalman filter with an impulse detector that rewinds and replays buffered measurements, unprompted.

The lesson, stated plainly

Implementation complexity is not difficulty. The only lever that held under measurement is information the policy cannot recover: partial observability and delay, applied to a recovery that is just barely achievable from observations alone. The 2026 literature agrees: delayed observation carries a provable optimality gap, and there is a computable lower bound on causal control cost that lets a reference be placed at the true optimum instead of tuned blind.

Multi-turn coding evaluations for frontier-model training

Prompts engineered so that capable models produce architecturally different solutions, then ranked with written rationales on seven fixed engineering axes. Preference pairs used directly in training.

ongoing since Jan 2026RLHFrubricspreference data
Open case ↓Close ↑

The craft

A useful comparison needs two answers that differ in a way a reviewer can defend, not two that differ in style. That means designing the prompt around a real fork: a concurrency choice, a data-model choice, an error-handling boundary. The follow-up turns then test whether the model holds its own design under pressure.

The grading

Seven axes, fixed before any output is read: correctness, robustness, design, readability, testing, performance, and communication. Each ranking ships with a rationale that cites lines, not impressions. The rubric is locked first so the rationale cannot drift toward whichever answer I liked.

Feedback loop

Every rejection from the client's review is traced to its cause and fed back into how the next prompt is built, so the acceptance rate is a lagging indicator of the rubric, not of effort.

Verification tasks for a frontier model's evaluation (Turing, 2025)

Python evaluation and verification tasks over synthetic healthcare, retail, logistics and finance data with controlled messiness, calibrated to a 20 to 50% model pass band and scored automatically.

Sep–Nov 2025synthetic dataautomatic scoring
Open case ↓Close ↑

What the work was

Each task combined a generated dataset with deliberate defects (duplicates, unit drift, missing keys, contradictory records) and a multi-step question whose answer could be checked programmatically. The checker verified reasoning steps and constraint satisfaction, not just a final number.

Calibration

Difficulty was tuned against the target model until pass rates sat in the 20 to 50% band, so each task carried signal: hard enough to fail sometimes, fair enough to be passable from the materials given.

AI Securewatch: co-founder, lead backend engineer

A startup I co-founded in 2024. First a payment-intelligence platform that finds insider-linked vendor fraud through entity resolution and graph analysis; now PayReality, decision intelligence that finds the unresolved questions behind an AI workflow's repeated escalations and turns them into tested rules.

2024 – nowentity resolutiongraph analysisdecision logicAWS · Python
Open case ↓Close ↑

The problem we started with

Enterprises pay thousands of vendors and formally manage a fraction of them. The gap between who an organisation thinks it pays (the vendor record) and who actually receives the money (vendor reality) is where insider-linked fraud hides: an employee who is also a vendor's director, shell companies sharing an address, invoices split to stay under an approval threshold. No procurement or third-party-risk system looks across those records at once.

The platform (2024 – 2026)

  • Payment-based vendor discovery. Start from the payment ledger, not the vendor master, so unmanaged and shadow vendors appear alongside the approved ones.
  • Entity resolution. Probabilistic record linkage across employees, vendors, company registrations and bank details (Splink on DuckDB): blocking on national ID, company registration, surname plus postal code, phone and email; Jaro-Winkler on names, Levenshtein on addresses, exact on identifiers. Built for South African data, including Luhn-validated ID numbers with date of birth and gender extraction, and company-registry formats.
  • Relationship graph. Resolved entities become a graph (NetworkX): shared addresses, shared directors, ownership links, employee-to-vendor connections, payment flows. Risk propagates across hops with decay, so a clean-looking vendor two steps from a flagged director still surfaces.
  • Seven detectors with explicit evidence requirements. Shell companies, self-supply loops, split purchasing, circular payments, ghost vendors, shared identifiers, dormancy spikes. Each has a defined signal set and risk weight, so an analyst can see why a score is what it is.
  • Measured against ground truth. A synthetic data generator embeds known fraud patterns with hidden labels, so detector recall and false-positive rates are measured before any client data is touched. The same habit as my evaluation work: a detector that is never tested against a planted answer is an opinion.
  • Delivery. Polars and Parquet for processing, a FastAPI service, an interactive dashboard, an ML anomaly layer for transaction behaviour, tamper-evident audit logging with on-chain verification, and automated response hooks; Python and Node.js on AWS. Modular monolith by choice: one engineer, a ten-week build window, clean module boundaries instead of infrastructure.

Where it is going: PayReality

Working with early-stage customers showed a more general problem than fraud. AI workflows handle the routine cases and stall on the exceptions, and the exceptions stall for the same reason again and again: a rule that was never made explicit. Two handlers get the same damaged-item claim; one approves, one escalates, because the policy never said whether a photo was required.

PayReality looks across many cases at once, finds the recurring uncertainty (missing information, unclear rules, judgement calls), prioritises the few questions whose answers would resolve most of it, has authorised experts answer them, encodes the answers as explicit decision logic, and replays historical cases against that logic before anyone trusts it. It sits under the models, rules engines and workflow tools a company already runs rather than replacing them. It is an evaluation harness for human and AI decisions, and it is currently a hypothesis we are testing with design partners, not a product with published customer results.

My role

Co-founder and the engineer who designed and built the backend end to end, from data model and resolution pipeline to API and deployment. I also work with my co-founders on roadmap, investor demonstrations and technical hiring.

Fleet operations platform: 24 desktop-application instances run from a phone

A year-long engagement for a client who operates many instances of a third-party desktop application. I built the control plane: hardware-level input, pixel-level state reading, a Discord-based operator console, a health loop that repairs its own failures, and an evidence harness that proves every feature on video.

in productionagentic systemscomputer usehuman in the loopreliability
Open case ↓Close ↑

The problem

The client needed to run and supervise up to 24 instances of an application that was never designed to be automated, from a phone, with no engineer on call. The application takes input only from real hardware and exposes its state only on screen. Every part of the stack had to be observable and recoverable without a terminal.

Architecture

  • Input as hardware. Six microcontrollers present 24 USB keyboards and 24 mice. Each instance owns one keyboard and one mouse, bound by serial number, so no two instances can ever cross-talk.
  • Isolation per instance. Each instance has its own virtual display, process tree, runtime prefix and network route. An instance without an assigned route is blocked at the socket layer rather than allowed to fall back.
  • State from pixels. Screen classification (login, character select, in world, popup, captcha) by validated pixel tests, with OCR only where text is the signal. Every reply to the operator says where the instance is and what to press next.
  • Operator console on Discord. One channel per instance with a persistent button panel; dashboards for capacity, finances, schedule and health, edited in place; history in threads; bilingual (English and Polish) from a single dictionary. Destructive actions confirm first; long actions report immediately and again when done.

Self-repair and evidence

  • A health loop walks each instance's dependency chain (board, display, input binding, controller, window) every 90 seconds, repairs what a reboot breaks, detects a failing microcontroller by its event stream and migrates the instance to a spare board, and applies upstream application updates by reading the vendor's own patch manifest.
  • An end-to-end harness exercises 13 features on a live instance, records a video and a per-step pass/fail table, and posts them as evidence. Its first two runs each caught a real production fault (a vendor update and an unsolved verification prompt) that the status system had reported as healthy.
  • A one-script rebuild of the whole stack on a fresh Windows machine, including firmware for new microcontrollers, with an offline kit that needs no downloads beyond standard tooling.

Human in the loop, by design

The application occasionally asks a person to prove they are one. The system detects that prompt, refuses to start automated work under it, and opens a magnified remote view so the operator can respond by hand through the same hardware path. It never answers on a person's behalf. The same principle runs through the console: anything with a cost to reverse asks before it acts.

Reliability work from the production audit

  • Replaced subprocess timeouts that never fire on Windows (only the shell dies; the child keeps the pipe) with process-tree kills, so a hung subsystem can no longer freeze the operator console.
  • Atomic config writes with a backup; a corrupt config refuses to start instead of silently running on defaults and overwriting the real one.
  • Per-instance command locks with a plain "busy with X" reply, fail-closed authorisation, central masking of credentials in every message, and deploys that roll back automatically if the service does not report healthy within 75 seconds.
  • Two independent review passes (one on wording and flow as a non-technical operator would experience it, one on failure modes); 45 UX findings and 9 critical robustness findings, all closed.

Method

How a task earns the right to ship

The order matters. Difficulty is measured, never asserted, and the measurement is taken against the strongest attacker available, before anyone spends time on polish.

1 · anchor

Oracle at exactly 1.0

A legal policy under the task's own rules, scored by the same grader the agents face. Not a number typed into a config.

2 · fair reference

Same information, 0.5

Built from the oracle's own code with one capability removed. If the reference needs privileged knowledge, the task is unfair, not hard.

3 · honesty gate

Naive policies at 0.0

Random, do-nothing, greedy, max-effort. Any of them scoring above the floor means the scorer rewards something other than the skill.

4 · attack

Strongest agent, public materials only

The agent's policy becomes a permanent regression test. The raw gap between it and the oracle is the task's real difficulty.

5 · record

Post-mortem either way

Held or cracked, the mechanism gets written down with numbers, so the next task starts from evidence rather than intuition.

Field notes

What the measurements keep saying

Conclusions I would not have believed without running the experiment. Each one cost at least one task.

Implementation complexity is not difficulty

A task designed to need a 15-state estimator, impulse detection and delay compensation was solved at 0.711. A strong agent writes the whole stack correctly when the structure is visible.

evidence: three-mass proxy, agent 0.711 vs ceiling 0.5

Publishing a proxy for a hidden variable kills the task

Making a hidden quantity observable, even indirectly, hands the agent the one thing the reference did not have. Hidden parameters only matter if knowing them changes the optimal policy.

evidence: sailing and slung-load salvage sweeps, both empty bands

Feedback erases planning on balanced systems

On an actively stabilised inverted plant, trajectory history is overwritten every step. Difficulty from planning cannot exist there; only controller quality remains, and that is perishable.

evidence: balanced-stick, oracle only 4% above agent

Shared information means shared pain

A disturbance added to rescue a task hurts the weaker controller more. If reference and agent see the same inputs, there is often no disturbance level where 1.0 / 0.5 / under-0.4 coexist.

evidence: gust escalation, agent 0.34 at reference 0.18

The only fundamental lever is unrecoverable information

Delay and partial observability carry a provable optimality gap. Everything else measured so far, including contact hybridity, was solved hierarchically by a strong agent.

evidence: 2026 literature scan filtered through measured results

A bare zero from an attacker is not a hold

An agent that hit its turn limit and never submitted also scores 0.000. The trustworthy signal is a low but non-zero final score with a readable reason.

evidence: 108 attack runs read for trajectory, not final number

Systems

Production software

Backend and product work that pays for the research habit. Five years of Python on AWS and in distributed architectures.

AI Securewatch

The startup I co-founded. Payment-graph fraud detection, now PayReality decision intelligence. Full account in the case study above.

co-founderPythonAWS

Read the case study

repo-testify

Technical due diligence that executes a repository's own README claims instead of reading them: extracts claims, runs them in a sandbox, and produces a per-claim verdict ledger with explicit abstention. Built for a 75-hour agentic-workflows hackathon with an honest baseline and ablations.

Pythonagentsevaluation

github.com/Nathanjr123/repo-testify

McIntyre MedSys

Clinical communication and patient-safety platform for nursing teams: structured handover, escalation ladder, dual-sign telephone orders with a tamper-evident audit trail. Zero-dependency web app, shipped as a clickable MVP.

JavaScripthealth techPOPIA-aware

Live MVP · Source

RisCura asset-management platform

Backend services and SQL Server query optimisation for an internal platform used daily by the investment team. Microservices and R Shiny front ends in production.

SQL ServermicroservicesR Shiny

About

Nathan Chukwudi Obiekwe

I trained in applied mathematics and computer science at Rhodes University and have worked as a backend engineer and independent consultant since 2019. Since late 2025 most of my time has gone into evaluation work for frontier labs: designing tasks, writing graders, and finding out, with numbers, where a model's ability actually ends.

I like work where the output can be checked. A task with a deterministic grader, an oracle that must hit 1.0, and an attacker's score on record is honest in a way a slide is not. I keep post-mortems of everything that failed because the failures are where the method came from.

I work remotely from Johannesburg, as a contractor or through an employer of record, and overlap comfortably with US East and European hours.

Jan 2026 – nowRL environments and coding evaluations for frontier-model training, via Alignerr
Sep – Nov 2025LLM evaluation and verification tasks, Turing
Oct 2024 – nowCo-founder and lead backend engineer, AI Securewatch (PayReality)
2024Solidity developer, Linum Labs
2022Software developer, RisCura
2019 – nowIndependent software consultant
2021BSc Applied Mathematics and Computer Science, Rhodes University