Documentation only — no Kotlin, Gradle or shell file is touched.
What this is
The wave-4 coverage read on main @ 54ca2dd (92.8% line, 81.3% branch, 584 tests in 87 classes — the committed figures, re-verified counter for counter against the report on disk rather than quoted).
It produced three things. The twelve test tickets are #192–#203 and the four deferred candidates are #204; this PR is the third part — the five findings a test would not fix, plus one correction to how the next read should be done.
The correction, which is the reusable half
Wave 3 filtered candidates on mi > 0, and CLAUDE.md recommended it. It fails in both directions:
Over-reports on Compose.JoinScreen.kt:222 reads mi=10 — and also ci=38, and JoinStateAffordancesTest already clicks that Save button and asserts save:joined.mp4. The missed instructions are the synthesized $changed/$dirty recomposition-skip path — the same codegen this repo already knew inflated the branch count, showing up in the instruction count too. Every onClick lambda flagged that way turned out covered at method level.
Under-reports on the case that mattered more. Both ViewModels' cancel() miss no line, so no line-level filter can see them — yet only the null arm of activeWorkId?.let(workManager::cancelWorkById) had ever been entered, and nothing in 584 tests connected the Cancel button to WorkManager. That is #192.
Use both: ci == 0 (JaCoCo's own missed-line definition, no judgement needed) plus ci > 0 && mb > 0 at method level.
The five findings
F6
Four more unreachable arms, each traced to the upstream guard that makes it so. One (ConversionRouter:214-217) carries a KDoc describing a hazard :117 already removed — F2's shape, and a one-line fix.
F7
probeWithExtractor's catch is unreachable for the same measured reason probeForConcat's is. The measurement was on record for one site and not the other, three lines apart in the same file.
F8
Three more dead members and six unused defaults.
F9
Both getForegroundInfo overrides are dead — getForegroundInfoAsync is called only for expedited work, and grep setExpedited returns nothing. Sharpens #88's close rather than reopening it.
F10
Three arms that are reachable and still cannot be made to bite. Recorded because all three were picked up as candidates and put down again.
Six of the ten findings are now "no action" or "not a test gap". That shape is the honest summary of what is left: arms nothing can reach, members nothing calls, and arms a test can reach but not pin — and a coverage number tells none of them apart.
One close qualified, not overturned
#86 and #133 ruled AndroidDeviceCodecs.probe() out through ShadowMediaCodecList, because MediaCodecInfoBuilder cannot set isAlias or canonicalName. A pure seam does not have that constraint and #133 did not evaluate one — so #194 is a different mechanism, not a third run of the same spike. Both this document and CLAUDE.md now say so, since #133's text currently reads as a close on the whole question.
Its argument is not coverage, either: the runCatching fallback logs "assuming permissive" while returning empty sets, which makes canEncode and canDecode answer no for everything.
Verification
Documentation-only, so the code gates have nothing to act on. What was checked instead is every factual claim the entries make — grep setExpedited (empty), ConcatWorker never reading Result.output, all three Transcoders call sites passing every argument, JobSnapshots.kt passing all seven fields, and each unreachable arm traced to its guard. Line citations were re-read rather than carried over.
Documentation only — no Kotlin, Gradle or shell file is touched.
## What this is
The wave-4 coverage read on `main` @ `54ca2dd` (**92.8% line, 81.3% branch, 584 tests in 87 classes** — the committed figures, re-verified counter for counter against the report on disk rather than quoted).
It produced three things. The twelve test tickets are **#192–#203** and the four deferred candidates are **#204**; this PR is the third part — the five findings a test would not fix, plus one correction to how the next read should be done.
## The correction, which is the reusable half
Wave 3 filtered candidates on `mi > 0`, and `CLAUDE.md` recommended it. It fails in both directions:
- **Over-reports on Compose.** `JoinScreen.kt:222` reads `mi=10` — and also `ci=38`, and `JoinStateAffordancesTest` already clicks that Save button and asserts `save:joined.mp4`. The missed instructions are the synthesized `$changed`/`$dirty` recomposition-skip path — the same codegen this repo already knew inflated the *branch* count, showing up in the instruction count too. Every `onClick` lambda flagged that way turned out covered at method level.
- **Under-reports on the case that mattered more.** Both ViewModels' `cancel()` miss no line, so no line-level filter can see them — yet only the null arm of `activeWorkId?.let(workManager::cancelWorkById)` had ever been entered, and nothing in 584 tests connected the Cancel button to WorkManager. That is #192.
Use both: `ci == 0` (JaCoCo's own missed-line definition, no judgement needed) plus `ci > 0 && mb > 0` at method level.
## The five findings
| | |
|---|---|
| **F6** | Four more unreachable arms, each traced to the upstream guard that makes it so. One (`ConversionRouter:214-217`) carries a KDoc describing a hazard `:117` already removed — F2's shape, and a one-line fix. |
| **F7** | `probeWithExtractor`'s catch is unreachable for the same measured reason `probeForConcat`'s is. The measurement was on record for one site and not the other, three lines apart in the same file. |
| **F8** | Three more dead members and six unused defaults. |
| **F9** | Both `getForegroundInfo` overrides are dead — `getForegroundInfoAsync` is called only for expedited work, and `grep setExpedited` returns nothing. **Sharpens #88's close rather than reopening it.** |
| **F10** | Three arms that *are* reachable and still cannot be made to bite. Recorded because all three were picked up as candidates and put down again. |
Six of the ten findings are now "no action" or "not a test gap". That shape is the honest summary of what is left: arms nothing can reach, members nothing calls, and arms a test can reach but not pin — and a coverage number tells none of them apart.
## One close qualified, not overturned
#86 and #133 ruled `AndroidDeviceCodecs.probe()` out **through `ShadowMediaCodecList`**, because `MediaCodecInfoBuilder` cannot set `isAlias` or `canonicalName`. A pure seam does not have that constraint and #133 did not evaluate one — so #194 is a different mechanism, not a third run of the same spike. Both this document and `CLAUDE.md` now say so, since #133's text currently reads as a close on the whole question.
Its argument is not coverage, either: the `runCatching` fallback logs *"assuming permissive"* while returning empty sets, which makes `canEncode` and `canDecode` answer **no** for everything.
## Verification
Documentation-only, so the code gates have nothing to act on. What was checked instead is every factual claim the entries make — `grep setExpedited` (empty), `ConcatWorker` never reading `Result.output`, all three `Transcoders` call sites passing every argument, `JobSnapshots.kt` passing all seven fields, and each unreachable arm traced to its guard. Line citations were re-read rather than carried over.
🤖 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.
Documentation only — no Kotlin, Gradle or shell file is touched.
What this is
The wave-4 coverage read on
main@54ca2dd(92.8% line, 81.3% branch, 584 tests in 87 classes — the committed figures, re-verified counter for counter against the report on disk rather than quoted).It produced three things. The twelve test tickets are #192–#203 and the four deferred candidates are #204; this PR is the third part — the five findings a test would not fix, plus one correction to how the next read should be done.
The correction, which is the reusable half
Wave 3 filtered candidates on
mi > 0, andCLAUDE.mdrecommended it. It fails in both directions:JoinScreen.kt:222readsmi=10— and alsoci=38, andJoinStateAffordancesTestalready clicks that Save button and assertssave:joined.mp4. The missed instructions are the synthesized$changed/$dirtyrecomposition-skip path — the same codegen this repo already knew inflated the branch count, showing up in the instruction count too. EveryonClicklambda flagged that way turned out covered at method level.cancel()miss no line, so no line-level filter can see them — yet only the null arm ofactiveWorkId?.let(workManager::cancelWorkById)had ever been entered, and nothing in 584 tests connected the Cancel button to WorkManager. That is #192.Use both:
ci == 0(JaCoCo's own missed-line definition, no judgement needed) plusci > 0 && mb > 0at method level.The five findings
ConversionRouter:214-217) carries a KDoc describing a hazard:117already removed — F2's shape, and a one-line fix.probeWithExtractor's catch is unreachable for the same measured reasonprobeForConcat's is. The measurement was on record for one site and not the other, three lines apart in the same file.getForegroundInfooverrides are dead —getForegroundInfoAsyncis called only for expedited work, andgrep setExpeditedreturns nothing. Sharpens #88's close rather than reopening it.Six of the ten findings are now "no action" or "not a test gap". That shape is the honest summary of what is left: arms nothing can reach, members nothing calls, and arms a test can reach but not pin — and a coverage number tells none of them apart.
One close qualified, not overturned
#86 and #133 ruled
AndroidDeviceCodecs.probe()out throughShadowMediaCodecList, becauseMediaCodecInfoBuildercannot setisAliasorcanonicalName. A pure seam does not have that constraint and #133 did not evaluate one — so #194 is a different mechanism, not a third run of the same spike. Both this document andCLAUDE.mdnow say so, since #133's text currently reads as a close on the whole question.Its argument is not coverage, either: the
runCatchingfallback logs "assuming permissive" while returning empty sets, which makescanEncodeandcanDecodeanswer no for everything.Verification
Documentation-only, so the code gates have nothing to act on. What was checked instead is every factual claim the entries make —
grep setExpedited(empty),ConcatWorkernever readingResult.output, all threeTranscoderscall sites passing every argument,JobSnapshots.ktpassing all seven fields, and each unreachable arm traced to its guard. Line citations were re-read rather than carried over.🤖 Generated with Claude Code