<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://afterxleep.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://afterxleep.github.io/" rel="alternate" type="text/html" /><updated>2026-09-01T16:11:47+00:00</updated><id>https://afterxleep.github.io/feed.xml</id><title type="html">AppleBench</title><subtitle>AppleBench asks whether an AI coding agent can take an Apple-development task from request to verified working result without a human stepping in. It hands the agent an isolated checkout of a real, intentionally broken Xcode project, then grades the final workspace itself with fresh xcodebuild, XCTest, XCUITest, and Simulator runtime checks.</subtitle><author><name>Daniel Bernal</name></author><entry><title type="html">Open the harness, keep the answers</title><link href="https://afterxleep.github.io/blog/2026/08/open-harness-private-answers/" rel="alternate" type="text/html" title="Open the harness, keep the answers" /><published>2026-08-27T20:00:00+00:00</published><updated>2026-08-27T20:00:00+00:00</updated><id>https://afterxleep.github.io/blog/2026/08/open-harness-private-answers</id><content type="html" xml:base="https://afterxleep.github.io/blog/2026/08/open-harness-private-answers/"><![CDATA[<p>There are two ways a benchmark stops measuring anything, and they get
conflated constantly.</p>

<p><strong>In-run cheating.</strong> An agent with web access finds the benchmark on GitHub
mid-evaluation and reads the fixture, or the expected diff, or the grader
assertions. This is the fast version. It happens in minutes, on the very
first run after publication.</p>

<p><strong>Pretraining contamination.</strong> Task text gets scraped, ends up in a training
corpus, and a future model has effectively memorized the answers. This is the
slow version. Months, not minutes, and silent. Nothing in the run
looks wrong.</p>

<p>These need different defenses, and people reach for the wrong one.</p>

<h2 id="closing-the-repository-only-solves-the-slow-one">Closing the repository only solves the slow one</h2>

<p>Keeping everything private does nothing about in-run cheating, because that
threat does not depend on the source being public. An agent that can search
the web can find <em>something</em>, and an agent that can reach the internet during
an evaluation is not being evaluated under controlled conditions at all.</p>

<p>The fix for the fast threat is sandboxing the run: no internet, no search,
standard toolchain only. AppleBench does this with a VM that default-denies
every network destination and mounts nothing of the host but the workspace,
and it would need to whether or not the repository were open.</p>

<p>Worth being precise about, because it is the kind of claim people repeat
without checking: that is a mode, not a default. Run the agent on your own
machine and its web tools are denied but its process is not confined, since
it still has a shell and <code class="language-plaintext highlighter-rouge">curl</code>. Every run records which of the two it was,
so a published number can be checked rather than taken on trust.</p>

<p>So the marginal value of going fully closed is lower than it feels. It buys
you the slow-leak defense and nothing else, at the cost of a benchmark
nobody can inspect, reproduce, or trust. Reviewers reasonably assume a closed
benchmark is hiding weak results.</p>

<h2 id="the-split">The split</h2>

<ul>
  <li><strong>Open:</strong> the harness. Grading engine, task schema, fixture-generation
tooling, the grader types, the isolation model, the tests that prove the
harness behaves. Everything you would need to audit whether a reported
number is honest.</li>
  <li><strong>Private:</strong> the gold set. 123 scoring tasks: prompts, fixtures, expected
outputs. Published scores come from these and only these.</li>
  <li><strong>Public and never scored:</strong> eight sample tasks with their fixtures, shipped
with the harness so a fresh clone runs end-to-end without touching gold, and
so anyone writing a task has a working one to copy.</li>
</ul>

<p>The two live in separate repositories and are joined by a single environment
variable, <code class="language-plaintext highlighter-rouge">APPLEBENCH_TASKSET</code>. Nothing is copied in either direction: prepared
fixtures, run artifacts and reports are all written inside the harness clone,
so a closed task set never lands in a public checkout and the harness never has
to be forked to run one.</p>

<p><code class="language-plaintext highlighter-rouge">./Scripts/check-task-set.sh</code> fails the build if a task set claims to be both
scored and open, if a task belongs to no suite at all, or if a referenced
fixture goes missing. The partition is enforced, not maintained by discipline.</p>

<h2 id="secrecy-is-a-delay-not-a-defense">Secrecy is a delay, not a defense</h2>

<p>Here is the part that matters more than the split.</p>

<p>A private set is not permanently private. It leaks through transcripts,
through screenshots, through the people who run it, through the reports that
describe what failed. Every published run leaks a little. The question is not
whether the gold set survives. It is what happens when it does not.</p>

<p>The answer has to be rotation. AppleBench fixtures are XcodeGen manifests with
templated defects, so the private set can be re-seeded: new bundle
identifiers, new defect placements, regenerated projects. A leaked transcript
from last quarter stops being a valid key.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">APPLEBENCH_TASKSET</span><span class="o">=</span>/path/to/scoring-set ./Scripts/rotate-private-set.sh 2026-q4
</code></pre></div></div>

