Every test in ProgressNotificationTest drives the FFmpeg path. HardwareFallbackTest reaches runMedia3OrFallBack, but its RecordingHardwareTranscoder records the call and never invokes the callback it was handed.
So the two engines' progress wiring was one tested and one not — and the untested one is the default, since ConversionRouter sends everything it can to Media3. That is the same asymmetry argument CLAUDE.md records for including ContainerCapabilities:94.
Why it lives in this file
Progress plumbing is here, RecordingForegroundUpdater is here, and putting the hardware case beside the software ones makes the asymmetry visible rather than merely fixed. workerReporting gains an engine-preference parameter defaulted to FORCE_SOFTWARE, so no existing case changes.
AUTO with a real H.264 probe, because FORCE_SOFTWARE is exactly what keeps the other tests out of this branch — and because InputProbe() reports UNPARSEABLE, which PERMISSIVE.canDecode refuses, sending every job to FFmpeg with nothing saying why.
Acceptance: mutations run and restored
mutation
result
empty the hardware onProgress lambda
red
report a constant percent instead of the engine's
red
The second is why the assertion reads the percentage rather than just counting updates — publishProgress takes a name and a percent, and swapping the percent for a constant compiles.
Verification
testDebugUnitTest (full suite) + ktlintCheck + detekt + lintDebug — green, production tree clean.
Closes #196.
## The gap
`ConversionWorker.kt:208-210` is a **second** `onProgress` lambda at a second call site — the one handed to `engine.transcode` — and it reported `ci == 0`:
```kotlin
engine.transcode(inputUri, staged, request) { percent ->
publishProgress(displayName, percent)
}
```
Every test in `ProgressNotificationTest` drives the FFmpeg path. `HardwareFallbackTest` reaches `runMedia3OrFallBack`, but its `RecordingHardwareTranscoder` records the call and never invokes the callback it was handed.
So the two engines' progress wiring was one tested and one not — and **the untested one is the default**, since `ConversionRouter` sends everything it can to Media3. That is the same asymmetry argument `CLAUDE.md` records for including `ContainerCapabilities:94`.
## Why it lives in this file
Progress plumbing is here, `RecordingForegroundUpdater` is here, and putting the hardware case beside the software ones makes the asymmetry *visible* rather than merely fixed. `workerReporting` gains an engine-preference parameter defaulted to `FORCE_SOFTWARE`, so no existing case changes.
`AUTO` with a real H.264 probe, because `FORCE_SOFTWARE` is exactly what keeps the other tests out of this branch — and because `InputProbe()` reports `UNPARSEABLE`, which `PERMISSIVE.canDecode` refuses, sending every job to FFmpeg with nothing saying why.
## Acceptance: mutations run and restored
| mutation | result |
|---|---|
| empty the hardware `onProgress` lambda | **red** |
| report a constant percent instead of the engine's | **red** |
The second is why the assertion reads the percentage rather than just counting updates — `publishProgress` takes a name and a percent, and swapping the percent for a constant compiles.
## Verification
`testDebugUnitTest` (full suite) + `ktlintCheck` + `detekt` + `lintDebug` — green, production tree clean.
🤖 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 #196.
The gap
ConversionWorker.kt:208-210is a secondonProgresslambda at a second call site — the one handed toengine.transcode— and it reportedci == 0:Every test in
ProgressNotificationTestdrives the FFmpeg path.HardwareFallbackTestreachesrunMedia3OrFallBack, but itsRecordingHardwareTranscoderrecords the call and never invokes the callback it was handed.So the two engines' progress wiring was one tested and one not — and the untested one is the default, since
ConversionRoutersends everything it can to Media3. That is the same asymmetry argumentCLAUDE.mdrecords for includingContainerCapabilities:94.Why it lives in this file
Progress plumbing is here,
RecordingForegroundUpdateris here, and putting the hardware case beside the software ones makes the asymmetry visible rather than merely fixed.workerReportinggains an engine-preference parameter defaulted toFORCE_SOFTWARE, so no existing case changes.AUTOwith a real H.264 probe, becauseFORCE_SOFTWAREis exactly what keeps the other tests out of this branch — and becauseInputProbe()reportsUNPARSEABLE, whichPERMISSIVE.canDecoderefuses, sending every job to FFmpeg with nothing saying why.Acceptance: mutations run and restored
onProgresslambdaThe second is why the assertion reads the percentage rather than just counting updates —
publishProgresstakes a name and a percent, and swapping the percent for a constant compiles.Verification
testDebugUnitTest(full suite) +ktlintCheck+detekt+lintDebug— green, production tree clean.🤖 Generated with Claude Code