stop waits for the app to exit, then TERM and KILL; launch --fresh #3
No reviewers
Labels
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
schaefera/ute2edriver!3
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/stop-verifies"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
lomiri-app-stopdoes nothing, and says nothing, for an app Lomiri no longer tracks. Soute2e stopleft yesterday's utStudyBible running, and a PSS check measured that one (utStudyBible #96, PR #111). Nowstopwaits for the app's process to exit (pidof). If it's still there, it sends TERM, then KILL, and it fails if the process survives KILL or the phone gives no answer.launch --freshstops a running app first. The example flows begin withstopso they always start a fresh app.Blast radius
Tier: trunk
Trunk paths touched:
src/ute2edriver/phone.py,src/ute2edriver/cli.pyTesting tier: standard
Gate / rollback: nothing is deployed (CLAUDE.md). Undo: revert this merge.
Proof
uv run ruff check .,uv run ty check: all checks passed.uv run python -m unittest discover -s tests: 28 tests OK, including 6 new ones inStopping: no kill when the app exits, TERM when Lomiri doesn't stop it, KILL and then an error if it survives,_gonegives up after the timeout, no answer from the phone is an error, and--freshstops before it launches.phone.py(plus only theSTOP_POLLname, so the patch decorator applies) and the new tests, the 5Stoppingtests of6cebd64all fail: 1 FAIL (the basestopnever pollspidof) and 4 ERROR (no_goneto patch, andlaunch()has nofresh). The no-answer test ofd266f51fails on the old_pidstoo (it returns[], sostopreturns).3cdadc4: nothing was running before.launchstarted pid 111974, andlaunch --freshgave a new pid, 112116.stopexited 0 after 9 s with no pid left:lomiri-app-stopalone hadn't ended the app within 5 s, so TERM did, which is the case this PR is for.stopwith nothing running exits 0.d266f51the same run gave pids 114092 → 114243, and stop took 8 s.6cebd64and again ond266f51:modules.tomlandsearch.tomlboth passed every step, starting with the newstopstep. The shots look right (module list searched for "Strong"). No screenshot from these runs was left on the phone; the only file in~/Pictures/Screenshotsis dated 2026-10-11, from before.d266f51:ci / testpassed.Review
Reviewer: fresh-context
code-reviewat high (review 307 on3cdadc4): 3 lows.6cebd64(example flows now stop first).d266f51(pidof's status is echoed; no answer raises). Its same-name match is answered in comment 2318.No re-review (lows only).
Review-Confidence: 70/100 (audit on
d266f51). −20 because the trunk fixd266f51to a low wasn't re-reviewed, −10 for two post-review fixes to lows. No missed defect; the auditor readd266f51and found none.Confidence by part
process.🤖 Generated with Claude Code
Review level: high. Commit:
3cdadc4250. Range: origin/main...HEAD.No high or medium findings. The phone E2E gate has not been run and is not counted. Two low findings are inline.
Finding outside the diff (low): src/ute2edriver/flow.py:103-106. A flow's
launchstep cannot request a fresh start, because onlyute2e launch --freshon the CLI can. README says--freshmeans "a check never measures an app left over from an earlier run". A flow withlaunch = trueagainst a stale untracked app still measures that app. A flow'sstop = truecan now raise RuntimeError mid-flow, which is intended.Files reviewed: README.md, CLAUDE.md, src/ute2edriver/phone.py, src/ute2edriver/cli.py, src/ute2edriver/config.py, src/ute2edriver/flow.py, src/ute2edriver/transport.py, src/ute2edriver/lock.py, tests/test_phone.py, examples/utstudybible/.ute2e.toml
@ -156,0 +162,4 @@if self.config.process and app == self.config.app_id:return self.config.processparts = app.split("_")return parts[1] if len(parts) == 3 else applow: the process name is guessed from the id's middle part. If the real executable differs (e.g. the click's desktop Exec is
utsb) andprocessis unset,pidoffinds nothing,_goneis true at once, andstoporlaunch --freshsilently does nothing for a stale untracked app. That is the bug this PR fixes. examples/utstudybible/.ute2e.toml does not setprocess, so the example gets no protection unless the middle part is the binary name. Setprocessthere, or verify the name.@ -156,0 +164,4 @@parts = app.split("_")return parts[1] if len(parts) == 3 else appdef _pids(self, process: str) -> list[str]:low:
pidof NAMEmatches any process with that name, including another user's or an unrelated one. Stop then sends TERM and KILL to all of them. If a stop runs while the adb connection drops,shell(check=False)returns an empty string and_gonereports success with no error.Answers to review 307 (3 lows):
pidof utstudybiblefound the app launched fromutstudybible.schaefera_utstudybible_0.0.1(pids 111974, then 112116 afterlaunch --fresh). An app whose binary is named differently setsprocess, as the README and config docstring say. Not changed.pidofmatches any process with that name; an adb drop reads as gone. UT phones have one user (phablet), and the name is the click's own binary, so an unrelated match is not a practical case. A dropped adb fails the next command loudly (the launch or tap after it). Not changed.6cebd64. Both example flows now begin withstop = true, and the README says astopbefore the firstlaunchgives a fresh app. That works now becausestopwaits until the old app is gone.WIP: stop waits for the app to exit, then TERM and KILL; launch --freshto stop waits for the app to exit, then TERM and KILL; launch --freshMerge gate on
d266f51(trunk, standard testing tier): approved.6cebd64. The adb-drop case of low 2 is fixed ind266f51. Comment 2318 answers the rest: low 1 with phone evidence, and the same-name-match part of low 2 as not a practical case on a single-user UT phone. I find those answers sound.pidofstatus echo handles every output case. A pid list with status 0 returns the pids. An empty list with status 1 returns no pids. No output, or any other status, raises. Tests cover each case. The example flows now start withstop, and the README says so. I found no defect with a concrete failure scenario.ci / test (pull_request)is green ond266f51.d266f51. No elevated, maximum, or AI-behavior gate is left unrun.