main
Drew Owens 0.6.9 source: launch resilience, honest counts, ownership persistence, drain, quit ladder — 21 adversary passes, 303 te… cf16621 1mo ago
//! ADVERSARIAL REVIEW OF 0.5.6 — pass ten, the drain's close key and its window.
//!
//! The close key is fixed the right way: the victim is chosen by path and closed
//! BY THAT PATH, with a post-close verify through `GetOpenDocumentByName` — which
//! the SOLIDWORKS API documents as requiring a fully qualified path, so the
//! verify's key is correct. A victim whose title another SCANNED document shares
//! is refused and reported. `close_doc`/`reset_workspace` keep resolving by path
//! with `ambiguous_target` intact.
//!
//! What is not sound is the WINDOW. The drain walks a bounded window and then
//! reasons about the session as though it had seen all of it.
//!
//! Every #[test] here FAILS on 449bcfb.

mod common;

use common::{Bridge, TempDir};
use serde_json::{json, Value};

fn s(v: &Value) -> String {
    serde_json::to_string_pretty(v).unwrap_or_default()
}

/// A session of 60 documents: an import temp first, 58 ordinary saved parts, and
/// a SECOND import temp past the end of the walk window that `batch:5` produces
/// (`max*4` floored at `max+50` = 55).
fn session_with_a_temp_beyond_the_window(scratch: &TempDir) {
    let root = r"C:\Users\drew\AppData\Local\Temp";
    let mut docs: Vec<Value> = vec![json!({
        "docType": "part", "path": "untitled:t0", "title": "First.step.SLDPRT",
        "saved": false, "importTemp": true,
        "tempPath": format!("{root}\\swx107688\\IC~~\\First.step.SLDPRT")
    })];
    for i in 0..58 {
        docs.push(json!({
            "docType": "part", "path": format!("C:\\work\\P{i}.SLDPRT"),
            "title": format!("P{i}.SLDPRT"), "saved": true, "importTemp": false
        }));
    }
    docs.push(json!({
        "docType": "part", "path": "untitled:t60", "title": "Far.step.SLDPRT",
        "saved": false, "importTemp": true,
        "tempPath": format!("{root}\\swx107688\\IC~~\\Far.step.SLDPRT")
    }));
    std::fs::write(
        scratch.join("mock-solidworks-open-docs.json"),
        json!({"running": true, "untitled": 2, "active": "untitled:t0",
               "docs": docs, "files": {}})
        .to_string(),
    )
    .unwrap();
}

fn drain(scratch: &TempDir) -> (Bridge, Value) {
    let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[]);
    b.call("swx_start", json!({"reason": "draining"}));
    let r = b.call("swx_close_import_temps", json!({"reason": "draining leaked temps", "batch": 5}));
    (b, r)
}

/// `done` is computed from `hit_limit`, and `hit_limit` is seeded from
/// `walk_stop == WalkStop::TimedOut` ALONE:
///
/// ```text
/// let walk_timed_out = walk_stop == WalkStop::TimedOut;
/// let mut hit_limit = walk_timed_out;
/// ```
///
/// `WalkStop::HitMax` (the walk hit its scan cap without reaching the end) and
/// `WalkStop::IterationFailed` (a document closed mid-walk invalidated the
/// iteration) both leave `hit_limit` false. So when fewer than `max` victims are
/// found inside a window that did NOT reach the end of the session, the drain
/// reports `done:true` — with temps still open beyond the window.
///
/// `WalkStop::complete()` exists for exactly this and is not consulted here.
/// The evidence is already in the response: `documentsScanned` (55) against
/// `documentCountBefore` (60).
#[test]
fn done_is_never_true_when_the_walk_did_not_reach_the_end() {
    let scratch = TempDir::new("adv10-a");
    session_with_a_temp_beyond_the_window(&scratch);
    let (b, r) = drain(&scratch);

    let scanned = r["documentsScanned"].as_u64().unwrap_or(0);
    let before = r["documentCountBefore"].as_u64().unwrap_or(0);
    assert!(
        scanned > 0 && before > scanned,
        "precondition: the walk covered {scanned} of {before} documents: {}",
        s(&r)
    );
    assert!(
        r["done"] != true,
        "the drain reported done:true having scanned only {scanned} of {before} open documents. \
         `hit_limit` is seeded from WalkStop::TimedOut alone, so a walk that stopped at its scan \
         cap (HitMax) or on an invalidated iteration (IterationFailed) is treated as one that \
         reached the end. WalkStop::complete() is defined for this and is not used in the `done` \
         computation, and the two numbers that settle it are already in this response.\n{}\n\
         --- server log ---\n{}",
        s(&r),
        b.log()
    );
}

/// The collision check compares each victim's title against `seen` — the walked
/// WINDOW — so a same-titled document outside it is invisible. That is safe for
/// the CLOSE (the path is the key), but the report then says `titleCollisions: []`
/// as though it had looked at the session. It has not, and the drain must say the
/// check was window-limited: `walkStop` is computed and named
/// (`WalkStop::name()`) and never published, so a caller cannot tell
/// `reachedEnd` from `hitMax` from `iterationFailed`.
#[test]
fn the_report_says_how_far_the_walk_got_and_what_that_limits() {
    let scratch = TempDir::new("adv10-b");
    session_with_a_temp_beyond_the_window(&scratch);
    let (_b, r) = drain(&scratch);
    assert!(
        !r["walkStop"].is_null(),
        "the four-state WalkStop is computed and named inside the host and never reaches the \
         caller, so `titleCollisions: []` and `done` cannot be interpreted: a collision check over \
         55 of 60 documents is not the same claim as one over the session.\n{}",
        s(&r)
    );
}

/// MOCK FIDELITY, and it is why the 257 green tests say nothing about any of the
/// above. The real backend selects victims from the WALKED WINDOW; the mock
/// selects them with `self.docs.iter().filter(is_temp).take(max)` over the WHOLE
/// session, and its collision check iterates the whole session too. Measured on
/// the fixture above: `documentsScanned: 55`, `closed: 2` — the mock closed a
/// document its own reported scan window never reached.
///
/// So the mock proves the close KEY (which is what 0.5.6 fixed) and cannot prove
/// anything about the window: not the collision check's blind spot, not `done`,
/// not `importTempsElsewhere`'s coverage.
#[test]
fn the_mock_only_closes_documents_it_actually_walked() {
    let scratch = TempDir::new("adv10-c");
    session_with_a_temp_beyond_the_window(&scratch);
    let (_b, r) = drain(&scratch);
    let scanned = r["documentsScanned"].as_u64().unwrap_or(0);
    let closed = r["closed"].as_u64().unwrap_or(0);
    // The far temp is the 60th document; a window of 55 cannot have reached it,
    // so a faithful backend closes exactly one.
    assert!(
        closed <= 1,
        "the mock closed {closed} temporaries while reporting documentsScanned:{scanned} — one of \
         them sits at document 60, outside the window it says it walked. Victim selection and the \
         collision check are not window-bounded in the mock, so every window property the real \
         backend has is untested.\n{}",
        s(&r)
    );
}