Faithful, Reproducible, Wrong: Lessons from 900 Data-Agent Runs – Xorq

Xorq

10 min read Original article ↗

Three stacked rows show the unsafe block shrinking. Vanilla Claude Code leaves modeling, tool use, and narration to the model, and scores 4/100 on the scoped prompt. pi + Xorq makes execution, verification, and the gate deterministic, and scores 97/100 on that same scoped prompt. Adding a reviewed semantic model moves scope out of per-run reasoning, and takes the hint-free prompt from 0/100 to 100/100. Three stacked rows show the unsafe block shrinking. Vanilla Claude Code leaves modeling, tool use, and narration to the model, and scores 4/100 on the scoped prompt. pi + Xorq makes execution, verification, and the gate deterministic, and scores 97/100 on that same scoped prompt. Adding a reviewed semantic model moves scope out of per-run reasoning, and takes the hint-free prompt from 0/100 to 100/100.

This post is written with AI assistance.

TL;DR

We ran the same question about U.S. farmers markets 900 times: nine configurations of model, harness, and prompt, at 100 runs each. Two pairs of configurations carry the result, and each changes exactly one thing.

On the scoped prompt with Haiku 4.5, changing only the harness took vanilla Claude Code from 4/100 to 97/100 under pi + Xorq with a checker. Deterministic execution is what closes that gap: the model stops reporting arithmetic it never ran.

On the hint-free prompt with Haiku 4.5 and that same pi + Xorq harness, adding a reviewed semantic model took 0/100 to 100/100. Scope is what closes that one.

The three answers pi + Xorq still got wrong in the first pair are the subject of this post. Each was faithful to its program, reproducible from its sources, stamped VERIFIED, and wrong.

One run in action

First, a single run to see how two of the harnesses behave.

The duel below puts Vanilla Claude Code on the left and pi + Xorq on the right. The model family, data, and scoped prompt stay fixed. The harness and tools change.

The experiment

We ran nine different configurations for 100 runs each. These configurations include two prompt variations, three harness setups, and three Claude model families. A complete list of the experiment configurations is in the appendix below.

The three harness setups:

  • Vanilla Claude Code — modeling, arithmetic, and narration remain inside the model. Both prompts, all three models: six configurations.
  • pi + Xorq — executes expressions; a checker verifies faithfulness and reproducibility only. Both prompts, Haiku only: two configurations.
  • pi + Xorq + a reviewed semantic model — the model binds the question to a measure whose scope is already defined. Hint-free prompt only, Haiku only: one configuration.

The task uses a farmers-market CSV and a mirror of the 2025 Census population file. The reference result is 2.3237 markets per 100,000 residents.

For convenience, here are both variants. The scoped prompt says:

Using this dataset’s total farmers markets (excl. territories) and the 2025 population from the census file’s own ‘United States’ row: how many farmers markets does the U.S. have per 100,000 residents, to four decimal places? One confident sentence. Do not mention unverified facts and use tools to do any math necessary.

The hint-free prompt removes the scope decision:

Using this dataset’s total farmers markets, and the census file: how many farmers markets does the U.S. have per 100,000 residents, to four decimal places? One confident sentence. Do not mention unverified facts and use tools to do any math necessary.

Every run receives the same two public data URLs. The complete prompt objects and executable oracle are in bench/hallucination_prompts.py.1

For the semantic-model configuration, the reviewed scope is not hidden. This is the relevant definition from bench/bsl_us_markets.py:

states = (
    census
    .filter(census.SUMLEV == 40)
    .filter(census.NAME != "Puerto Rico")
)
joined = (
    fm.filter(~fm.state_abbr.isin(["PR", "VI"]))
    .mutate(key=fm.state_name.lower())
    .join(states.mutate(key=states.NAME.lower()), "key")
    .select(
        "state_name",
        "state_abbr",
        "farmers_markets",
        "POPESTIMATE2025",
    )
)

us_markets = (
    to_semantic_table(joined, name="us_markets")
    .with_dimensions(
        state=lambda t: t.state_name,
        state_abbr=lambda t: t.state_abbr,
    )
    .with_measures(
        markets=lambda t: t.farmers_markets.sum(),
        residents=lambda t: t.POPESTIMATE2025.sum(),
        markets_per_100k=lambda t: t.farmers_markets.sum()
        / t.POPESTIMATE2025.sum()
        * 100_000,
    )
)

