Part of #224 — the ConcatEngine half. The FFmpegEngine half landed in ad2a75d (#236). Between them, asking a real native session to stop is now covered on both FFmpeg paths. Media3Engine remains, so the ticket stays open.
Why the assertion is the session's return code
On the conversion side this was the better of two options. Here it is close to the only one: ConcatEngine does not delete its output on cancellation at all.
versus FFmpegEngine, which also deletes the partial. Whether that asymmetry is deliberate is a separate question from this test — flagged on the ticket — so this asserts what is true of both engines rather than depending on it.
Why the cancel triggers on RUNNING
ConcatWorker publishes no progress at all, so there is no callback to hang a cancel on even in principle. The conversion side had already measured the deeper reason: the committed clips are 2 s at 320×240 and the encode outruns a callback-triggered cancel (that attempt failed with state=COMPLETED rc=0).
The inputs are the mismatched pair on purpose, so ConcatPlanner chooses REENCODE. A stream copy of two short clips is close to instantaneous and would leave nothing to interrupt — and re-encoding is also the case where a user would actually reach for Cancel.
Verification — local API 34 emulator
run 1: tests=64 failures=0 errors=0 skipped=3
run 2: tests=64 failures=0 errors=0 skipped=3
run 3: tests=64 failures=0 errors=0 skipped=3
Mutation — invokeOnCancellation { }:
ConcatEngineTest > cancellingARunningJoinCancelsTheNativeSession FAILED
the native join session was not cancelled: state=COMPLETED rc=0
Part of #224 — the `ConcatEngine` half. The `FFmpegEngine` half landed in `ad2a75d` (#236). Between them, asking a **real native session** to stop is now covered on both FFmpeg paths. `Media3Engine` remains, so the ticket stays open.
## Why the assertion is the session's return code
On the conversion side this was the better of two options. Here it is close to the only one: **`ConcatEngine` does not delete its output on cancellation at all.**
```kotlin
// ConcatEngine.kt:80
cont.invokeOnCancellation { FFmpegKit.cancel(session.getSessionId()) }
```
versus `FFmpegEngine`, which also deletes the partial. Whether that asymmetry is deliberate is a separate question from this test — flagged on the ticket — so this asserts what is true of both engines rather than depending on it.
## Why the cancel triggers on `RUNNING`
`ConcatWorker` publishes no progress at all, so there is no callback to hang a cancel on even in principle. The conversion side had already measured the deeper reason: the committed clips are 2 s at 320×240 and the encode outruns a callback-triggered cancel (that attempt failed with `state=COMPLETED rc=0`).
The inputs are the **mismatched** pair on purpose, so `ConcatPlanner` chooses `REENCODE`. A stream copy of two short clips is close to instantaneous and would leave nothing to interrupt — and re-encoding is also the case where a user would actually reach for Cancel.
## Verification — local API 34 emulator
```
run 1: tests=64 failures=0 errors=0 skipped=3
run 2: tests=64 failures=0 errors=0 skipped=3
run 3: tests=64 failures=0 errors=0 skipped=3
```
Mutation — `invokeOnCancellation { }`:
```
ConcatEngineTest > cancellingARunningJoinCancelsTheNativeSession FAILED
the native join session was not cancelled: state=COMPLETED rc=0
```
Fails this test and nothing else.
🤖 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.
Part of #224 — the
ConcatEnginehalf. TheFFmpegEnginehalf landed inad2a75d(#236). Between them, asking a real native session to stop is now covered on both FFmpeg paths.Media3Engineremains, so the ticket stays open.Why the assertion is the session's return code
On the conversion side this was the better of two options. Here it is close to the only one:
ConcatEnginedoes not delete its output on cancellation at all.versus
FFmpegEngine, which also deletes the partial. Whether that asymmetry is deliberate is a separate question from this test — flagged on the ticket — so this asserts what is true of both engines rather than depending on it.Why the cancel triggers on
RUNNINGConcatWorkerpublishes no progress at all, so there is no callback to hang a cancel on even in principle. The conversion side had already measured the deeper reason: the committed clips are 2 s at 320×240 and the encode outruns a callback-triggered cancel (that attempt failed withstate=COMPLETED rc=0).The inputs are the mismatched pair on purpose, so
ConcatPlannerchoosesREENCODE. A stream copy of two short clips is close to instantaneous and would leave nothing to interrupt — and re-encoding is also the case where a user would actually reach for Cancel.Verification — local API 34 emulator
Mutation —
invokeOnCancellation { }:Fails this test and nothing else.
🤖 Generated with Claude Code