Dublin, Ireland

I build the correctness layer underneath tool-calling AI systems — and I measure the instruments the field uses to judge them.

A more capable model does not fix idempotency, determinism, crash recovery, authority boundaries, or honest uncertainty. When a tool call times out, the local journal cannot distinguish the request never arrived from the request committed and the acknowledgement was lost — no amount of reasoning recovers that bit. So the work below shares one design signature: when the truth is not knowable, the system records an explicit unknown and stops at a human gate instead of guessing well.

The same instinct points at evaluation. A benchmark that reports “this model writes secure code 62% of the time” is reporting what a checker said 62% of the time. My current research measures how much of that verdict is a property of the code and how much is a property of the checker.

Best fit: backend engineering, AI infrastructure, developer tools, and security-focused platform roles.

Download résumé View HTML résumé Review selected systems

What this page does not claim

I have no publications, preprints, or peer-reviewed papers, and no ORCID or Google Scholar record yet. Everything described below is public code and reproducible research artifacts. Where a number appears, it was produced by a command in the repository that reports it, and the caveat that repository states is repeated here rather than dropped.

01 Research focus

Three threads, in the order I currently spend time on them. All three are about the same question: what does a system know, and what is it only assuming?

Evaluation-oracle integrity

Most reported “security of AI-generated code” is scored by static, single-CWE, function-level checkers. If those checkers respond to the form of the code rather than its behaviour, then any intervention that shifts style can move the score without moving the security. I build corpora whose labels are earned by running an exploit, and score the checkers against them.

Secure-coding instructions for coding agents

If an identical secure-coding sentence is placed in the task prompt, the repository context, both, or neither, does the agent’s output change — in security and in functional correctness? A 2 × 2 factorial design, pre-registered in public before holdout outputs were generated, with development tasks permanently separated from an untouched holdout.

Correctness and authority for agent side effects

Retries turn one intended charge, refund, or production change into several. I build the boundary that stops that: stable intent, one downstream idempotency key across every attempt, authoritative reconciliation, and an explicit outcome_unknown that stops for a human instead of faking exactly-once.

02 Evidence

Numbers that came out of a command, with the conditions under which they were produced. Each table names the repository and file it is drawn from.

Figure 1 Five security oracles against 96 Python implementations whose labels were established by executing an exploit — 48 secure, 48 vulnerable, 0 invalid, 0 disagreements with author intent. A perfect oracle scores Youden’s J = 1.0.
Oracle Sensitivity Specificity Youden’s J
structural AST, written for this study68.8%79.2%+0.479
pattern regex, written for this study75.0%62.5%+0.375
bandit 1.9.452.1%75.0%+0.271
semgrep 1.173.0 p/security-audit31.2%93.8%+0.250
semgrep 1.173.0 p/python20.8%95.8%+0.167

Intervals in the source report are percentile bootstrap over cases, not variants, because variants inside a case are not independent draws. Two pre-planned sensitivity analyses — count any finding, or count only confident findings — move bandit by ±0.04 and change nothing else.

Figure 2 The same five oracles against 140 real fixes to real CVEs in 65 real projects — aiohttp, Django, Synapse, superset, GitPython, Anki, thumbor, python-rsa. Each observation is one Python file immediately before a security fix and at the fix. The right-hand column asks only whether the verdict changed when the weakness was actually repaired.
Oracle Detected the pre-fix file Fixes that changed nothing in its verdict
bandit29.3% (41/140)95.7%
structural29.3% (41/140)96.4%
pattern27.1% (38/140)92.9%
semgrep p/security-audit7.9% (11/140)98.6%
semgrep p/python4.3% (6/140)97.9%

For between 130 and 138 of 140 real security fixes, the oracle said exactly the same thing before and after. Detection rates are reported as floors, because a fix commit may touch files that never carried the bug; the fix-blindness column needs no such assumption. 37 of the 77 single-file fixes were missed by every one of the five oracles.

Figure 3 False alarms follow the spelling. “Plain” and “decoy” variants are both secure — the same exploit witness was run against both and failed against both. Decoys merely carry the weakness class’s lexical signature: the dangerous call written out in a comment, md5 as a cache key in a module that stores passwords with PBKDF2, shell=True with every argument correctly quoted.
Oracle Plain secure flagged Decoy secure flagged Ratio
pattern6.9% (2/29)84.2% (16/19)12×
structural6.9% (2/29)42.1% (8/19)
bandit13.8% (4/29)42.1% (8/19)
semgrep p/security-audit0.0% (0/29)15.8% (3/19)
semgrep p/python0.0% (0/29)10.5% (2/19)

One secure variant was flagged by all five oracles: shell=True with every argument quoted for the platform. The witness fires a shell separator at it and the injection fails. A benchmark using any of these oracles would count that implementation as insecure.

Did the hand-built corpus predict reality?