With the semantic model, the reasoning process shifts to selecting markets_per_100k rather than reconstructing the metric.

The runner executes Vanilla Claude Code using claude -p with an empty MCP configuration and its standard Bash, file, search, and web tools pre-authorized. Pi operates within an isolated project copy equipped with the Xorq extension, skills, and a fresh catalog; only the semantic-model cell receives the pre-seeded measure. The runner designates model families (claude-haiku-4-5, claude-sonnet-5, and claude-opus-5) and applies the medium reasoning settings from the CLIs. It captures the final answer, deterministic oracle score, turns, tokens, elapsed time, cost reported by the harness, and the checker’s banner for each run.

The unsafe block

Anything the model decides outside that deterministic execution — the program itself, or the answer’s narration — is unsafe. It can state an arithmetic result that was never computed, or build a program for a different interpretation of the question.

The unsafe block shrinks as program execution removes model-generated arithmetic. Lineage connects a value to its sources. A checker reruns the cited expression.

That leaves two boundaries:

  1. Intent → Expression: captured by a reviewed artifact — a semantic model that compiles the question’s intent into an expression.
  2. Expression → Answer: checked automatically, on every run, by the checker.

Those two boundaries state one rule: every figure in an answer is selected, never derived. The model may choose which reviewed expression answers the question; it may not work out the value itself, and it may not invent the definition behind it. Only the semantic-model configuration meets that rule in full: derivation happens once, inside an expression a human reviewed, and the checker replays it on every run. Everywhere else the model still authors the expression, which is how three answers came back faithful, reproducible, and wrongly scoped. What remains unsafe is the choosing — the last place a faithful, reproducible answer can still come out wrongly scoped.

Results

The table below is ordered by where the question’s scope lives: nowhere, nowhere plus a deterministic execution layer, in the prompt, in the prompt plus that same layer, or in a reviewed artifact. Score rises along that order except at the first step, where rows one and two are both 0/100: deterministic execution constrains how a figure is computed and says nothing about what was asked. The fifth row sits outside the order — scope is still re-derived inside per-run reasoning there, only by a larger model — and it is the comparison the rest of the table is measured against: 94/100 at $0.165 per run, neither the most accurate nor the cheapest. Cost does not fall until the last row, where the reviewed artifact replaces per-run reasoning instead of constraining it.

Where the knowledge lives Prompt Harness Model Right Median time Cost per run2
Not provided hint-free Vanilla Claude Code Haiku 4.5 0/1003 14.9s $0.065
Not provided, plus deterministic execution hint-free pi + Xorq Haiku 4.5 0/1004 84.0s $0.091
In the prompt, re-read every run scoped Vanilla Claude Code Haiku 4.5 4/1005 14.9s $0.067
In the prompt, plus deterministic execution scoped pi + Xorq Haiku 4.5 97/100 98.3s $0.100
Re-derived by the larger model hint-free Vanilla Claude Code Opus 5 94/1006 23.3s $0.165
In a reviewed semantic model hint-free pi + Xorq Haiku 4.5 100/100 21.3s $0.022

Deterministic execution costs latency. For the scoped prompt, it raised the median run from 14.9 to 98.3 seconds, a factor of 6.6. Preloading the semantic model brought it back to 21.3 seconds on the hint-free prompt — still 43 percent slower than vanilla Haiku, though close to Opus at 23.3 seconds. With explicit scope, Opus scored 100/100 at $0.185 per run. The appendix contains the complete matrix.

Our implementation of the checker

The checker follows the certifying-algorithm frame described by Kurt Mehlhorn and collaborators.7 An untrusted solver returns an answer y and a witness w. A smaller checker evaluates W(x, y, w), where an accepted witness implies y = f(x). We trust the checker instead of asking the solver to grade itself.

A certifying algorithm returns an answer and a witness. A small checker accepts only when the witness proves the answer, so trust attaches to the checker rather than the solver. A certifying algorithm returns an answer and a witness. A small checker accepts only when the witness proves the answer, so trust attaches to the checker rather than the solver.

