A client-side provenance contract on tool-call arguments removed 421 attack successes and induced 26. McNemar exact p = 5.6e-93, six models, 1,800 paired runs.
AI RELIABILITY & EVALS PLATFORM
Non-deterministic models.
Deterministic decisions.
FAULTLINE measures how AI agents behave across repeated runs, turns that into rule-checked release decisions, and guards tool calls at runtime. Open-source tools, and services when you want us to run it with you.
OPEN SOURCE · MIT · FAULTLINE EVALS · FAULTGATE 0.3.1 · MCP-GUARD
Measure the agent over repeated runs with a deterministic oracle
Turn test runs into rule-checked release decisions in CI
Check tool calls at runtime against pinned tool definitions
One continuous loop: FAULTLINE Evals in the lab, faultgate in CI, and mcp-guard at runtime.
01 / WHY NOW
Same model, same inputs, different results.
Same model, same 30 inputs, five runs: pass rate moved from 0.60 to 0.87.
A new model, prompt or tool can break an agent that passed yesterday. Every one is a release.
Tracing tools show what happened. A person still has to decide whether to ship.
Our code check for search loops agrees with human labels (κ 0.98, n = 200). Model judges on the same question: κ 0.09 or below.
02 / THE PLATFORM
One loop: evaluate, gate, guard.
FAULTLINE Evals
A reproducible research workbench for evaluating autonomous AI agents under repeated execution. Measures run-to-run variance with a deterministic oracle.
- 1,350 graded runs across 150 scenarios at temperature 0.0
- Deterministic dual-condition oracle, no model judges in the loop
- pass^k independence holds within 2.5 percentage points
faultgate 0.3.1
A local-first release gate that checks traces for known failure modes, measures noise bands, and returns PASS, FAIL or INCONCLUSIVE in CI.
- PASS / FAIL / INCONCLUSIVE with required sample size in CI
- Business rules in policy.json as a hard block
- Reads OTLP, Langfuse, LangSmith, Braintrust, Phoenix
mcp-guard
A local firewall for MCP tool calls. Sits between your AI client and MCP servers: logs every call, flags poisoned descriptions, and blocks rule violations.
- Pins tool definitions on first run to detect rug-pulls
- Flags poisoned descriptions and prompt injection heuristics
- Blocks unknown tools and extra arguments in enforce mode
Models will stay non-deterministic. Our job is to make every decision about them deterministic.
03 / HOW IT WORKS
Block regressions before they merge, in three commands.
Measure the agent over repeated runs with a deterministic oracle; get a noise band, not a single score.
On every change, faultgate returns PASS, FAIL or INCONCLUSIVE in CI; business rules are a hard block.
At runtime, mcp-guard checks tool calls against pinned tool definitions.
- uses: Faultline-lab/faultgate@main
with:
traces: traces/candidate.json
band: traces/band.json
policy: traces/policy.json
comment: "true"04 / SEE A RELEASE DECISION
See exactly why a release failed, on the PR.
Gate: clean rate 0.87 vs band [0.80, 0.87] from 2 baseline runs · fail below 0.70 · p=0.642
4/30 traces failed · judge none · redaction builtin
| check | fired |
|---|---|
search_loop | 2 |
abstention | 0 |
policy | 0 |
repeated_call | 0 |
unrecovered_tool_error | 0 |
context_overflow | 0 |
wrong_answer | 2 |
truncation | 2 |
| scenario | trace | check | reason |
|---|---|---|---|
r-0221 | 30e9a0bd0f27 | search_loop | no answer, 24 steps (cap), 58% empty results |
r-0263 | b314e7088369 | wrong_answer | expected 'Prism-4914' not found in answer |
r-0263 | b314e7088369 | truncation | answer has 'Prism' but not 'Prism-4914' |
r-0274 | 3f7adb56dfc8 | wrong_answer | expected 'Sable-4967' not found in answer |
r-0274 | 3f7adb56dfc8 | truncation | answer has 'Sable' but not 'Sable-4967' |
r-0277 | 93b9ae6c03a6 | search_loop | no answer, 24 steps (cap), 58% empty results |
| metric | baseline | this run | Δ |
|---|---|---|---|
| latency / run | 16.5 s | 16.0 s | -2.7% |
pip install 'faultgate==0.3.0'
faultgate check examples/gate/baseline_glm_run2.json --band examples/gate/band.json --golden examples/gate/golden.jsonPASS example: a baseline run checked against its own band.
{
"faultgate_version": "0.3.0",
"created_utc": "2026-10-13T13:49:21Z",
"verdict": "FAIL",
"exit_code": 1,
"command": "faultgate check examples/gate/candidate_gpt.json --band examples/gate/band.json --golden examples/gate/golden.json",
"inputs": [
{
"role": "traces",
"path": "examples/gate/candidate_gpt.json",
"sha256": "0f23010a2da86e7695e7c99b6748246aac13a36d28748ea1d76128eff9144b29"
},
{
"role": "band",
"path": "examples/gate/band.json",
"sha256": "5cd572abf5efce5cdbc9d53acd4de7b5c7abafa3388b65813c32affa51e62a12"
},
{
"role": "golden",
"path": "examples/gate/golden.json",
"sha256": "b70463146559496637f01e004cb35d485a1f33446f282964b8e0e59f104ddc0b"
}
],
"judge": "none",
"checks": [
"search_loop",
"abstention",
"policy",
"repeated_call",
"unrecovered_tool_error",
"context_overflow",
"wrong_answer",
"truncation"
],
"redaction": "builtin",
"traces": 30,
"failed_traces": 21,
"fired": {
"search_loop": 18,
"abstention": 0,
… (57 more lines)[
{
"trace_id": "4dc5e933abe820a352c63601a0319ce9",
"scenario": "r-0336",
"checks": [
{
"check": "wrong_answer",
"reason": "expected 'Alto-5275' not found in answer"
},
{
"check": "truncation",
"reason": "answer has 'Alto' but not 'Alto-5275'"
}
]
},
{
"trace_id": "51c15300072be9563b8dcdae613d3f7f",
"scenario": "r-0221",
"checks": [
{
"check": "search_loop",
"reason": "no answer, 24 steps (cap), 62% empty results"
}
]
},
{
"trace_id": "b6f824a010a79968e6d3403a3eb240f0",
"scenario": "r-0286",
"checks": [
{
"check": "search_loop",
"reason": "no answer, 24 steps (cap), 79% empty results"
}
]
},
{
"trace_id": "7e74e68d7296e93d8e5e679451c99795",
"scenario": "r-0232",
"checks": [
{
… (184 more lines)#!/bin/sh
# faultgate 0.3.0 · verdict FAIL · exit 1
pip install 'faultgate==0.3.0'
faultgate check examples/gate/candidate_gpt.json --band examples/gate/band.json --golden examples/gate/golden.json
Real output of faultgate 0.3.0 on the examples in its GitHub repo. PR number is illustrative.
Reproduce it06 / WORKS WITH YOUR STACK
Reads the traces you already record.
07 / FINDINGS
What 1,800 paired runs taught us about agent failure.
Repeated trials compound almost exactly as (pass@1)^k at k = 3. 150 held-out scenarios, 1,350 runs, deterministic oracle, no model judge.
32 of 34 R2 failures never surfaced a required chain document. A stronger model does not fix that; oracle retrieval rescues all 32 at 3.1× fewer tokens.
Serving variance moves a fixed model across 27 points. Release gates must be tolerance bands graded on a pinned golden set, not thresholds.
08 / SECURITY
Your traces stay in your CI.
Turn on an API judge and only a redacted copy goes to your model provider.
Local-first
faultgate reads traces in memory and writes no trace payloads anywhere. Rules, policy, bands and the local judge never send anything off the machine.
Redacted by default
anything that leaves (API-judge input, reasons in CI logs and PR comments) is masked: emails, Luhn-checked cards, SSNs, phones, IPs, API keys, bearer tokens, JWTs. Presidio optional.
Auditable
every run can write verdict.json with the SHA-256 of every input, failing_traces.json and repro.sh. No prompts, answers or tool payloads are copied.
Open source
MIT, one dependency (pydantic), runs in your CI runner. Read every line.
Make your agent's next release a deterministic decision.
Free and open source today. Gate, the managed layer, is on the roadmap. Design partners help build it.
Gate: clean rate 0.30 vs band [0.80, 0.87] from 2 baseline runs · fail below 0.70 · p=0.000
Regressions (clean in every baseline run, not now):
r-0214,r-0216,r-0226,r-0258,r-0279,r-0286,r-0292,r-0317,r-0320,r-0322,r-0324,r-0330,r-0332,r-0344,r-035021/30 traces failed · judge none · redaction builtin
search_loopabstentionpolicyrepeated_callunrecovered_tool_errorcontext_overflowwrong_answertruncationr-03364dc5e933abe8r-03364dc5e933abe8r-022151c15300072br-0286b6f824a010a7r-02327e74e68d7296r-021610fa2370723er-029210a63caed2d6r-021404a16662742er-0263b80e27d064fer-0344ab3503d28cdar-03204d6f5e788fe1r-0350316bcde0d931r-02248fd42bacf992r-033209a946f2c89dr-033209a946f2c89dr-027954f099f8147er-0330ac2a7d9eaf68r-02266f508650cff0r-025825465761c097r-03244c78f65e849dr-03244c78f65e849dr-03228e4ab8196357r-0317a3131ab0f714