Over the 30 (oracle, weakness class) cells the two studies share: 83% agreement (25/30) on whether an oracle detects a class at all, Spearman ρ = +0.782 between synthetic and real detection rates, and the real rate is lower than the synthetic rate in 19 of 30 cells. A corpus written to embarrass these tools would score them below their real-world performance. This one scores them above it — the hand-written mutants are easier than what maintainers actually shipped.

Figure 4 Measuring a grounded-answering system rather than asserting it. Retrieval recall is a credibility property here, not a relevance nicety: a system that refuses when it retrieves nothing will confidently deny a qualification it actually holds.
Retrieval, over 24 questions answerable from the corpus recall@8 MRR No evidence returned
Token overlap12/24 (50%)0.3681
BM25 + reviewed alias map24/24 (100%)0.8960
Claim verification, 36 labelled claims (20 fabricated) Precision Recall Fabrications accepted
As originally shipped — overlap ratio only0.5560.93812 / 20
With unsupported-name check, threshold from a sweep0.9411.0001 / 20

Read the 100% with the caveat it deserves: the eval set and the alias map were written in the same sitting, so it measures whether known vocabulary gaps stay closed, not general recall. One labelled fabrication still passes verification, and a test pins it so the gap stays visible.

The most useful number I have is a negative one

A regex prompt-injection filter caught 18 of 18 phrasings the patterns were written against, 0 of 10 phrasings written afterwards for the same intents, and produced 0 false positives on 26 ordinary questions. The 100% is meaningless — the patterns and that corpus were written together. The honest figure is the second row, and it is not a gap to close by adding patterns; it is what keyword matching is against anyone who can rephrase. So the filter is a courtesy, not a defence. The layer that actually holds is grounding: tests assert that every held-out injection evades the filter and every fabrication it was fishing for is still refused.

Reproducibility, as reported by each repository

secure-instruction-placement
48 unit tests, standard library only; CI on Python 3.11 and 3.12; six public releases
effect-broker
68 passed, 11 skipped at commit 61906b2 on Python 3.13.5; ruff check clean. The 11 skips are the Postgres cases, which need a test DSN
agent-redteam
153 passed; ruff check clean; every target and model response in that run was a local fake or a recorded fixture
agentic digital twin
216 passed with network access blocked inside pytest; CI across Python 3.11, 3.12 and 3.13
PatchPilot
118 passing tests at v0.18.0; public Action smoke-tested in CI; provider campaigns verify three asset hashes and a customer-pinned Ed25519 key before applying code

Test counts are evidence that a claim is checked, not that a system is correct. They are listed because the alternative — asserting quality — is worth less.

03 Research artifacts

Does the oracle read the code, or the spelling?

Two studies. A controlled one: five oracles against 96 Python implementations whose security labels were earned by executing an exploit, never asserted by an author. And a production one, on code nobody involved wrote: the same five oracles against 140 real fixes to real CVEs in 65 real projects, where the label comes from a reviewed advisory and the maintainer’s own patch. The second exists because the first has an obvious objection — its author also chose the mutations.

The design separates the two reasons a verdict is wrong: not having a rule, and having a rule that matches the wrong thing. The headline statistic is conditional on the oracle having flagged the textbook form, so absence of coverage cannot be mistaken for form-sensitivity. The protocol was fixed before any oracle ran.

  • 96 execution-labelled variants across 8 weakness classes; 48 secure, 48 vulnerable, 0 invalid
  • 140 real CVE fix pairs, 102 advisories, 65 repositories
  • Labels replicate across platforms — identical split and identical scores on an Ubuntu CI runner under Python 3.12
  • Stated gap: CodeQL, the oracle behind much of the published literature, is not audited

It does not claim any published benchmark is wrong; it characterises families of oracle. It does not measure static analysers as static analysers — a tool tuned for a low false-positive rate is behaving correctly when it stays quiet. The claim is about what happens when such a tool is promoted to benchmark ground truth, where silence is scored as security. The corpus is small and hand-built: no rate here estimates how often this happens in the wild.

Repository

Secure Instruction Placement for AI Coding Agents

A 2 × 2 factorial design over where a fixed security sentence lives: absent, in the task instruction, in the repository context, or both. The pre-specified primary outcome is joint functional-and-security success under executable tests. The point of publishing the artifact before results is to make the research decisions inspectable: exact wording, task and verifier contracts, benchmark seed audits, a fail-closed runner with immutable raw records, and the analysis code.

  • Two public, explicitly non-confirmatory pilots — a four-condition infrastructure pilot and a 12-run writable-agent pilot with hashes and executable outcomes
  • A development security-oracle mutation audit detected 3/3 targeted unsafe regressions while all functional tests still passed
  • Three pilot tasks permanently locked as development data; eight untouched tasks protected as a holdout
  • A deterministic 96-run schedule and task-clustered factorial analysis committed before holdout execution
  • The runner refuses to execute while the agent configuration is marked draft-not-frozen

Confirmatory runs have been executed locally, but their outputs and analysis are not yet a reviewed public result. This page therefore claims no experimental effect. Pilot observations remain non-confirmatory by construction, and independent methods review is still outstanding.

Repository

04 Selected work

