Hold the two codec MIME claims that only existed in prose #98

Merged
JMR-dev merged 2 commits from test/device-codecs-encode-consequence into main 2026-08-25 14:51:01 +00:00
JMR-dev commented 2026-08-25 05:21:36 +00:00 (Migrated from github.com)

Closes #86.

Most of #86 landed with #90; per its comment, two things were left.

1. mimeFor's COPY, NONE -> null arm, at the seam it exists for

The arm documents a consequence rather than a value: returning null is what makes canEncode answer true, because a copied or absent track places no demand on the hardware. #90 pinned the null. Nothing pinned the answer.

CodecVocabularyTest.a device with no video encoder at all still permits a copied or absent track builds forTesting(encoders = emptySet()) and asserts canEncode(COPY) and canEncode(NONE) are both true — with canEncode(H264) == false on the same instance, so a canEncode that unconditionally said yes cannot satisfy it.

2. The fifth VideoCodec -> MIME table

Media3Engine.videoMimeTypeFor is the same axis as AndroidDeviceCodecs.mimeFor. Both became internal in #85/#87, so the cross-check is finally writable. New file: VideoCodecMimeAgreementTest.

They do not agree everywhere, and forcing them to would be a regression. Three buckets, all asserted, with the fourth asserted empty:

Bucket Codecs Why
Both name a MIME H.264, H.265 Must be the same string, or the device is asked about one codec and Transformer told to produce another
Device only VP8, VP9, AV1 setVideoMimeType rejects them so the router never asks Media3 — but a device may genuinely own a VP9 encoder and canEncode must answer truthfully. Flattening mimeFor to null here would make canEncode(VP9) say true on hardware with no VP9 encoder
Neither COPY, NONE Nothing is encoded
Transformer only (empty) Would mean canEncode waving through a codec Media3 really is told to produce

Sorting rather than filtering, so a convergence fails too: giving videoMimeTypeFor(VP9) a real MIME reddens this. The divergence should be deliberate and visible.

The routing half of the VP8/VP9/AV1 claim is already proved against the real router in Media3EngineMimeTypesTest.the router sends exactly H264 and H265 video encodes to Media3; the KDoc points there rather than duplicating the CopyPlanner-driving harness.

Audio has no partner

AndroidDeviceCodecs enumerates video/ MIME types only, so audioMimeTypeFor has nothing to cross-check against — a missing audio encoder is still found by failing rather than up front. Named in the KDoc as a gap rather than left as an unexplained asymmetry.

Mutations

All three run against the full 416-test JVM suite.

(a) AndroidDeviceCodecs.mimeFor, COPY gets a MIME:

VideoCodec.COPY -> MediaFormat.MIMETYPE_VIDEO_AVC
VideoCodec.NONE -> null

→ 416 tests completed, 2 failed — CodecVocabularyTest > a device with no video encoder at all still permits a copied or absent track and VideoCodecMimeAgreementTest > each video codec is in the bucket the two tables actually put it in. Nothing else in the suite notices.

(b) Media3Engine.videoMimeTypeFor, the two tables disagree on H.265:

VideoCodec.H265 -> MimeTypes.VIDEO_H264

→ 416 tests completed, 3 failed — the two new cross-check tests, plus the pre-existing Media3EngineMimeTypesTest > every video codec maps to the MIME type Transformer will be given. This shows the cross-check is sufficient, not that it is necessary: the arm test catches this one too.

(c) the same disagreement, with the per-table expectation updated in lockstep — (b) plus, in Media3EngineMimeTypesTest:

VideoCodec.H265 to MimeTypes.VIDEO_H264,

→ 416 tests completed, 2 failed, both in VideoCodecMimeAgreementTest. All 7 of Media3EngineMimeTypesTest and all 10 of CodecVocabularyTest stay green while the two tables describe different codecs. This is the mutation that shows the cross-check is necessary, and it is the argument #87 made.

Exemptions

  • Test-only change. No main source file is touched.
  • No e2e. Both tables take an enum and return a constant; there is nothing a device answers differently. The device-dependent half is canEncode's membership test, exercised here through forTesting.
  • audioMimeTypeFor is not cross-checked — there is no second audio table to check it against. Documented in the KDoc rather than papered over.
  • The deviceOnly divergence test is implied by the bucket test. Kept deliberately: it is the place the legitimate disagreement is stated by name, and it fails with a message explaining which half a "tidy-up" would have deleted.

Gate

assembleDebug testDebugUnitTest compileDebugAndroidTestKotlin ktlintCheck detekt lintDebug --continue → BUILD SUCCESSFUL.

🤖 Generated with Claude Code

