From 14049bb4777739e48f690bf5f0e82d20a12665a7 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:09:27 -0700 Subject: [PATCH] Document the forced-probe redesign in the changelog --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ src/disc/pgs_forced_probe.rs | 23 ++++++++++++++++++----- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 119c61a..4c2ebdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,37 @@ ### Fixed +- **Content-based forced-subtitle detection never observed anything on a + feature-length disc.** The PGS probe spent its entire 256 MiB budget on the + first sectors of a title, where a feature has no subtitles at all — it hit + the budget, observed zero display sets, and contributed nothing to any + verdict, so the vendor label was always the only input. The same budget is + now SPREAD across each extent as ~16 MiB sample windows sized in proportion + to the extent (still on the AACS aligned-unit grid, still bounded by the same + ceiling): a track is disproven by any single non-forced display set anywhere, + and a genuine forced track is small enough to be caught by the spread. Cost + is unchanged; placement is not. The probe also stops spending budget on a + track the moment it is disproven, and skips an extent that owes evidence only + for such tracks. +- **A partially-read extent's evidence was memoised as if the whole extent had + been read.** A budget-cut (and now sampled) read covers a fraction of an + extent, but its result was filed under the extent's full key and replayed to + every other playlist sharing the clip — turning a prefix into an absence + claim about the whole extent. Cache entries now carry the coverage behind + them, and an entry only answers for a run that intended to read no more than + it did. Positive evidence (a non-forced display set was seen) still answers + regardless, being irretractable. +- **Content could never correct a wrong vendor forced label.** The muxer only + ever promoted `FlagForced` 0 → 1, so a track labelled forced stayed forced in + the output even when the mux had seen every one of its two thousand display + sets and not one was forced. Content may now clear the flag too — in the + muxer and in the scan-time probe — behind a single shared guard: the absence + of `forced_on_flag` means nothing on a disc whose authoring never sets it, so + a demotion requires that some other track demonstrably uses the flag AND that + the track have the shape of a full dialogue track rather than of a + forced-narrative one. Where no track on the disc uses the flag, nothing is + demotable. + - **An `.fvi` index named itself as its own source.** The `fvi://` sink was handed the DESTINATION path as its `source_path`, so every index reported `source.path` as the file it was writing. `source.medium` was always `file` diff --git a/src/disc/pgs_forced_probe.rs b/src/disc/pgs_forced_probe.rs index f15565a..7cd3b88 100644 --- a/src/disc/pgs_forced_probe.rs +++ b/src/disc/pgs_forced_probe.rs @@ -6,11 +6,24 @@ //! streams and feeding them through the one shared classifier //! ([`crate::mux::codec::pgs::ForcedTracker`]) — so the two never diverge. //! -//! Cost: a track is only confirmed forced once EVERY display set is seen to be -//! forced, so a disc that has a forced track is read through — the -//! accuracy-over-speed tradeoff `info` opts into. Full tracks early-exit as soon -//! as they show a single non-forced subtitle, and a whole run stops early once -//! every track has settled. +//! WHERE it reads is the whole design. A track is forced iff EVERY display set +//! carries `forced_on_flag`, so one non-forced set disproves forced for good, +//! while proving forced needs the whole track — and the tracks that are +//! expensive to prove are the cheap ones to read (a forced-narrative track is +//! tens of display sets; a full dialogue track is thousands). A bounded budget +//! spent on the title's HEAD therefore learns nothing at all: a feature's +//! subtitles begin minutes in, past the end of any affordable prefix. The budget +//! ([`PROBE_BUDGET_SECTORS`]) is instead SPREAD over each extent as sample +//! windows ([`plan_windows`]), so every window is an independent chance to catch +//! a display set. +//! +//! Cost: the budget is a hard ceiling per call. A run stops early once no track +//! can still change its outcome — disproven, and with no wrong forced label left +//! to correct. +//! +//! Contradicting a label: content may CLEAR a vendor forced flag as well as set +//! one, but only behind [`crate::mux::codec::pgs::demotable`] — an absence of +//! `forced_on_flag` proves nothing on a disc whose authoring never sets it. //! //! Encrypted content: the probe reuses whatever [`SectorSource`] the scan holds. //! With a decrypting source it sees real PGS; without keys it reads ciphertext