Working systems with offline deterministic test suites so what is under test is the system’s behaviour rather than a provider’s mood.

PatchPilot

APIs that migrate their own customers

A working response to YC's Self-Maintaining APIs request. A provider can fan one signed, hash-pinned API release out to as many as 100 opted-in customer repositories. Each customer's protected workflow verifies its own pinned Ed25519 key, finds affected JavaScript, TypeScript and Python call sites, applies deterministic syntax-valid edits, and opens a reviewable pull request. See the v0.18.0 release.

It does not pretend a model can safely guess every migration: ambiguous changes are flagged for a human rather than invented. Missing operation IDs and safe changes with no supported call-site evidence are reported as coverage gaps, never as successful migrations. Campaigns are an end-to-end prototype, not a hosted service: customer consent is currently file-backed, and there is no revocation UI. It runs parser-level syntax checks and never executes uploaded customer code.

effect-broker

Correctness boundary for side-effecting agent tools

One downstream idempotency key across every retry, authoritative reconciliation, and an honest manual_review instead of a fake exactly-once guarantee. The crash matrix kills a worker with a real os._exit(137) after the target commits but before the receipt is written — the exact window that causes double-charges — then asserts the target-side effect count after recovery.

Explicitly not an unconditional exactly-once system: if a target supplies neither idempotency nor authoritative reconciliation, the broker stops and requires manual review. Ships no production payment or email adapters.

agent-redteam

Adversarial testing and runtime guardrails for LLM agents

A layered oracle scores attack success from planted evidence rather than by eyeballing model output, and rolls it into a recomputable risk vector you can gate CI on. Agentic findings carry a hash-chained causal proof: the poisoned trace, a clean-fixture counterfactual, and the attribution claim share one content address, so post-run edits are detectable without rerunning a model.

Defensive tool for systems you own or are authorised to assess; a run is refused unless the target config asserts authorisation and the host is allowlisted. Canaries are synthetic. The offline result does not measure any live model, and passing the suite is not a claim of security.

agentic-digital-twin

Source-grounded answering behind an authority gate

Answers only from a structured CV corpus and live allow-listed repository metadata, naming its sources. Background research can propose visitor context, but the context assembler has no code path that admits it until the visitor confirms — pre-confirmation isolation happens before any model is called, so prompt instructions are defence in depth rather than the access-control mechanism.

Retrieval and verification are measured, not asserted — see Figure 4 and the negative result above.

Also public

05 How I work

  1. Prove the failure, not the happy path.

    A test that shows the system working under good conditions is a demonstration. The interesting assertion is what the target looks like after a worker is killed inside the one window that causes duplicates.

  2. Durable before dispatch.

    Append the intent to a journal, then act. Recovery reads the log, never process memory, and compare-and-swap transitions keep two workers from advancing the same record.

  3. Degrade to unknown, not to a guess.

    Every one of these systems has a verdict for cannot be determined, and it is never the optimistic one.

  4. Keep a human on the authority boundary.

    Irreversible or external effects pass through an explicit gate with recorded scope, not a confidence threshold. A proposal is not an authorised effect.

  5. Measure the thing you are about to claim.

    Both of the most valuable numbers I have produced were unflattering: a claim verifier that accepted 12 of 20 fabrications, and an injection filter that caught none of the ten held-out rephrasings. Publishing those is what makes the favourable numbers on the same page worth reading.

  6. Default to offline and deterministic.

    Test suites and demos run with no API keys and, where it matters, with the network blocked inside the test process.

06 Background

I am a software engineer in Dublin, Ireland, working on the reliability and evaluation of AI systems that take actions. My route into it was ordinary: support engineering, then backend and platform work, then a master’s in cybersecurity — and then the growing suspicion that the hardest problems in agent systems are not reasoning problems at all, but information and atomicity problems that better models do not touch.

Education

  1. Sep 2024 – Sep 2025

    MSc, Cybersecurity

    Dublin Business School, Ireland

  2. Aug 2021 – Jun 2024

    Bachelor’s degree, Computer Science — First Class

    Savitribai Phule Pune University, India

Experience

  1. Jan 2025 – present

    Independent Software Engineer — AI and Automation Systems

    Dublin, Ireland

  2. Oct 2024 – Dec 2024

    Java Developer Intern

    PhysicsWallah — remote

  3. Jun 2022 – Jul 2024

    Software Engineer

    matriXploit, India — on-site

  4. Jan 2022 – Jun 2022

    Technical Support Engineer

    matriXploit, India

Tools I reach for

Python · Java · FastAPI · Spring Boot · PostgreSQL · SQLite · Docker · Kubernetes · AWS · Azure · Terraform · MCP · pytest · Ruff

Listed because they appear in the work above, not as a proficiency ranking.

07 Contact

Email is the reliable channel. It is the same address recorded as the git author identity on the research commits, so the artifact trail and any future publication trail agree without rewriting.

No ORCID or Google Scholar record exists yet; this page will link them when they do. If you are checking a claim on this page, the repository that produced it is linked beside it — please read the caveats it ships with.