Blolabel
← Notes
analysis 8 min read

Action-conditioned bisimulation stops GUI memories merging look-alike screens; phoneshell's layout fingerprint mostly splits them, 60 keys for 29 screens

The paper's warning is about merging too eagerly. We checked phoneshell's screen memory against its own crawl records and found the opposite error dominates, with one family of exceptions that a second paper this week tells explorers to skip.

Merging GUI states by what their actions do, instead of by how they look, raised a frozen Qwen3-8B from 72.3% to 78.2% success on ten MiniWoB++ tasks. Merging by appearance scored 70.8%. That is the result of a paper posted on 30 September 2026. phoneshell's screen memory merges by appearance. On its own eleven crawls of 11 September, the appearance key mostly erred the other way: 29 titled screens received 60 keys, 14 of them for Settings. Only 4 of 38 repeated taps behaved differently, and every one of the four was a promotional or banner row.

Abstract technical illustration of a graph of nodes where several near-identical nodes sit apart and two dissimilar edges leave one node

What the two papers found

Hongbo Zhang, Liuyang Song, Quanquan Li, Daqian Yang, Yan Wen and Zhengtao Yao (arXiv:2609.38778, "Action Conditioned Bisimulation For GUI Agent Memory", 30 September 2026) start from a specific failure: GUIs are full of pages that look alike and answer the same click differently, two tabs of one widget or two rows of one menu. Their rule merges two states only when shared actions lead to agreeing outcomes and successor blocks. It replaces only the merge rule of an existing outcome-value memory, so their ablation ladder isolates it. Each rung changes one thing and keeps the model, prompt, call budget and exploration detours fixed.

System (MiniWoB++, 10 tasks, frozen Qwen3-8B, 400 paired cells)Success rateChange vs ReAct95% CIpSource
ReAct, no memory0.723---Table 1
Shortlist control (same detours, keeps nothing)0.723+0.000[+0.000, +0.000]1.000Table 1
Memory, successor-representation merge0.728+0.005[-0.007, +0.018]0.727Table 1
Memory, observation-similarity merge0.708-0.015[-0.033, +0.003]0.180Table 1
Memory, action-conditioned bisimulation0.782+0.060[+0.033, +0.090]0.001Table 1

It is one seed, one model and web widgets, and the authors say so. The second paper is SAGE (Bo Han, Qianyi Wang, Shuai Liu and colleagues, arXiv:2609.39547, 30 September 2026). It argues that self-collected priors drift with app updates, promotions, ads, A/B tests and personalisation. Across 176 tasks in 20 apps with paired old and new versions, only 44% kept identical trajectories after an update. Its explorer assigns advertisements and promotional cards zero interaction budget.

phoneshell's fingerprint on its own crawl records

memory.fingerprint in phoneshell hashes the bundle id with the type, label and 32-point grid cell of every Button, Tab, Switch, text field, Link and similar control, plus the count of those controls divided by four. The crawler (crawl.py, line 918) stores the same hash as each screen's structural key and uses (structural key, control key) to decide that a control has been tried. The agent's memory uses it to decide when a screen is known. After two visits, observe() stops sending the screenshot, and the hint tells the model what each control "did last time".

The crawler's manifests record every tap with the before and after screen. Eleven crawls with manifests ran on 11 September 2026, eight of Settings and three of the Talika app: 113 screens and 237 edges, of which 193 taps reached another screen, 41 changed nothing and 3 left the app. Within one crawl a control is tapped once per layout, so repeated taps come from different crawls of the same screen. That makes it a test of the merge rule across time. We grouped edges by (source fingerprint, control) and compared what happened. Behaviour means the destination app and title, or no-op, or left the app.

