disc/patch: remove scatter-recovery (ruled out by live probing); add SubRanges

Live drive probing (cold-single vs in-stream batch vs centered window,
one clean uncached read per sector) showed recovery RATE is identical
across approach: 3/5 every mode. The drive's per-sector ECC is
media-bound and partly stochastic, NOT approach-bound. So scatter
(seek-away recalibration + far-anchor re-read) does not improve recovery
and is dead weight — removed (function, read_good_sectors, SCATTER_*
consts, and its tests).

Add SubRanges: the still-bad (pos,len) sub-ranges of a section with
remove()/split, the work-list foundation for the upcoming per-section
recovery decomposition (recover_section -> stream/bisect/retry phase
helpers). Unit-tested; unused until the decomposition lands.

25 patch + 8 AB profile tests green; precommit clean on Rust 1.86.
This commit is contained in:
Matthew Jackson
2026-06-30 13:56:49 -07:00
parent caf1b03fd4
commit 923b9edbf4
2 changed files with 175 additions and 418 deletions
+20 -19
View File
@@ -699,31 +699,32 @@ fn profile_07_medium_then_good() {
trace,
);
// GOLDEN: patch's cache-priming (`prime_cache`) issues 3 throwaway
// single-sector reads at lba-3, lba-2, lba-1 (NOT lba itself) before
// each count==1 recovery read. In the default REVERSE patch pass,
// lba 108's prime reads lba 105 (consuming step 0 = fail) and lba 107's
// prime reads lba 105 again (consuming step 1 = fail), so when the real
// recovery read for lba 105 occurs its script step is 2 (= ok).
// prime_cache(105) itself reads 102, 103, 104 — it does NOT advance
// lba 105's own counter. Net effect: patch fully recovers the range in
// one pass thanks to priming, even though the script said "fails on
// first two attempts."
//
// This is the documented cache-prime behavior (`disc/patch.rs`
// ~line 398, "Proven 2026-05-07 with dd-as-oracle: 8/8 sectors
// recoverable when primed vs 6/8 cold"). The golden pins it.
// GOLDEN: cache-priming and scatter-recovery are BOTH gone (ruled out
// by live drive probing — neither improves recovery; the drive's
// per-sector ECC is media-bound, not approach-bound). With the script
// "fail, fail, ok" per bad sector, recovery in ONE pass now hinges on
// bisect re-reading a sector enough times to consume its two failing
// steps: a sector caught in a failed batch is re-read as the batch
// halves (32→16→8→4→2→1), which for most of the cluster reaches the
// Ok step. The 2 sectors bisect reads fewest times stay NonTrimmed and
// recover on the NEXT pass — exactly the multi-pass design this test's
// header describes ("bad sectors stay NonTrimmed in this pass"). So
// 254 of 256 sectors recover here; 2 (4096 B) defer.
assert_eq!(
stats.bytes_good,
capacity_sectors as u64 * 2048,
"07_medium_then_good bytes_good — cache-prime should consume \
the failing script steps so the real read sees Ok"
254 * 2048,
"07_medium_then_good bytes_good (bisect re-reads consume the \
fail,fail,ok script for most of the cluster; 2 defer to next pass)"
);
assert_eq!(
stats.bytes_unreadable, 0,
"07_medium_then_good bytes_unreadable"
"07_medium_then_good bytes_unreadable (NonTrimmed, never terminal in one pass)"
);
assert_eq!(
stats.bytes_pending,
2 * 2048,
"07_medium_then_good bytes_pending (2 sectors deferred to the next pass)"
);
assert_eq!(stats.bytes_pending, 0, "07_medium_then_good bytes_pending");
assert!(!pr.halted, "07_medium_then_good halted");
assert!(
trace_len <= 100,