Blolabel
← Notes
analysis 8 min read

AgentHorizon builds failures by swapping instructions; 11 of phoneshell's 80 device checks pass a sibling task's finish

A judge that reads a trajectory can be fooled by a coherent finish to the wrong request. A grader that reads the phone can be too, and the swap test finds where without recording anything.

AgentHorizon, posted on 8 October 2026, tests judges of computer-use agents with a simple trick: record a task done right, then pair the recording with a closely related instruction it does not satisfy. The strongest judge, GPT-5.5 running inside OpenAI's Codex agent, reaches 80.9% balanced accuracy on the hard split. We ran the same swap over phoneshell's own 80 iPhone tasks, which are graded from device state rather than by a model. In 46 ordered task pairs, any finish that passes one task passes the other on check text alone. In 40 of those the instructions disagree. The 11 tasks involved passed 66 of 66 runs on 9 September 2026.

Abstract technical illustration of two parallel paths of light that cross and exchange endpoints over a dark grid

What AgentHorizon measured, and how the negatives were built

Xing Han Lù and eleven co-authors at ServiceNow Research, Mila and McGill (arXiv:2610.11050) collected 166 hours of human screen recordings on Windows, Linux and macOS. Annotators wrote two instructions that differ in one requirement and recorded a demonstration of each. Matched pairs are positive candidates. Crossed pairs, recording B judged against instruction A, are negatives by construction: "a very coherent execution, but it is paired with a request that the execution does not satisfy." After review the benchmark holds 1,373 items, 523 positive and 850 negative, with a median of 121 steps per item. Negatives are typed as Critical Mistake, Bad Side Effect or Misunderstanding.

Eleven judges were run directly and as coding agents inside five agent tools (Claude Code, Codex, Gemini CLI, OpenHands, OpenCode). Judges with similar balanced accuracy make opposite errors. Qwen 3.6 27B as a direct judge accepts 93.8% of valid work and rejects only 61.5% of swapped work. GPT-5.5 in Codex rejects 90.0% of swaps and accepts only 71.8% of valid runs. Given no instruction at all, Qwen 3.6 27B calls 98.9% of both classes successful, which is the paper's evidence that a finished-looking trajectory carries almost no signal by itself. Bad Side Effect had the lowest recall of the three types.

AgentHorizon (AH split): accept valid work vs reject a swapped request accepts valid (Pos %) rejects swapped (Neg %) 0 20 40 60 80 100 class accuracy, % 71.8 90 GPT-5.5 Codex 65.6 89.7 Gemini 3.1 Pro CLI 76.7 75.4 Opus 4.7 Claude Code 93.8 61.5 Qwen 3.6 27B direct 75.3 65.4 Qwen 3.6 27B OpenCode Source: Lu et al., arXiv:2610.11050, Table 2 (8 October 2026). Balanced accuracy is the mean of the two bars.

The same swap, applied to a grader that reads the phone

phoneshell's checks are assertions run against the phone after the agent stops: which app is in front, whether a text appears in the accessibility tree, whether a regular expression matches the screen, and for 20 probe tasks whether the answer contains a fixed word. Element matching is a case-insensitive substring over label, name, value and identifier (find_by_text in perception/tree.py). That makes implication between two tasks decidable from the YAML. Task A is implied by task B when every check in A is the same as a check in B, or, for element checks, is a substring of one. If A is implied by B, any phone state that passes B passes A. No recording is needed.

