Skip to content

Commit d017a38

Browse files
Staacksclaude
andcommitted
lab: the iOS connect path verifies what it started, and both Android branches explain themselves
iOS: connect_phone launched the app with its own copy of the devicectl line and returned success if the LAUNCH returned 0 - which says the app started and nothing more, so a phone that never loaded an experiment was reported as connected and failed later on "no data". It now goes through device.py's launcher (which also carries the fallback for phones devicectl cannot talk to) and then waits for the remote API, exactly as Android does. The failure names where to look: the app's own "-phyphoxBleConnect: no device advertising as X turned up within 60 s" line in the device console, the Bluetooth permission, and whether the installed build has the seam. Worth saying in the message because -phyphoxBleConnect opens NO dialog by design - the app scans headlessly, so "nothing visible happened" is not evidence of anything. Android: the two failure branches had drifted. The hold branch reports the first exception and keeps the whole output; the API branch still tailed 300 characters, which is why the single failure of today's last pass came back as "...within the connect timeout: de.rwth_aachen.phyphox.BleCompatConnectTest:" and nothing else. Both go through one explainer now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 0d78aba commit d017a38

1 file changed

Lines changed: 57 additions & 24 deletions

File tree

tools/lab/ble.py

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,33 @@ def _await_hold(dev, timeout):
579579
TRANSFER_FILE = "files/temp_bt/bt.phyphox"
580580

581581

582+
def _instrumentation_cause(dev, scenario, args, out):
583+
"""The first exception with the lines under it, plus the whole output
584+
kept as evidence. Returns a string to append to a finding.
585+
586+
Shared by both failure branches on purpose. The hold branch learned
587+
this on 2026-08-28 (eight failures reported as JUnit's header line
588+
with the cause thrown away) and the API branch did not, so the one
589+
remaining failure of that day's last pass came back as
590+
"...within the connect timeout: de.rwth_aachen.phyphox.\
591+
BleCompatConnectTest:" - the same defect, one branch over.
592+
"""
593+
lines = [ln.strip() for ln in (out or "").splitlines() if ln.strip()]
594+
at = next((i for i, ln in enumerate(lines)
595+
if "Exception" in ln or "Error" in ln), None)
596+
said = " | ".join(lines[at:at + 3])[:400] if at is not None else ""
597+
try:
598+
log = evidence_path(dev, args,
599+
f"{scenario['library']}-{scenario['example']}"
600+
f"-connect-failed.txt")
601+
with open(log, "w") as f:
602+
f.write(out or "")
603+
said += f" [full output: {os.path.relpath(log, ROOT)}]"
604+
except OSError:
605+
pass
606+
return said or (out or "")[-300:]
607+
608+
582609
def connect_phone(dev, scenario, args, advertised=None):
583610
"""Run the platform's scan-and-connect test on the phone. The UI flow
584611
(scan, pick the device, accept its experiment) has no remote-API
@@ -658,39 +685,45 @@ def connect_phone(dev, scenario, args, advertised=None):
658685
# 2026-08-28 reported eight failures as "Error in
659686
# theDeviceOffersItsExperimentAndItLoads(...):" and nothing
660687
# else, which is why the whole output is now kept as well.
661-
lines = [ln.strip() for ln in out.splitlines() if ln.strip()]
662-
at = next((i for i, ln in enumerate(lines)
663-
if "Exception" in ln or "Error" in ln), None)
664-
first = " | ".join(lines[at:at + 3])[:400] if at is not None else ""
665-
try:
666-
log = evidence_path(
667-
dev, args,
668-
f"{scenario['library']}-{scenario['example']}"
669-
f"-connect-failed.txt")
670-
with open(log, "w") as f:
671-
f.write(out)
672-
first += f" [full output: {os.path.relpath(log, ROOT)}]"
673-
except OSError:
674-
pass
675688
return False, ("the connect test never reached its hold: "
676-
+ (first or out[-300:])), None
689+
+ _instrumentation_cause(dev, scenario, args,
690+
out)), None
677691
if wait_api(dev.base, args.connect_timeout) is None:
678692
proc.kill()
679693
# Killing the local adb does NOT stop the instrumentation on
680694
# the phone; without this it keeps the app alive and the next
681695
# scenario talks to it.
682696
sh(dev.adb + ["shell", "am", "force-stop", ANDROID_PACKAGE])
683-
out = (proc.communicate()[0] or "")[-300:]
697+
out = proc.communicate()[0] or ""
684698
return False, ("the phone did not reach a loaded experiment "
685-
"within the connect timeout: " + out), None
699+
"within the connect timeout: "
700+
+ _instrumentation_cause(dev, scenario, args,
701+
out)), None
686702
return True, "connected", proc
687-
r = sh(["xcrun", "devicectl", "device", "process", "launch",
688-
"--terminate-existing", "--device", dev.udid, "--",
689-
"de.rwth-aachen.physics.phyphox",
690-
"-phyphoxBleConnect", name, "-phyphoxRemote",
691-
"-phyphoxRemotePort", "80", "-phyphoxAutoConfirm"],
692-
timeout=args.connect_timeout)
693-
return r.returncode == 0, (r.stderr or r.stdout or "")[-300:], None
703+
# device.py's own launcher rather than a second copy of the devicectl
704+
# line: it adds -phyphoxRemote, the port and -phyphoxAutoConfirm, and
705+
# it carries the fallback for phones devicectl cannot talk to (iOS 17+
706+
# only, and the lab's iPhone 8 tops out at 16).
707+
if not dev._launch_args(["-phyphoxBleConnect", name]):
708+
return False, f"the app did not launch: {dev.last_error}", None
709+
# A launch that returns 0 says the app STARTED, nothing more. The
710+
# first iOS attempt reported every scenario as connected and then
711+
# failed on "no data", which describes the symptom and hides the
712+
# cause. -phyphoxBleConnect opens no dialog by design - the app scans
713+
# headlessly and the experiment page appearing is the only visible
714+
# sign - so the remote API coming up is what "connected" means here,
715+
# exactly as on Android.
716+
if wait_api(dev.base, args.connect_timeout) is None:
717+
return False, (
718+
f"the app launched but no experiment was loaded within "
719+
f"{args.connect_timeout:.0f} s, so nothing served the remote "
720+
f"API. The app logs '-phyphoxBleConnect: no device advertising "
721+
f"as {name} turned up within 60 s' to the device console when "
722+
f"its scan finds nothing - check there first, then that "
723+
f"Bluetooth is permitted for phyphox in Settings (a system "
724+
f"prompt, which -phyphoxAutoConfirm deliberately does not "
725+
f"touch) and that this build has the seam at all"), None
726+
return True, "connected", None
694727

695728

696729
def release_phone(dev, handle, args):

0 commit comments

Comments
 (0)