Blolabel
← Notes
analysis 6 min read

Rollback-Induced Reflection rolls an agent back up to 1.3 times a task; phoneshell has no checkpoint to roll back to

A method published 16 September 2026 restores a long-horizon agent to an earlier state and keeps what the failed attempt learned. phoneshell's only answer to a task that goes wrong is to let it run out of steps and call that a failure, with nothing kept and nowhere to go back to.

Rollback-Induced Reflection (RIR), submitted to arXiv on 16 September 2026 by Yi Yu, Liuyi Yao, Yaliang Li, Enshu Wang and Libing Wu, beats the strongest baseline on three long-horizon agent benchmarks by 3.09 to 6.57 percentage points, averaged per backbone model, by restoring execution to a chosen earlier state when a trajectory goes wrong and carrying forward what that failed attempt learned. phoneshell (github.com/Blomega/phoneshell), the harness that runs this site's benchmark, has no equivalent of any kind. Its only reaction to an agent that cannot finish a task is error_max_turns: a hard stop at a fixed step count, scored as an outright failure, with no saved state and no path back to one.

Abstract technical illustration on a dark grid: a glowing path with several marked checkpoint nodes behind the leading edge, one checkpoint lit up and a faint ghost trail looping back to it, beside a second plain straight line that simply stops dead at a wall with no markers on it at all, cool blues with one amber accent

What RIR actually decides, and when

The paper frames recovery as a "rollback-boundary control problem": three decisions, not one. When to intervene. Where to resume. What to keep. Most prior methods pick one side of this and lose on the other, the authors argue: fixing the context without repairing the environment's actual state leaves the agent reasoning about a world that no longer matches what it sees, while restoring an earlier state the plain way throws away everything the failed attempt was worth. RIR's trigger condition is explicit in the paper's own notation: a review happens when the agent calls a rollback tool, or when a review horizon L_t has elapsed since the last review, whichever comes first (ReviewEvent_t = I[a_t = rollback] ∨ I[t − t_rev ≥ L_t]), with a default horizon of 4 to 8 steps. Calling the tool does not roll anything back by itself; it only requests a review. An LLM reviewer then returns a verdict, and a rollback executes only if that verdict is "Rollback" and the method's own rollback budget for the episode has not run out.

Where it resumes is the second decision. Rollback depth is defined as k = t − r, the distance from the current step back to the restore point r. Rather than always jumping back a fixed number of steps, RIR's restore rule looks for the latest checkpoint inside a localized interval that removes the condition that caused the failure, so a shallow mistake gets a shallow rollback. What survives the rollback is the third decision: not nothing, and not the full trajectory either. A "structured reflection memory" distilled from the abandoned attempt is carried forward to guide the next try, which is the paper's actual innovation over plain state-restoration: on ScienceWorld, RIR executes an average of about 0.9 to 1.3 rollbacks per task, each one keeping a piece of what the discarded path learned rather than erasing it.

Rollback-Induced Reflection: one review cycle ReviewEvent trigger agent calls rollback tool, OR 4-8 steps since last review (default horizon L=4,8) LLM reviewer verdict Continue: agent proceeds, no state change Rollback: see below budget check rollback executes only if the episode's rollback budget is not exhausted else: verdict is ignored restore to checkpoint r depth k = t − r, the latest checkpoint that removes the failure condition structured reflection memory distilled from the abandoned attempt, carried into the next try ~0.9-1.3 rollbacks/task, ScienceWorld next attempt resumes from r with the reflection memory available

phoneshell's only exit is down