MeasureValueSource
Crawls with a manifest, 11 Sep 202611 (8 Settings, 3 Talika); 5 report iOS 18.4, 6 report iOS 26.6.1; WDA 16.12.4manifest.device
Screens, edges113 screens; 237 edges: 193 tap, 41 no-op, 3 crossingour count
Layout fingerprints vs titled screens60 fingerprints, 29 distinct (app, title) screens; 1 fingerprint under two titlesour count
Screen titled "Settings"14 fingerprints (9 on iOS 18.4 crawls, 5 on iOS 26.6.1)our count
(fingerprint, control) pairs tapped more than once38 pairs, 133 edgesour count
Same behaviour, same destination fingerprint26our count
Same behaviour, different destination fingerprint8 (Apple Account once, Talika tabs seven times)our count
Different behaviour4: storage-limit banner, Apple Music offer, Talika "Tap to discover how much" card, Talika headerour count
38 layout-and-control pairs tapped more than once in the 11 September crawls pairs 0 5 10 15 20 25 30 pairs 26 same screen, same fingerprint 8 same screen, new fingerprint 4 different behaviour Source: runtime/crawls/*/manifest.json on our rig, 11 crawls with manifests, 237 edges; our count.

The four disagreements are the paper's failure, but not in the paper's form. They are not two look-alike screens. They are one screen whose promotional row changed its effect between runs: the "You've reached your storage limit" banner left Settings in one crawl and stayed put in the next. "3 Months of Apple Music Included" opened "Services Included with Purchase" once and left the agent on a screen still titled Settings once. The Talika earnings card and header changed the screen in two taps of four and did nothing in the other two. An action-conditioned rule would refuse those merges. It would also learn nothing stable about them, which is SAGE's reason for not tapping them at all.

Two rules for "same screen", and where each one errs phoneshell memory.fingerprint (also the crawler's "structural" key) sha1( bundle id :: sorted[ type | label or id | round(x/32),round(y/32) ] for Button, Tab, Switch, Field, Link... :: count // 4 ) Only what the screen looks like. What its controls do never enters the key. Splits: same screen, new key Scroll the Settings list by one row: every row moves to another 32-pt cell "Settings": 14 fingerprints (9 on the iOS 18.4 crawls, 5 on iOS 26.6.1) 8 repeated taps reached the same screen under a different destination key cost: memory resets, screenshots resent Merges: same key, different effect "You've reached your storage limit" run 1: left the app; run 2: stayed in Settings "3 Months of Apple Music Included" run 1: opened a page; run 2: stayed on Settings Talika "Tap to discover how much" card 2 of 4 taps did nothing, 2 changed the screen cost: a confident hint that is wrong half the time Action-conditioned bisimulation (arXiv:2609.38778): merge s and t only if shared actions lead to agreeing outcomes and agreeing successor blocks. Scroll offsets would merge; the banners' two behaviours would not. Sources: phoneshell memory.py fingerprint(), crawl.py line 918; crawl manifests of 11 September 2026; Zhang et al., arXiv:2609.38778, Sec. 2.

The larger error is splitting. A one-row scroll moves every row into another 32-point cell, and a list that grows by four controls changes the count term. So the screen a person calls Settings carried 14 keys, and 8 of the 38 repeated pairs landed on the same screen under a new destination key. The bisimulation rule would merge those, since their actions agree. For phoneshell, a split costs a memory that starts again from zero visits, so the screenshot keeps being sent and the hint stays empty. The paper's gain came from a memory that pooled evidence across episodes. A key that fragments the same screen pools less.

Layout fingerprints per titled screen, same crawls fingerprints per screen 0 4 8 12 16 fingerprints 14 Settings 7 (untitled) 4 Explore 3 Line 2 each 8 screens 1 each 17 screens Source: as above. '8 screens' = General, Apple Intelligence & Siri, Camera, StandBy, Game Center, Apple Account, Talika, Studio.

What it means if your phone agent remembers screens

Check it yourself

# the key and how memory uses it
sed -n '/def fingerprint/,/hexdigest/p' phoneshell/memory.py
grep -n "min_visits_to_trust\|skip_image_on_known" phoneshell/actions.py phoneshell/config.py
grep -n "structural = fingerprint" phoneshell/crawl.py

# crawl your own phone, then group edges
bin/phoneshell collect Settings      # writes runtime/crawls/<stamp>-settings/manifest.json
# for each edge: key = (screens[frm].structural, edge.key)
#                behaviour = 'no-op' | 'left app' | (screens[to].bundle_id, screens[to].title)
# a pair disagrees when its edges carry more than one behaviour

Our eleven manifests are not published. They carry the phone owner's account name and network name on the Settings root. The counts above come from a 40-line script over screens and edges in each manifest, using the fields named in the comment. The papers' numbers are in Table 1 of arXiv:2609.38778 and Section 1 of arXiv:2609.39547.

What would prove this wrong

By 31 March 2027 we will rerun the Settings and Talika crawls on the same phone and compare them with the 11 September set. Two predictions. A scroll-invariant fingerprint (list rows keyed by label without the y cell) will give the Settings screen at most 4 keys instead of 14, without merging any (fingerprint, control) pair whose behaviours disagree. At least 3 of today's 4 disagreeing rows will still disagree or will have vanished, because they are promotions and account banners. If the scroll-invariant key creates new disagreements outside promotional rows, appearance was carrying information we have thrown away, and the bisimulation test belongs in the crawler rather than in a tidier key.

Sources