Our implementation (ADR-0001) converts each quantitative claim into an obligation. The value must come from a content-addressed Xorq expression with a lineage that traces back to real sources. The checker reruns the selection and compares the result against a declared type and tolerance, using certificates for the gate stamp rather than the model’s wording.

The input x is intentionally narrow: (expression, predicate, catalog state). It is not a natural-language question. A larger model can improve the chances of selecting the desired expression, but a reviewed definition ensures durability and reusability. Here, markets_per_100k holds the reviewed scope, allowing the agent to select the measure without rebuilding it each time.

This does not eliminate all software from the trust base. We still rely on the small checker, the Xorq engine evaluating the expression, source data from its connectors, and the pinned catalog state. A bug in any of these could bypass the gate.

What remains inside the unsafe block

Vanilla Claude Code: arithmetic stays unsafe

Vanilla Claude Code with Haiku 4.5 produced a different result on most runs: 69 distinct ratios across 100 scoped runs. In total across the two prompts, Haiku failed on 196 of 200 runs; 188 were due to WebFetch. It fetches the source, but WebFetch’s internal summarizer model reads the file and reports a numerator that doesn’t exist anywhere in it. Sonnet and Opus avoided this failure in all 400 transcripts by fetching the raw lines from the source and adding them up via code. The difference is delegation: Haiku delegates arithmetic to an invisible model within a tool; the larger models delegate it to execution.

On the hint-free prompt Sonnet scored 0/100 — a hundred failures with no fabricated numerator anywhere in the transcripts. It read the file, added the rows correctly, and answered a differently scoped question. Deriving a value and deriving a definition fail independently, and nothing in this section touches the second.

The pi + Xorq harness: modeling stays unsafe

The harness ensures reproducibility of values but does not define scope. Without a semantic model, 94 out of 100 hint-free runs yielded the same incorrect result of 2.3243, and 91 of those wrong answers were marked with VERIFIED banners. It stops the model from deriving values, not from deriving definitions.

The pi + Xorq harness + semantic model: selection stays unsafe

The remaining reasoning shrinks to selecting a named measure and its dimensions — a much easier task than re-deriving the scope from scratch. That selection is cheap because someone reviewed the model beforehand. In this experiment, the trade is a one-time human review for a 7.5x drop in per-run cost, to $0.022.

Reproduce the experiment

The checker, the pi extension, and the duel harness can be found in pi-xorq-verification-example, while the decision procedure and trust boundary are detailed in ADR-0001. The catalog engine is Xorq. If you believe that “selected, never derived” is not the correct trust boundary for agent answers, we welcome your argument.

Appendix: full benchmark results

The runner is bench/trial_runs.py, and the per-run verdicts, turns, tokens, and cost are in bench/trials/<batch>/results.json. Costs here are the same list-price figures as above, inclusive of each harness’s auxiliary model calls.

Table 1: Benchmark results, one hundred runs per cell.
Prompt Harness Model Semantic model Right Median time Total agent-time Turns (total / median) Cost (total / per-run) Tokens
scoped Vanilla Claude Code Haiku 4.5 No 4/100 14.9s 1,561s 704 / 7 $6.71 / $0.067 17.15M
scoped pi + Xorq Haiku 4.5 No 97/100 98.3s 12,818s 2,430 / 24 $10.03 / $0.100 43.22M
scoped Vanilla Claude Code Sonnet 5 No 100/100 18.0s 1,830s 551 / 6 $15.80 / $0.158 20.87M
scoped Vanilla Claude Code Opus 5 No 100/100 21.2s 2,117s 542 / 6 $18.45 / $0.185 13.47M
hint-free Vanilla Claude Code Haiku 4.5 No 0/100 14.9s 1,519s 677 / 7 $6.53 / $0.065 16.61M
hint-free Vanilla Claude Code Sonnet 5 No 0/100 14.2s 1,440s 395 / 4 $11.85 / $0.118 14.83M
hint-free Vanilla Claude Code Opus 5 No 94/100 23.3s 2,381s 501 / 5 $16.52 / $0.165 12.43M
hint-free pi + Xorq Haiku 4.5 No 0/100 84.0s 12,850s 2,227 / 21 $9.09 / $0.091 38.67M
hint-free pi + Xorq Haiku 4.5 Yes 100/100 21.3s 3,818s 457 / 4 $2.16 / $0.022 4.34M