The swap test, from AgentHorizon to phoneshell's task files AgentHorizon (arXiv:2610.11050) instruction A + recording A = positive instruction B + recording B = positive instruction A + recording B = negative instruction B + recording A = negative 425 pairs, 850 negatives, all kept after review phoneshell, no recording needed checks(A) all implied by checks(B) so any end state that passes B passes A 46 ordered pairs among 80 tasks 40 of them ask for something B never does 11 tasks accept at least one sibling's finish multi.app_switchCalculator, then Safari, then back to Calculator check: foreground_app = com.apple.calculatorpassed by calculator.arithmetic (no Safari) settings.search.storageuse the search field, open the Storage page check: Settings in front, element "Storage"passed by settings.storage.reach ("iPhone Storage") notes.searchuse search to find the note "phoneshell benchmark" check: Notes in front, element "phoneshell benchmark"passed by notes.create_titled (makes a new note) Sources: arXiv:2610.11050 Sec. 3.2; phoneshell environments/*.yaml and bench/verify.py, read 9 October 2026.

Over the 80 files the test finds 46 ordered pairs. We read each pair's two instructions. In 6, B's finish does satisfy A's instruction: a settings.about.serial run does reach the page settings.about.reach asks for. In the other 40, it does not. Those are AgentHorizon negatives that phoneshell's grader would score as passes.

Task A (checks too weak)What A asks that the check cannot seeSibling finishes it accepts9 Sep passesAgentHorizon type (our judgement)Source
multi.three_appsCalculator, then Clock, then Settings20 (every Settings task)6 of 6Critical Mistakeenvironments/multi_three_apps.yaml
multi.app_switcha detour through Safari46 of 6Critical Mistakemulti_app_switch.yaml
multi.return_after_detoura detour through Notes46 of 6Critical Mistakemulti_return_after_detour.yaml
system.spotlight.find_applaunching from Spotlight46 of 6Misunderstandingsystem_spotlight_find_app.yaml
settings.search.wifi, .bluetooth, .storageusing the Settings search field1 each18 of 18Misunderstandingsettings_search_*.yaml
safari.read.headingsaying the heading26 of 6Critical Mistakesafari_read_heading.yaml
settings.about.serialsaying the model number16 of 6Critical Mistakesettings_about_serial.yaml
notes.searchfinding the note, not making one1 (notes.create_titled)6 of 6Bad Side Effectnotes_search.yaml
notes.create_titledmaking a new note1 (notes.search)6 of 6Critical Mistakenotes_create_titled.yaml
Total40 pairs; 35 path, 3 answer, 2 create or find66 of 66xv2.jsonl, 9 Sep 2026
40 swapped finishes phoneshell's checks would pass, by task sibling tasks whose passing end state also passes this task's checks multi.three_apps 20 (path) multi.app_switch 4 (path) multi.return_after_detour 4 (path) system.spotlight.find_app 4 (path) safari.read.heading 2 (answer) settings.about.serial 1 (answer) notes.search 1 (create for find) notes.create_titled 1 (find for create) settings.search.wifi 1 (path) settings.search.bluetooth 1 (path) settings.search.storage 1 (path) Source: our implication test over phoneshell environments/*.yaml (80 tasks), 9 October 2026. Script under Check it yourself.

Where the device stops being the witness

The 11 tasks are not failing. All 66 runs on 9 September passed, six models on an iPhone 14 Pro. Read the models' own summaries and they say the right things: all six settings.about.serial answers give MQ163LL/A, all six safari.read.heading answers say "Example Domain", every Spotlight run says it used Spotlight. The problem is where that evidence comes from. On these 11 tasks the part that separates the instruction from its sibling is confirmed only by the model's account, which is the source phoneshell exists to replace. On the same run, the models' summaries claimed success on 16 of 27 device-graded failures.

The three mechanisms are different. A path requirement (35 pairs) is invisible to any end-state check: Calculator in front looks the same with or without a trip through Safari. An answer requirement (3 pairs) is a missing check: phoneshell already has answer_contains and uses it on its 20 probe tasks, where the grader rejects swaps between the image word and the text word on the same page. A create-or-find pair (2) is a side effect: a model asked to search Notes can type a new note titled "phoneshell benchmark" and pass. Two of the six notes.search summaries say they found "multiple notes"; our guess, not checked on the phone, is that earlier create runs left them there.

Without the 11 tasks the 9 September run scores 256 of 283, 90.5%, against 322 of 349, 92.3%, with them. The 7 October note found 12 checks that pass on the opened app before any choice. The two lists measure different weaknesses, and we have not merged them.

What it means for anyone grading agents on phones

Check it yourself

# AgentHorizon: construction (Sec. 3.2), Table 1 counts, Table 2 judges
https://arxiv.org/abs/2610.11050
git clone https://github.com/ServiceNow/agenthorizon

# phoneshell: the implication test over the 80 task files (needs PyYAML)
python3 - <<'EOF'
import yaml, glob
T = {}
for f in glob.glob("environments/*.yaml"):
    d = yaml.safe_load(open(f))
    T[d["id"]] = [(c["kind"], str(c.get("text", c.get("value", ""))), bool(c.get("negate"))) for c in d["checks"]]
EL = ("element_exists", "element_exists_anywhere")
def implied(c, B):
    k, t, n = c
    for k2, t2, n2 in B:
        if n != n2: continue
        if n: 
            if k == k2 and t2.lower() in t.lower(): return True
            continue
        if (k, t) == (k2, t2): return True
        if k in EL and k2 in EL and t.lower() in t2.lower() and not (k == EL[0] and k2 == EL[1]): return True
        if k == k2 == "answer_contains" and t.lower() in t2.lower(): return True
    return False
P = [(a, b) for a in T for b in T if a != b and all(implied(c, T[b]) for c in T[a])]
print(len(T), len(P))          # 80 46
for a, b in sorted(P): print(a, "<=", b)
EOF

# the 9 September run
curl -sLO https://huggingface.co/datasets/blolabel/phoneshell-bench/resolve/main/results/xv2.jsonl
python3 -c "import json;R=[json.loads(l) for l in open('xv2.jsonl')];S={'multi.three_apps','multi.app_switch','multi.return_after_detour','system.spotlight.find_app','safari.read.heading','settings.about.serial','notes.search','notes.create_titled','settings.search.wifi','settings.search.bluetooth','settings.search.storage'};x=[r for r in R if r['task_id'] in S];print(sum(r['passed'] for r in x),len(x))"   # 66 66

The six pairs we marked compatible, and the AgentHorizon type in the table, are our reading of the instructions. Everything else follows from the files.

What would prove this wrong

Our claim is that 40 swapped finishes pass phoneshell's checks. It is wrong if any of them fails on the phone. The cheapest test is multi.app_switch graded on the end state of a calculator.arithmetic run, and notes.search graded after a fresh notes.create_titled run. By 31 December 2026 we expect phoneshell to grade the path for the 8 path tasks from its action log, and to add answer checks to safari.read.heading and settings.about.serial. Rerun after those changes, the implication test should report 6 pairs, all compatible. For AgentHorizon we expect, by 30 June 2027, no judge on the AH split above 90% balanced accuracy with both class accuracies above 85%.

Sources