<p>Closed answers buy time. Rotation is what keeps a benchmark alive past its
first year. Anyone building one of these should plan for the second thing on
day one, because the first thing has an expiry date whether or not you
acknowledge it.</p>]]></content><author><name>Daniel Bernal</name></author><category term="contamination" /><category term="design" /><summary type="html"><![CDATA[There are two ways a benchmark stops measuring anything, and they get conflated constantly.]]></summary></entry><entry><title type="html">Why AppleBench exists</title><link href="https://afterxleep.github.io/blog/2026/08/why-applebench/" rel="alternate" type="text/html" title="Why AppleBench exists" /><published>2026-08-27T14:00:00+00:00</published><updated>2026-08-27T14:00:00+00:00</updated><id>https://afterxleep.github.io/blog/2026/08/why-applebench</id><content type="html" xml:base="https://afterxleep.github.io/blog/2026/08/why-applebench/"><![CDATA[<p>Ask most coding benchmarks what they measure and the honest answer is: can the
model produce a patch that makes a test go green. That is a real skill and it
is worth measuring. It is also not what Apple development is.</p>

<p>Apple development is an execution loop:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>understand → edit → build → diagnose → run → inspect → interact → test → verify
</code></pre></div></div>

<p>The edit is one step out of nine. The other eight involve a toolchain that
gives you feedback only when you run it, in formats you have to know how to
read, with failure modes that have nothing to do with the language. A model
that writes flawless Swift and cannot get <code class="language-plaintext highlighter-rouge">xcodebuild</code> to target a simulator
is not useful to an iOS engineer.</p>

<h2 id="what-done-has-to-mean">What “done” has to mean</h2>

<p>The design constraint that shaped everything else: <strong>a passing result has to
mean the app actually works</strong>, not that the diff looked right.</p>

<p>So AppleBench grades the workspace, not the agent’s account of it. After the
agent exits, the harness runs a fresh <code class="language-plaintext highlighter-rouge">xcodebuild</code> with clean derived data,
runs the tests, installs the product on a simulator, launches it, and watches
it survive. The agent’s own successful build counts for nothing. If the agent
built it and the grader cannot, the grader wins.</p>

<p>That inversion is the whole product. Everything else in the harness exists to
keep it honest:</p>

<ul>
  <li>Grader configuration is not written anywhere near the workspace until the
agent has already exited. It cannot read the assertions and write to them.</li>
  <li>Prompts state the symptom, never the cause and never the file. The
diagnosis is the task.</li>
  <li>Project configuration is graded by what it <em>resolves to</em>: build settings
from <code class="language-plaintext highlighter-rouge">xcodebuild -showBuildSettings -json</code>, <code class="language-plaintext highlighter-rouge">Info.plist</code> keys read out of
the built product. A plausible line pasted into <code class="language-plaintext highlighter-rouge">project.pbxproj</code> that does
not take effect cannot pass.</li>
</ul>

<h2 id="what-got-cut">What got cut</h2>

<p>The first version had tasks about Swift generics, actor isolation, and data
races. They came out.</p>

<p>Not because they are easy. Some were the hardest tasks in the set,
but because other benchmarks already cover language-level Swift, and overlap
buys nothing. If a model’s <code class="language-plaintext highlighter-rouge">Sendable</code> reasoning is already measured somewhere
credible, measuring it again here adds noise and no signal.</p>

<p>What nobody else measures is whether an agent can operate the toolchain. So
that is what is left: build failures that are SDK-specific, project
configuration, simulator interaction, XCUITests, Apple frameworks, and raw
<code class="language-plaintext highlighter-rouge">xcodebuild</code>/<code class="language-plaintext highlighter-rouge">simctl</code> operational loops with every wrapper CLI stripped off
the path.</p>

<h2 id="the-uncomfortable-part">The uncomfortable part</h2>

<p>Building a benchmark means eventually publishing a number, and a number is
much easier to trust than it should be.</p>

<p>The first full run produced 33.7%. It could just as defensibly have been
26.5%. Same artifacts, same model, same day, different rule about which
attempt counts when a task was re-run after an infrastructure failure. Neither
number is wrong. Only one of them is meaningful without the sentence that
explains it.</p>

<p>That is why every published run here states its suite, its model, its
environment, and its selection rule, and why the harness reports a grader that
<em>failed</em> and a grader that <em>could not run</em> as two different outcomes. A
benchmark that quietly collapses those is measuring your CI stability and
calling it model capability.</p>]]></content><author><name>Daniel Bernal</name></author><category term="benchmark" /><category term="design" /><summary type="html"><![CDATA[Ask most coding benchmarks what they measure and the honest answer is: can the model produce a patch that makes a test go green. That is a real skill and it is worth measuring. It is also not what Apple development is.]]></summary></entry></feed>