Closes#230, with the answer it asked for rather than the test it imagined.
Reattachment.rank gives RUNNING the highest rank of all — "live work outranks a finished result because a running job is holding a foreground service" — and no test on either source set had ever produced one.
state
covered where
SUCCEEDED with a file
ReattachOnLaunchTest
SUCCEEDED, staged file gone
ReattachOnLaunchTest
ambiguous pair
ReattachOnLaunchTest
ENQUEUED
ReattachOnLaunchTest
CANCELLED
ReattachOnLaunchTest
RUNNING
nothing — ReattachmentTest ranks fabricated snapshots as a pure function
It is also the likeliest reattachment there is: the user starts a conversion, leaves, and comes back while it is still going.
Why the engine is a fake, and why that is not a weakening
The job has to still be running when the ViewModel is built, and every real conversion in this suite finishes in about a second — racing that is exactly what made the cancellation tests flaky enough to need retries (#240). A SoftwareTranscoder that blocks until released removes the race outright.
Nothing about reattachment depends on which engine is transcoding. Under test are the tag query, Reattachment.choose over live WorkManager state, and observe's mapping to Converting — identical whatever is doing the work.
Process death itself stays device-manual.docs/defect-audit.md D3/D13 already record that am kill refuses a process holding a foreground service. There is a more basic obstacle underneath that, which is the actual answer: instrumentation runs in the app's own process, so any route that really killed it would take the test runner with it and leave nothing to assert with. Observing a relaunch needs two instrumentation runs, which the runner does not provide.
So the closest observable analogue is what this adds: a fresh ViewModel, with no memory of the work, meeting a job that is genuinely mid-flight.
Also fixed
The teardown now resets ConversionDependencies. The suite runs without Android Test Orchestrator, so a BlockingTranscoder left in place would hang the next class that converts anything.
Verification — local API 34 emulator
tests=67 failures=0 errors=0 skipped=3
Mutation — make RUNNING unreattachable in Reattachment.rank:
Closes #230, with the answer it asked for rather than the test it imagined.
`Reattachment.rank` gives `RUNNING` the **highest rank of all** — *"live work outranks a finished result because a running job is holding a foreground service"* — and **no test on either source set had ever produced one**.
| state | covered where |
|---|---|
| SUCCEEDED with a file | `ReattachOnLaunchTest` |
| SUCCEEDED, staged file gone | `ReattachOnLaunchTest` |
| ambiguous pair | `ReattachOnLaunchTest` |
| ENQUEUED | `ReattachOnLaunchTest` |
| CANCELLED | `ReattachOnLaunchTest` |
| **RUNNING** | **nothing** — `ReattachmentTest` ranks fabricated snapshots as a pure function |
It is also the likeliest reattachment there is: the user starts a conversion, leaves, and comes back while it is still going.
## Why the engine is a fake, and why that is not a weakening
The job has to still be running when the ViewModel is built, and every real conversion in this suite finishes in about a second — racing that is exactly what made the cancellation tests flaky enough to need retries (#240). A `SoftwareTranscoder` that blocks until released removes the race outright.
Nothing about reattachment depends on which engine is transcoding. Under test are the tag query, `Reattachment.choose` over live WorkManager state, and `observe`'s mapping to `Converting` — identical whatever is doing the work.
## What #230 asked, answered
**Process death itself stays device-manual.** `docs/defect-audit.md` D3/D13 already record that `am kill` refuses a process holding a foreground service. There is a more basic obstacle underneath that, which is the actual answer: **instrumentation runs in the app's own process**, so any route that really killed it would take the test runner with it and leave nothing to assert with. Observing a relaunch needs two instrumentation runs, which the runner does not provide.
So the closest observable analogue is what this adds: a fresh ViewModel, with no memory of the work, meeting a job that is genuinely mid-flight.
## Also fixed
The teardown now resets `ConversionDependencies`. The suite runs without Android Test Orchestrator, so a `BlockingTranscoder` left in place would hang the next class that converts anything.
## Verification — local API 34 emulator
```
tests=67 failures=0 errors=0 skipped=3
```
Mutation — make `RUNNING` unreattachable in `Reattachment.rank`:
```
ReattachOnLaunchTest > reattachesToAConversionThatIsStillRunning FAILED
tests=67 failures=1
```
Fails this test **and nothing else** — which is also the evidence that the JVM ranking test was not already covering it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #230, with the answer it asked for rather than the test it imagined.
Reattachment.rankgivesRUNNINGthe highest rank of all — "live work outranks a finished result because a running job is holding a foreground service" — and no test on either source set had ever produced one.ReattachOnLaunchTestReattachOnLaunchTestReattachOnLaunchTestReattachOnLaunchTestReattachOnLaunchTestReattachmentTestranks fabricated snapshots as a pure functionIt is also the likeliest reattachment there is: the user starts a conversion, leaves, and comes back while it is still going.
Why the engine is a fake, and why that is not a weakening
The job has to still be running when the ViewModel is built, and every real conversion in this suite finishes in about a second — racing that is exactly what made the cancellation tests flaky enough to need retries (#240). A
SoftwareTranscoderthat blocks until released removes the race outright.Nothing about reattachment depends on which engine is transcoding. Under test are the tag query,
Reattachment.chooseover live WorkManager state, andobserve's mapping toConverting— identical whatever is doing the work.What #230 asked, answered
Process death itself stays device-manual.
docs/defect-audit.mdD3/D13 already record thatam killrefuses a process holding a foreground service. There is a more basic obstacle underneath that, which is the actual answer: instrumentation runs in the app's own process, so any route that really killed it would take the test runner with it and leave nothing to assert with. Observing a relaunch needs two instrumentation runs, which the runner does not provide.So the closest observable analogue is what this adds: a fresh ViewModel, with no memory of the work, meeting a job that is genuinely mid-flight.
Also fixed
The teardown now resets
ConversionDependencies. The suite runs without Android Test Orchestrator, so aBlockingTranscoderleft in place would hang the next class that converts anything.Verification — local API 34 emulator
Mutation — make
RUNNINGunreattachable inReattachment.rank:Fails this test and nothing else — which is also the evidence that the JVM ranking test was not already covering it.
🤖 Generated with Claude Code