Closes #86. Most of #86 landed with #90; per its comment, two things were left. ## 1. `mimeFor`'s `COPY, NONE -> null` arm, at the seam it exists for The arm documents a consequence rather than a value: returning null is what makes `canEncode` answer `true`, because a copied or absent track places no demand on the hardware. #90 pinned the null. Nothing pinned the answer. `CodecVocabularyTest.a device with no video encoder at all still permits a copied or absent track` builds `forTesting(encoders = emptySet())` and asserts `canEncode(COPY)` and `canEncode(NONE)` are both true — with `canEncode(H264) == false` on the same instance, so a `canEncode` that unconditionally said yes cannot satisfy it. ## 2. The fifth `VideoCodec -> MIME` table `Media3Engine.videoMimeTypeFor` is the same axis as `AndroidDeviceCodecs.mimeFor`. Both became `internal` in #85/#87, so the cross-check is finally writable. New file: `VideoCodecMimeAgreementTest`. **They do not agree everywhere, and forcing them to would be a regression.** Three buckets, all asserted, with the fourth asserted empty: | Bucket | Codecs | Why | |---|---|---| | Both name a MIME | H.264, H.265 | Must be the same string, or the device is asked about one codec and Transformer told to produce another | | Device only | VP8, VP9, AV1 | `setVideoMimeType` rejects them so the router never asks Media3 — but a device may genuinely own a VP9 encoder and `canEncode` must answer truthfully. Flattening `mimeFor` to null here would make `canEncode(VP9)` say true on hardware with no VP9 encoder | | Neither | COPY, NONE | Nothing is encoded | | Transformer only | *(empty)* | Would mean `canEncode` waving through a codec Media3 really is told to produce | Sorting rather than filtering, so a *convergence* fails too: giving `videoMimeTypeFor(VP9)` a real MIME reddens this. The divergence should be deliberate and visible. The routing half of the VP8/VP9/AV1 claim is already proved against the real router in `Media3EngineMimeTypesTest.the router sends exactly H264 and H265 video encodes to Media3`; the KDoc points there rather than duplicating the `CopyPlanner`-driving harness. ## Audio has no partner `AndroidDeviceCodecs` enumerates `video/` MIME types only, so `audioMimeTypeFor` has nothing to cross-check against — a missing audio encoder is still found by failing rather than up front. Named in the KDoc as a gap rather than left as an unexplained asymmetry. ## Mutations All three run against the full 416-test JVM suite. **(a) `AndroidDeviceCodecs.mimeFor`, `COPY` gets a MIME:** ```kotlin VideoCodec.COPY -> MediaFormat.MIMETYPE_VIDEO_AVC VideoCodec.NONE -> null ``` → `416 tests completed, 2 failed` — `CodecVocabularyTest > a device with no video encoder at all still permits a copied or absent track` and `VideoCodecMimeAgreementTest > each video codec is in the bucket the two tables actually put it in`. Nothing else in the suite notices. **(b) `Media3Engine.videoMimeTypeFor`, the two tables disagree on H.265:** ```kotlin VideoCodec.H265 -> MimeTypes.VIDEO_H264 ``` → `416 tests completed, 3 failed` — the two new cross-check tests, plus the pre-existing `Media3EngineMimeTypesTest > every video codec maps to the MIME type Transformer will be given`. This shows the cross-check is *sufficient*, not that it is necessary: the arm test catches this one too. **(c) the same disagreement, with the per-table expectation updated in lockstep** — (b) plus, in `Media3EngineMimeTypesTest`: ```kotlin VideoCodec.H265 to MimeTypes.VIDEO_H264, ``` → `416 tests completed, 2 failed`, **both in `VideoCodecMimeAgreementTest`**. All 7 of `Media3EngineMimeTypesTest` and all 10 of `CodecVocabularyTest` stay green while the two tables describe different codecs. This is the mutation that shows the cross-check is *necessary*, and it is the argument #87 made. ## Exemptions - **Test-only change.** No main source file is touched. - **No e2e.** Both tables take an enum and return a constant; there is nothing a device answers differently. The device-dependent half is `canEncode`'s membership test, exercised here through `forTesting`. - **`audioMimeTypeFor` is not cross-checked** — there is no second audio table to check it against. Documented in the KDoc rather than papered over. - **The `deviceOnly` divergence test is implied by the bucket test.** Kept deliberately: it is the place the legitimate disagreement is stated by name, and it fails with a message explaining which half a "tidy-up" would have deleted. ## Gate `assembleDebug testDebugUnitTest compileDebugAndroidTestKotlin ktlintCheck detekt lintDebug --continue` → BUILD SUCCESSFUL. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.