From 022657d481ee3b54635a91e17d5b33942a7cc134 Mon Sep 17 00:00:00 2001 From: MattJackson <1085847+MattJackson@users.noreply.github.com> Date: Fri, 24 Apr 2026 21:36:49 -0700 Subject: [PATCH] docs: complete 0.13.6 docs sweep (architecture, api-design, disc-to-rip, README) Follow-up to the rip-recovery + drive-access updates: aligns the remaining docs with the v0.13.6 single-shot read model and the three-layer recovery architecture. - architecture.md: module map says single-shot read; new paragraph on layered recovery with postmortem pointer. - api-design.md: EventKind enum example expanded; emission notes document that BytesRead now fires from DiscStream::fill_extents and Retry/SectorRecovered are no longer emitted in 0.13.6+. - disc-to-rip.md: Step 10 of the pipeline diagram + module table reflect single-shot read. - docs/README.md: added rip-recovery.md to the TOC. --- docs/README.md | 1 + docs/api-design.md | 36 +++++++++++++++++++++++++++++++++--- docs/architecture.md | 11 +++++++++-- docs/disc-to-rip.md | 6 ++++-- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index fcfc3d8..45a5335 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,6 +12,7 @@ Technical documentation for [libfreemkv](https://github.com/freemkv/libfreemkv), |----------|---------------| | [Architecture](architecture.md) | Module map, design principles, error codes, platform support | | [Drive Access](drive-access.md) | Drive, SCSI transport, profiles, unlock, why raw mode is needed | +| [Rip Recovery](rip-recovery.md) | Three-layer recovery model: Disc::patch, single-shot Drive::read, DiscStream batch halving | | [AACS Encryption](aacs.md) | Key resolution (4 paths), content decryption, bus encryption, SCSI handshake | | [UDF Filesystem](udf.md) | UDF 2.50 with metadata partitions, pointer chain, how files are read from disc | | [MPLS Playlists](mpls.md) | Playlist format, play items, STN stream table, coding types | diff --git a/docs/api-design.md b/docs/api-design.md index fb976e4..3e8c24c 100644 --- a/docs/api-design.md +++ b/docs/api-design.md @@ -126,15 +126,45 @@ pub struct Event { } pub enum EventKind { + // Init / scan + DriveOpened { device: String }, + DriveReady, + InitComplete { success: bool }, + ProbeComplete { success: bool }, + ScanComplete { titles: usize }, + + // Read pipeline BytesRead { bytes: u64, total: u64 }, ReadError { sector: u64, error: Error }, - Retry { attempt: u32 }, SpeedChange { speed_kbs: u16 }, ExtentStart { index: usize, start_sector: u64, sector_count: u64 }, + SectorSkipped { sector: u64 }, + BatchSizeChanged { new_size: u16, reason: BatchSizeReason }, Complete { bytes: u64, errors: u32 }, + + // Kept for forward-compat; not emitted in 0.13.6+ + Retry { attempt: u32 }, + SectorRecovered { sector: u64 }, } ``` +Emission notes: + +- `BytesRead { bytes, total }` is emitted from `DiscStream::fill_extents` + after each successful sector read. `bytes` is the cumulative running + total; `total` is the precomputed extent sum (0 if unknown). +- `SpeedChange` is emitted from the public `Drive::set_speed` API path. + It is no longer emitted from a recovery hot loop (recovery loop removed + in 0.13.6). +- `BatchSizeChanged` fires from the `DiscStream` adaptive sizer on shrink + (read failed at a larger size) and on probe-up (clean-read streak hit + the threshold). Consumers use it to display a "recovering" state + distinct from "ripping normally". +- `Retry` and `SectorRecovered` are NOT emitted in 0.13.6+. They were + tied to the inline `Drive::read` recovery phases that were removed; the + variants are kept for forward compatibility so consumers' match arms + don't need conditional compilation. + Events report what happened. App decides what to do. GUI shows a dialog. CLI prints a line. Server logs to file. @@ -145,8 +175,8 @@ libfreemkv/src/ ├── lib.rs Public exports ├── error.rs Error codes (no English) ├── event.rs Event types for callbacks -├── drive/ Drive (open, init, read with recovery) -│ ├── mod.rs Drive struct, init, read, reset, eject +├── drive/ Drive (open, init, single-shot read) +│ ├── mod.rs Drive struct, init, read (single-shot), reset, eject │ ├── capture.rs Drive profile capture for contribution │ ├── linux.rs Linux drive discovery │ ├── macos.rs macOS drive discovery diff --git a/docs/architecture.md b/docs/architecture.md index dd33d94..3da74d3 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -41,7 +41,7 @@ AACS keys are derived internally, and all SCSI communication is handled in-proce libfreemkv (lib.rs) │ ├── Drive Access -│ ├── drive Drive — open, identify, init, unlock, read (with recovery) +│ ├── drive Drive — open, identify, init, unlock, single-shot read │ ├── scsi ScsiTransport trait + platform backends (sg async, IOKit, SPTI) │ ├── platform/ Platform trait — per-chipset command handlers │ │ └── mt1959 MediaTek MT1959 driver (LG, ASUS, HP) @@ -93,10 +93,17 @@ Drive::open(Path::new("/dev/sg4")) After open: - `init()` -- unlock + firmware upload + speed calibration - `probe_disc()` -- probe disc surface for optimal speeds -- `read(lba, count, buf)` -- single read method with built-in error recovery +- `read(lba, count, buf, recovery)` -- single-shot read; `recovery` only selects the per-CDB timeout (1.5 s vs. 30 s) - `wait_ready()` -- wait for disc insertion - `eject()` -- eject tray +Recovery is layered above `Drive::read`, not inside it. Layer 1 +(`Disc::patch`) handles bad-range retry by replaying the ddrescue mapfile. +Layer 3 (`DiscStream::fill_extents` adaptive batch sizer) handles in-loop +request-size adaptation. Inline recovery (gentle retry → SCSI reset → retry) +was removed in 0.13.6 — see [`rip-recovery.md`](rip-recovery.md) and +`(internal)/postmortems/2026-04-25-stop-wedge-and-zero-kbs.md`. + --- ## Disc Scanning Flow diff --git a/docs/disc-to-rip.md b/docs/disc-to-rip.md index cb2f55e..d3feea1 100644 --- a/docs/disc-to-rip.md +++ b/docs/disc-to-rip.md @@ -77,7 +77,9 @@ Insert disc 10. Stream content (mux/disc.rs → DiscStream) │ Read sectors → decrypt → TS demux → PES frames │ Or: read sectors → decrypt → raw bytes (for ISO output) - │ Drive::read() handles error recovery (min speed → reset → retry) + │ Drive::read() is single-shot. DiscStream::fill_extents adapts the + │ batch size on failure (halve / probe-up). Bad-range retry is layer + │ 1 above this — Disc::patch re-runs against the mapfile. │ ▼ PES frames → output stream (MKV, M2TS, network, etc.) @@ -110,7 +112,7 @@ output.finish()?; | Module | Doc | Purpose | |--------|-----|---------| -| drive/ | [drive-access.md](drive-access.md) | Open, identify, init, unlock, read (with recovery) | +| drive/ | [drive-access.md](drive-access.md) | Open, identify, init, unlock, single-shot read | | scsi/ | [drive-access.md](drive-access.md) | Platform SCSI transport (Linux, macOS, Windows) | | udf.rs | [udf.md](udf.md) | UDF 2.50 filesystem | | mpls.rs | [mpls.md](mpls.md) | MPLS playlists + STN streams |