main
Drew Owens 0.9.0: bridge data moved out of the install cache (recovery survives updates), closed-in-place records, gates route thr… 5d02ca9 20d ago
//! ADVERSARIAL REVIEW OF 0.7.3 — pass twenty-five.
//!
//! On the judgement call: **I agree with the Builder.** The distinction that
//! makes it principled is between a PREDICTION and a VERIFICATION. The headroom
//! gate predicts whether a write will fit; the marker, the floor, the
//! close-phase re-verify and the per-save census verify what actually reached
//! disk. Data safety rests entirely on the second group, and all of it still
//! runs when free space cannot be read. Refusing on an unmeasurable PREDICTION
//! would block a safe operation on a fact with no bearing on whether anything is
//! lost — and would put "ask the user" back in the path Drew ruled it out of.
//! Predictions may be unknown; verifications may not. `null` is the honest
//! report, and it is visible.
//!
//! That agreement is conditional, though, and the condition is this file: the
//! residual the call accepts is exactly the truncation class the verification
//! chain cannot catch (header intact, over the floor). How narrow that residual
//! is depends on the estimate being roughly right, and for a document whose size
//! cannot be measured it is not.
//!
//! MEASURED, over the 166 real documents in this container:
//!
//! ```text
//!          n     min        median      max
//! .SLDPRT  99    29,130     134,885     37,200,505
//! .SLDASM  38    95,492     4,139,430   16,644,232
//! .SLDDRW  29    319,803    1,958,169   32,250,713
//! ```

use swx_bridge::disk::estimate_writes;

/// A SMALL MEASURED DOCUMENT MAKES THE GUESS FOR AN UNKNOWN ONE SMALLER.
///
/// ```text
/// let unknown_cost = if biggest_known > 0 { biggest_known.saturating_mul(2) }
///                    else { UNKNOWN_DOCUMENT_ESTIMATE };
/// ```
///
/// With nothing measurable the estimator assumes 1 MB for an unknown document.
/// Measure one 29 KB part — the smallest real part in this container — and the
/// assumption for the unknown one DROPS to 58 KB. Knowing something small about
/// the session made the estimate of the unmeasured part of it worse.
///
/// It matters because `per_save_needed = estimate.largest * HEADROOM_FACTOR`,
/// so the same number gates the re-check before every save. A pathless assembly
/// beside a small part is costed at 58 KB; the median real assembly here is
/// 4.1 MB, and the largest is 16.6 MB. The per-save gate then passes with far
/// less room than the write needs, and the truncation that follows is the one
/// case marker-plus-floor cannot see.
///
/// The fix is one `max`: never let a measured neighbour lower the floor for an
/// unknown. Better still, key the floor to the document type the sweep already
/// knows — from the table above, a part floor of 256 KB, an assembly floor of
/// 8 MB and a drawing floor of 4 MB are each above the measured median. The same
/// table would strengthen `MIN_RECOVERY_BYTES`, which at 16 KB sits below the
/// smallest real document of EVERY type (29 KB, 95 KB, 320 KB).
#[test]
fn a_small_measured_document_never_lowers_the_guess_for_an_unknown_one() {
    let dir = std::env::temp_dir().join("adv24-estimate");
    let _ = std::fs::create_dir_all(&dir);
    let small = dir.join("small.SLDPRT");
    // The smallest real part measured in this container.
    std::fs::write(&small, vec![0u8; 29_130]).unwrap();

    // One unknown document, nothing measurable beside it.
    let alone = estimate_writes(&[String::new()]);
    // The same unknown document, beside one small measured one.
    let beside = estimate_writes(&[String::new(), small.to_string_lossy().to_string()]);

    let unknown_alone = alone.total;
    let unknown_beside = beside.total.saturating_sub(29_130);
    let _ = std::fs::remove_dir_all(&dir);

    assert!(
        unknown_beside >= unknown_alone,
        "the estimate for an UNKNOWN document fell from {unknown_alone} bytes to {unknown_beside} \
         bytes because a 29 KB part was measurable beside it. Knowing something small about the \
         session made the guess about the rest of it smaller. `estimate.largest` also gates the \
         per-save re-check, so this is the number that decides whether the next write is allowed \
         to start — and a pathless assembly costed at 58 KB against a 4.1 MB median is exactly \
         how a truncation the marker cannot detect gets through."
    );
}