Stop reporting a corrupt mkv:// source as an empty title

E6008 meant two unrelated things: "this title produced no muxable
frames", which is a benign stub worth skipping, and "the source file is
malformed", which is not. Because a single code carried both,
is_skippable_title_stub answered yes to the second one — so feeding a
truncated or corrupt mkv:// input made the engine classify it
SkippableStub, print a notice saying the title was empty, and exit 0.
Silent data loss reported as success.

Split into E9053 MkvSourceInvalid for the read path (25 raise sites
across mkvstream.rs and ebml.rs's read primitives) and E9054
MkvUnencodable for the four write-side sites, which are the encoder
refusing to emit a body at or above the 56-bit VINT limit — an output
limit with no input involved, so calling it a corrupt source would be
wrong in the other direction. E6008 keeps only the zero-frame guard it
was documented to mean.

Kept one code for the whole read path rather than one per raise site:
nothing a consumer does differs between a bad VINT, a non-UTF-8 string
element, a truncated body and a child overrunning its parent. E9052 is
the model for when a carve-out earns its keep — laced blocks name one
specific RFC 9559 §10.3 feature with its own diagnosis.

Also fixed meta_sink.rs raising MkvInvalid for a serde_json encode
failure in the json:// sink, where no MKV is involved at all; it now
matches the identical guard in mux/meta.rs.

Reverting the split at the single code() arm reproduces the old
classification: 22 tests fail, including both new assertions. The
opposite direction is pinned too — dropping E6008 from the predicate
fails the genuine-stub test, which drives the real muxer end to end.
This commit is contained in:
Matthew Jackson
2026-07-29 22:11:53 -07:00
parent 0bbceed985
commit f5e169efb3
6 changed files with 260 additions and 79 deletions
+17
View File
@@ -41,6 +41,23 @@
### Fixed
- **A corrupt `mkv://` input is no longer reported as a title worth silently
skipping.** `Error::MkvInvalid` (E6008) carried two unrelated meanings: the
genuine "this title produced no muxable frames" stub — which
`is_skippable_title_stub` classifies as skippable, so an all-titles rip drops
the title and finishes the rest — and *every* malformed-input rejection in the
MKV read path. A truncated file, a bad VINT, a cluster timestamp past
`i64::MAX`, a BlockGroup child overrunning its group: all of them classified as
skippable, so a broken source was passed over by a run that then exited
successfully. The read path now raises `Error::MkvSourceInvalid`
(**E9053**) — the counterpart of `Mp4Invalid` (E9049) — and the writer's
unrepresentable-element-size guards raise `Error::MkvUnencodable` (**E9054**).
Neither is skippable. `E6008` now means only the no-muxable-frames stub (the
mux driver's headers-never-resolved gate and the MKV muxer's zero-frame
`finish()` guard). The `json://` sink's metadata-encoding guard, which also
raised `MkvInvalid`, now raises `NoMetadata` (E9008) like `mux::meta`'s.
Front-ends rendering error strings need entries for E9053 and E9054 (and for
E9051 / E9052, split off `E6008` earlier in this cycle for the same reason).
- **The FMTS (AACS 2.1) forensic key resolution now runs once per disc, not once
per title.** `Disc::resolve_content_key_map` resolves every title, and the FMTS
branch ran ahead of everything else — so each playlist re-walked the UDF