phoneshell's step budget is a single config field: max_steps: int = 60 in phoneshell/config.py, labelled in the code's own comment as "Hard cap on agent steps per task, and on money." Each task file can set a lower per-task ceiling through Task.max_steps in phoneshell/bench/schema.py, which defaults to 25. runner.py hands that number straight to the model under test, either as max_steps on the OpenRouter path or as --max-turns on the Claude Code CLI path. There is no reviewer, no horizon, and no budget for a second chance: once the count is reached, the CLI exits 0 with {"subtype":"error_max_turns","is_error":true} and, per the code's own comment, "usually no result text." runner.py treats that exactly like a wall-clock timeout, setting timed_out = True, and the comment beside that line states the policy outright: "A model that runs out of time has FAILED the task... scoring it from whatever the phone happens to look like afterwards credits work it never finished." Nothing is salvaged. No earlier screen state is kept to return to, because none was ever recorded as a checkpoint in the first place; the only persisted record of the attempt is the row in results.json, which keeps the outcome (passed, turns, seconds, checks) and nothing about what the agent tried along the way.

DimensionRollback-Induced ReflectionphoneshellSource
What a budget overrun meansa reviewable event, not an automatic failurean automatic failure (error_max_turns → timed_out)arXiv:2609.18304 §3; runner.py
State kept from a bad attemptstructured reflection memory, distillednone; only the pass/fail row survivesarXiv:2609.18304 §3; results.json schema
Where execution resumeslatest checkpoint that removes the failure condition (depth k = t−r)nowhere; the task endsarXiv:2609.18304 §3; bench/runner.py
Decision authoritya second LLM call (the reviewer) judges Continue vs Rollbacknone; the step count alone decidesarXiv:2609.18304 §3; config.py max_steps
Typical intervention rate~0.9-1.3 rollbacks per task (ScienceWorld)not applicable, no intervention existsarXiv:2609.18304 §4

The gain is real, but it is not free, and it is not mobile

RIR's reported edge holds across three different model backbones on three benchmarks that have nothing to do with phones: ALFWorld (embodied household interaction), ScienceWorld (text-based scientific experimentation) and GAIA (open-domain tool use). Averaged per backbone, RIR beats the strongest baseline by 3.09 points on Qwen3-14B, 6.57 points on DeepSeek-V3, and 3.04 points on Qwen3.8-27B. Those are real, model-specific, benchmark-specific gains, not a universal multiplier, and none of the three backbones are the GUI-grounded models phoneshell evaluates (the OpenRouter and Claude Code CLI paths it drives today). Nothing in the paper claims a GUI or mobile result; it is cross-listed only to cs.CL and cs.RO.

RIR's gain over the strongest baseline, averaged per backbone (pp) 0 2 4 6 8 +3.09 Qwen3-14B +6.57 DeepSeek-V3 +3.04 Qwen3.8-27B Source: arXiv:2609.18304, abstract and Section 4, read 15 October 2026. Benchmarks: ALFWorld, ScienceWorld, GAIA.

What it means for anyone grading a phone agent

Check it yourself

# phoneshell's step budget and its only failure path
grep -n "max_steps: int = 60" phoneshell/config.py
grep -n "max_steps: int = 25" phoneshell/bench/schema.py
grep -n "max-turns\|error_max_turns\|timed_out = True" phoneshell/bench/runner.py -A2 -B2

# confirm there is no rollback, checkpoint or restore concept anywhere in the codebase
grep -rniE "rollback|checkpoint|restore_state" phoneshell/ || echo "no matches"

# RIR's own trigger rule and reported numbers
curl -s https://arxiv.org/abs/2609.18304 | grep -i "rollback\|percentage point"
# full method and Table 1: https://arxiv.org/html/2609.18304v3

What would prove this wrong

We claim phoneshell has no mechanism that preserves any state from a failed attempt or resumes execution from one. That is wrong if a future version of bench/runner.py or actions.py retains a Snapshot across actions, or if any task file gains a field for a partial-credit or retry state. We also claim RIR's reported gains, while real on ALFWorld, ScienceWorld and GAIA, have not been shown to transfer to GUI or mobile agents. That claim is falsified the moment RIR, or a method built on its rollback-boundary framing, is evaluated on a mobile GUI benchmark (iOSWorld, AndroidWorld, DAC-Bench or phoneshell's own 80 tasks) and the result is published. We will treat either event, checked by 31 March 2027, as grounds to revisit this comparison.

Sources