Media3Engine's two enum-to-MIME tables decide which codec ends up in the user's file, and neither
was exercised by anything. One of them also carried a claim about its callers, which nothing checked.
The verdict on the "never reached" claim: split
Video — proved.// Never reached: only an Encode plan consults this, and COPY/NONE are not Encode is true, and it is now a checked claim rather than an asserted one. The proof is a property
of CopyPlanner, which is where every plan the engine sees comes from: both codecs are answered
before the Encode branch (NONE -> Drop, COPY -> Copy or fallback), and the fallback draws from ContainerCapabilities.encodableVideo, which contains neither. The test sweeps every spec the
planner can be handed — 15 containers x 7 video codecs x 8 audio codecs x 7 probes — and asserts no Encode plan carries COPY or NONE.
Audio — incomplete, and rewritten.// MP3 and FLAC have no Android encoder; the router routes them to FFmpeg is true as far as it goes, and it reads as though those two were the exceptions.
They are not. One rule — audioEncode !in MEDIA3_AUDIO, where MEDIA3_AUDIO = {AAC, OPUS, PCM} —
diverts Vorbis by identical logic, so three of the six encodable codecs never reach the
table, not two. AudioCodec.VORBIS -> MimeTypes.AUDIO_VORBIS names a MIME type Transformer is never
actually asked for.
The arm is kept: the mapping is correct, and deleting a right answer out of unreachable code buys
nothing while changing behaviour in code no test can reach. The comment now says what is actually
guaranteed, and Vorbis is the one MIME type the router never asks for pins the surplus, so a
routing change that makes Vorbis live fails rather than surprises.
What the tests check
Three kinds, because arm-by-arm equality alone would only pin today's answers:
Every arm of both tables, nulls included, against an expected map that is itself asserted to
name every enum constant — so a new codec cannot arrive untested.
The "never reached" claim, as the sweep above. Two counters guard it: (plan.video as? VideoPlan.Encode)?.let { ... } asserts nothing at all for a Drop or Copy plan, so a sweep
that stopped producing Encode plans would stay green while checking nothing.
The tables against ConversionRouter's decisions, not against its codec sets. The comments
claim behaviour ("the router routes them to FFmpeg") and a set can be right while the rule
reading it is wrong, so the tests call route(). Each helper first asserts that its request
really does plan an Encode of the codec in question, so "routed to FFmpeg" is about the codec
rather than about some other plan shape.
Mutations, verbatim
The one #85 names — VideoCodec.H265 -> MimeTypes.VIDEO_H264:
org.junit.ComparisonFailure: videoMimeTypeFor(H.265) expected:<video/[he]vc> but was:<video/[a]vc>
The sweep carrying the ticket's point — delete if (requested == VideoCodec.NONE) return VideoPlan.Drop from CopyPlanner.planVideo:
java.lang.AssertionError: CopyPlanner produced VideoPlan.Encode(NONE) for OutputSpec(container=MP4,
videoCodec=NONE, audioCodec=COPY) against InputProbe(videoCodec=null, audioCodec=null,
hasVideo=true, durationMs=0, kind=VIDEO, container=null, width=0, height=0)
The Vorbis finding — add AudioCodec.VORBIS to ConversionRouter.MEDIA3_AUDIO:
java.lang.AssertionError: expected:<[AAC, OPUS, PCM]> but was:<[AAC, OPUS, VORBIS, PCM]>
java.lang.AssertionError: expected:<[VORBIS]> but was:<[]>
Each mutation was reverted and the suite confirmed green again.
The visibility change
Both functions move to an internal companion object. internal is #57's precedent — the JVM test
source set is a friend of main. The companion is what avoids constructing a Media3Engine to
answer an enum lookup, which would start a real HandlerThread; the call sites in buildTransformer
are unchanged.
Not covered, and why
transcode, buildTransformer, pollProgress, close and the constructor drive Transformer
against real codecs. androidTest/Media3EngineTest and RemuxTest cover them on a device, and
JaCoCo measures testDebugUnitTest only. Untouched, and not mocked.
No fifth codec table was added, and CodecNames.kt / AndroidDeviceCodecs.kt / MediaProbe.kt
are untouched — #87 owns the alias-name drift. Worth noting for that ticket: AndroidDeviceCodecs
has an enum -> MIME table too (mimeFor(VideoCodec)), on the same axis as the one here, and it
currently agrees by value. That is a fifth pairing nothing checks; it belongs with #87's
cross-check rather than here.
Closes #85.
`Media3Engine`'s two enum-to-MIME tables decide which codec ends up in the user's file, and neither
was exercised by anything. One of them also carried a claim about its callers, which nothing checked.
## The verdict on the "never reached" claim: split
**Video — proved.** `// Never reached: only an Encode plan consults this, and COPY/NONE are not
Encode` is true, and it is now a checked claim rather than an asserted one. The proof is a property
of `CopyPlanner`, which is where every plan the engine sees comes from: both codecs are answered
before the `Encode` branch (`NONE -> Drop`, `COPY -> Copy or fallback`), and the fallback draws from
`ContainerCapabilities.encodableVideo`, which contains neither. The test sweeps every spec the
planner can be handed — 15 containers x 7 video codecs x 8 audio codecs x 7 probes — and asserts no
`Encode` plan carries `COPY` or `NONE`.
**Audio — incomplete, and rewritten.** `// MP3 and FLAC have no Android encoder; the router routes
them to FFmpeg` is true as far as it goes, and it reads as though those two were the exceptions.
They are not. One rule — `audioEncode !in MEDIA3_AUDIO`, where `MEDIA3_AUDIO = {AAC, OPUS, PCM}` —
diverts **Vorbis** by identical logic, so **three** of the six encodable codecs never reach the
table, not two. `AudioCodec.VORBIS -> MimeTypes.AUDIO_VORBIS` names a MIME type Transformer is never
actually asked for.
The arm is kept: the mapping is correct, and deleting a right answer out of unreachable code buys
nothing while changing behaviour in code no test can reach. The comment now says what is actually
guaranteed, and `Vorbis is the one MIME type the router never asks for` pins the surplus, so a
routing change that makes Vorbis live fails rather than surprises.
## What the tests check
Three kinds, because arm-by-arm equality alone would only pin today's answers:
1. **Every arm of both tables**, nulls included, against an expected map that is itself asserted to
name every enum constant — so a new codec cannot arrive untested.
2. **The "never reached" claim**, as the sweep above. Two counters guard it: `(plan.video as?
VideoPlan.Encode)?.let { ... }` asserts nothing at all for a `Drop` or `Copy` plan, so a sweep
that stopped producing `Encode` plans would stay green while checking nothing.
3. **The tables against `ConversionRouter`'s decisions**, not against its codec sets. The comments
claim behaviour ("the router routes them to FFmpeg") and a set can be right while the rule
reading it is wrong, so the tests call `route()`. Each helper first asserts that its request
really does plan an `Encode` of the codec in question, so "routed to FFmpeg" is about the codec
rather than about some other plan shape.
## Mutations, verbatim
**The one #85 names** — `VideoCodec.H265 -> MimeTypes.VIDEO_H264`:
```
org.junit.ComparisonFailure: videoMimeTypeFor(H.265) expected:<video/[he]vc> but was:<video/[a]vc>
```
**The sweep carrying the ticket's point** — delete `if (requested == VideoCodec.NONE) return
VideoPlan.Drop` from `CopyPlanner.planVideo`:
```
java.lang.AssertionError: CopyPlanner produced VideoPlan.Encode(NONE) for OutputSpec(container=MP4,
videoCodec=NONE, audioCodec=COPY) against InputProbe(videoCodec=null, audioCodec=null,
hasVideo=true, durationMs=0, kind=VIDEO, container=null, width=0, height=0)
```
**The Vorbis finding** — add `AudioCodec.VORBIS` to `ConversionRouter.MEDIA3_AUDIO`:
```
java.lang.AssertionError: expected:<[AAC, OPUS, PCM]> but was:<[AAC, OPUS, VORBIS, PCM]>
java.lang.AssertionError: expected:<[VORBIS]> but was:<[]>
```
Each mutation was reverted and the suite confirmed green again.
## The visibility change
Both functions move to an `internal companion object`. `internal` is #57's precedent — the JVM test
source set is a friend of `main`. The companion is what avoids constructing a `Media3Engine` to
answer an enum lookup, which would start a real `HandlerThread`; the call sites in `buildTransformer`
are unchanged.
## Not covered, and why
- `transcode`, `buildTransformer`, `pollProgress`, `close` and the constructor drive Transformer
against real codecs. `androidTest/Media3EngineTest` and `RemuxTest` cover them on a device, and
JaCoCo measures `testDebugUnitTest` only. Untouched, and not mocked.
- No fifth codec table was added, and `CodecNames.kt` / `AndroidDeviceCodecs.kt` / `MediaProbe.kt`
are untouched — #87 owns the alias-name drift. Worth noting for that ticket: `AndroidDeviceCodecs`
has an `enum -> MIME` table too (`mimeFor(VideoCodec)`), on the same axis as the one here, and it
currently agrees by value. That is a fifth pairing nothing checks; it belongs with #87's
cross-check rather than here.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
CI: everything green except two things, neither of them this diff.
E2E API 37 Media3 hardware transcode (advisory) — red on every PR by design, per CLAUDE.md.
E2E API 34 — SafPickerRoundTripTest.thePickedInputSurvivesARealRotation and .pickingAFileThroughTheSystemPickerFillsInTheFileCard, the pair landed in #80. Three pieces of
evidence that they are a flake rather than a regression:
The identical two tests failed at the same moment on #89, whose entire diff is two JVM unit
test files. A change that touches no androidTest code cannot break a SAF picker test.
On a re-run of this same commit, E2E API 33 and E2E API 35 flipped from red to green
while nothing changed. E2E API 36 and the gating E2E API 37 were green in both runs.
This diff is a visibility change plus comments in Media3Engine.kt and one new JVM test file.
There is no path from it to the SAF picker.
The first run had five agent PRs on CI simultaneously, which is the kind of load a
rotation-and-picker test is sensitive to. Not filing a ticket from here in case a sibling agent
already has; flagging it because it will keep costing re-runs.
CI: everything green except two things, neither of them this diff.
**`E2E API 37 Media3 hardware transcode (advisory)`** — red on every PR by design, per CLAUDE.md.
**`E2E API 34`** — `SafPickerRoundTripTest.thePickedInputSurvivesARealRotation` and
`.pickingAFileThroughTheSystemPickerFillsInTheFileCard`, the pair landed in #80. Three pieces of
evidence that they are a flake rather than a regression:
1. The **identical two tests** failed at the same moment on #89, whose entire diff is two JVM unit
test files. A change that touches no `androidTest` code cannot break a SAF picker test.
2. On a re-run of **this same commit**, `E2E API 33` and `E2E API 35` flipped from red to green
while nothing changed. `E2E API 36` and the gating `E2E API 37` were green in both runs.
3. This diff is a visibility change plus comments in `Media3Engine.kt` and one new JVM test file.
There is no path from it to the SAF picker.
The first run had five agent PRs on CI simultaneously, which is the kind of load a
rotation-and-picker test is sensitive to. Not filing a ticket from here in case a sibling agent
already has; flagging it because it will keep costing re-runs.
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 #85.
Media3Engine's two enum-to-MIME tables decide which codec ends up in the user's file, and neitherwas exercised by anything. One of them also carried a claim about its callers, which nothing checked.
The verdict on the "never reached" claim: split
Video — proved.
// Never reached: only an Encode plan consults this, and COPY/NONE are not Encodeis true, and it is now a checked claim rather than an asserted one. The proof is a propertyof
CopyPlanner, which is where every plan the engine sees comes from: both codecs are answeredbefore the
Encodebranch (NONE -> Drop,COPY -> Copy or fallback), and the fallback draws fromContainerCapabilities.encodableVideo, which contains neither. The test sweeps every spec theplanner can be handed — 15 containers x 7 video codecs x 8 audio codecs x 7 probes — and asserts no
Encodeplan carriesCOPYorNONE.Audio — incomplete, and rewritten.
// MP3 and FLAC have no Android encoder; the router routes them to FFmpegis true as far as it goes, and it reads as though those two were the exceptions.They are not. One rule —
audioEncode !in MEDIA3_AUDIO, whereMEDIA3_AUDIO = {AAC, OPUS, PCM}—diverts Vorbis by identical logic, so three of the six encodable codecs never reach the
table, not two.
AudioCodec.VORBIS -> MimeTypes.AUDIO_VORBISnames a MIME type Transformer is neveractually asked for.
The arm is kept: the mapping is correct, and deleting a right answer out of unreachable code buys
nothing while changing behaviour in code no test can reach. The comment now says what is actually
guaranteed, and
Vorbis is the one MIME type the router never asks forpins the surplus, so arouting change that makes Vorbis live fails rather than surprises.
What the tests check
Three kinds, because arm-by-arm equality alone would only pin today's answers:
name every enum constant — so a new codec cannot arrive untested.
(plan.video as? VideoPlan.Encode)?.let { ... }asserts nothing at all for aDroporCopyplan, so a sweepthat stopped producing
Encodeplans would stay green while checking nothing.ConversionRouter's decisions, not against its codec sets. The commentsclaim behaviour ("the router routes them to FFmpeg") and a set can be right while the rule
reading it is wrong, so the tests call
route(). Each helper first asserts that its requestreally does plan an
Encodeof the codec in question, so "routed to FFmpeg" is about the codecrather than about some other plan shape.
Mutations, verbatim
The one #85 names —
VideoCodec.H265 -> MimeTypes.VIDEO_H264:The sweep carrying the ticket's point — delete
if (requested == VideoCodec.NONE) return VideoPlan.DropfromCopyPlanner.planVideo:The Vorbis finding — add
AudioCodec.VORBIStoConversionRouter.MEDIA3_AUDIO:Each mutation was reverted and the suite confirmed green again.
The visibility change
Both functions move to an
internal companion object.internalis #57's precedent — the JVM testsource set is a friend of
main. The companion is what avoids constructing aMedia3Enginetoanswer an enum lookup, which would start a real
HandlerThread; the call sites inbuildTransformerare unchanged.
Not covered, and why
transcode,buildTransformer,pollProgress,closeand the constructor drive Transformeragainst real codecs.
androidTest/Media3EngineTestandRemuxTestcover them on a device, andJaCoCo measures
testDebugUnitTestonly. Untouched, and not mocked.CodecNames.kt/AndroidDeviceCodecs.kt/MediaProbe.ktare untouched — #87 owns the alias-name drift. Worth noting for that ticket:
AndroidDeviceCodecshas an
enum -> MIMEtable too (mimeFor(VideoCodec)), on the same axis as the one here, and itcurrently agrees by value. That is a fifth pairing nothing checks; it belongs with #87's
cross-check rather than here.
🤖 Generated with Claude Code
CI: everything green except two things, neither of them this diff.
E2E API 37 Media3 hardware transcode (advisory)— red on every PR by design, per CLAUDE.md.E2E API 34—SafPickerRoundTripTest.thePickedInputSurvivesARealRotationand.pickingAFileThroughTheSystemPickerFillsInTheFileCard, the pair landed in #80. Three pieces ofevidence that they are a flake rather than a regression:
test files. A change that touches no
androidTestcode cannot break a SAF picker test.E2E API 33andE2E API 35flipped from red to greenwhile nothing changed.
E2E API 36and the gatingE2E API 37were green in both runs.Media3Engine.ktand one new JVM test file.There is no path from it to the SAF picker.
The first run had five agent PRs on CI simultaneously, which is the kind of load a
rotation-and-picker test is sensitive to. Not filing a ticket from here in case a sibling agent
already has; flagging it because it will keep costing re-runs.