main
Drew Owens 0.10.7 source e6a7431 6d ago
//! MEMORY (0.10.5) — the incident of 2026-10-14, and what the bridge now does
//! about it.
//!
//! MEASURED on adom_drew2: the SOLIDWORKS Resource Monitor warned "Available
//! committed memory is critically low" at 72.3 of 76.6 GB committed, 4.2 GB
//! available. Fusion 360 held 20.7 GB (the user's), the bridge-started
//! SOLIDWORKS 10.6 GB with zero documents open, Chrome 10.2 GB over 51
//! processes. Quitting that SOLIDWORKS returned about 16 GB.
//!
//! Everything here runs in the SIMULATOR (`memory.json` in the simulated
//! machine): the numbers are the measured ones, the behaviour is the bridge's.

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()
}

/// The machine on 2026-10-14 (MB): the commit pair, and the holders other than
/// SOLIDWORKS (which the simulator adds from `sldworks.json`).
fn incident(avail_mb: u64) -> Value {
    let mut procs = vec![
        json!({"name": "Fusion360.exe", "pid": 41000, "privateMB": 21197}),
        json!({"name": "vmmemWSL", "pid": 41500, "privateMB": 4812}),
    ];
    for i in 0..3 {
        procs.push(json!({"name": "chrome.exe", "pid": 42000 + i, "privateMB": 3400}));
    }
    json!({"commitLimitMB": 78438, "commitAvailMB": avail_mb, "physTotalMB": 32153, "physAvailMB": 3000, "processes": procs})
}

struct Machine {
    dir: TempDir,
}

impl Machine {
    fn new(tag: &str, memory: Value, sw_private_mb: u64) -> Machine {
        let dir = TempDir::new(tag);
        std::fs::write(dir.join("windows.json"), "[]").unwrap();
        std::fs::write(dir.join("memory.json"), memory.to_string()).unwrap();
        std::fs::write(
            dir.join("sldworks.json"),
            json!({"responding": true, "hwnd": 6622700, "privateMB": sw_private_mb, "handles": 4000}).to_string(),
        )
        .unwrap();
        Machine { dir }
    }

    fn env(&self) -> Vec<(&'static str, &'static str)> {
        vec![
            ("SWX_LAUNCH_FAKE_DIR", Box::leak(self.dir.path().into_boxed_str())),
            ("SWX_QUIT_SETTLE_MS", "80"),
            ("SWX_QUIT_EXIT_WAIT_SECS", "3"),
            ("SWX_RECYCLE_POLL_MS", "100"),
            ("SWX_RECYCLE_READY_SECS", "30"),
        ]
    }

    fn boot(&self) -> Bridge {
        Bridge::start_with(&self.env())
    }

    /// A SOLIDWORKS session THIS BRIDGE LAUNCHED: the launch record's claim
    /// names the very process the simulator runs (pid AND creation time).
    fn boot_as_bridge_started(&self, quit_script: Value) -> Bridge {
        std::fs::write(self.dir.join("quit-script.json"), quit_script.to_string()).unwrap();
        std::fs::write(self.dir.join("sldworks-created"), "1700000000").unwrap();
        let scratch = TempDir::new("memory-scratch");
        std::fs::write(scratch.join("mock-solidworks-session"), "700900").unwrap();
        std::fs::write(
            scratch.join("launch-state.json"),
            json!({
                "attempt": {
                    "id": 1, "startedAt": 1700000000u64, "shortcut": "x.lnk",
                    "route": "shellExecute", "invokedAt": 1700000000u64,
                    "stage": "attached", "finished": true, "outcome": "attached",
                    "runBeginSeen": true,
                    "attributedSolidworks": {"pid": 700900, "createdAt": 1700000000u64},
                },
                "preferredRoute": "shellExecute", "consecutiveFailures": 0,
            })
            .to_string(),
        )
        .unwrap();
        Bridge::start_in(scratch, &self.env())
    }

    fn quit_happened(&self) -> bool {
        self.dir.join("quit.jsonl").exists()
    }

    /// NOTHING WAS EVER KILLED: the simulator records every terminate.
    fn nothing_terminated(&self) -> bool {
        !self.dir.join("terminated.jsonl").exists()
    }
}

fn doc_count(b: &Bridge) -> usize {
    b.call("swx_docs", json!({}))["docs"].as_array().map(|a| a.len()).unwrap_or(usize::MAX)
}

fn ledger(b: &Bridge) -> Vec<Value> {
    b.call("swx_action_ledger", json!({"limit": 500}))["actions"].as_array().cloned().unwrap_or_default()
}

#[test]
fn status_reports_the_commit_charge_and_the_largest_holders() {
    let m = Machine::new("mem-status", incident(4300), 10854);
    let b = m.boot();
    b.call("swx_start", json!({}));
    let r = b.call("swx_status", json!({}));
    let mem = &r["memory"];
    check!(
        b,
        "swx_status.memory: the commit pair, as GlobalMemoryStatusEx gives it (simulated)",
        mem["commitLimitMb"] == 78438 && mem["commitAvailableMb"] == 4300 && mem["commitUsedMb"] == 78438 - 4300
            && mem["commitUsedPercent"] == 94.5,
        s(mem)
    );
    check!(
        b,
        "SOLIDWORKS's own share, the 6 GB default budget, and CRITICAL pressure",
        mem["solidworks"]["privateMb"] == 10854 && mem["solidworks"]["overBudget"] == true
            && mem["sessionBudgetMb"] == 6144 && mem["pressure"] == "critical",
        s(mem)
    );
    check!(
        b,
        "the top holders, per process and per application, Fusion first",
        mem["topProcesses"][0]["name"] == "Fusion360.exe" && mem["topProcesses"].as_array().map(|a| a.len()) == Some(5)
            && mem["topImages"].as_array().unwrap().iter().any(|i| i["name"] == "chrome.exe" && i["processes"] == 3),
        s(mem)
    );
    check!(
        b,
        "every reply's _hint names the largest holders while pressure is not ok",
        r["_hint"].as_str().unwrap_or("").contains("MEMORY CRITICAL")
            && b.call("swx_docs", json!({}))["_hint"].as_str().unwrap_or("").contains("Fusion360.exe 20.7 GB"),
        s(&r["_hint"])
    );
    check!(b, "the one log line per verb carries the memory sample", b.log().contains("| mem: commit available 4.2 GB"), "log");
    check!(b, "read-only: nothing was terminated", m.nothing_terminated(), "terminated.jsonl exists");
}

#[test]
fn critical_memory_refuses_geometry_and_changes_nothing() {
    let m = Machine::new("mem-guard", incident(4300), 2000);
    let b = m.boot();
    b.call("swx_start", json!({}));
    let before = doc_count(&b);
    let r = b.call("swx_new_document", json!({"type": "part"}));
    check!(
        b,
        "swx_new_document is refused low_commit_memory, with the numbers and the holders",
        r["success"] == false && r["errorCode"] == "low_commit_memory" && r["changedNothing"] == true
            && r["error"].as_str().unwrap_or("").contains("4.2 GB available")
            && r["largestHolders"].as_str().unwrap_or("").starts_with("Fusion360.exe 20.7 GB"),
        s(&r)
    );
    check!(
        b,
        "not the bridge's session: the remedy is to tell the user, never to close anything",
        r["remedy"].as_str().unwrap_or("").contains("Tell the user") && r["remedy"].as_str().unwrap_or("").contains("Never close them")
            && !r["remedy"].as_str().unwrap_or("").contains("swx_stop"),
        s(&r)
    );
    check!(b, "...and nothing was created", doc_count(&b) == before, format!("{before} -> {}", doc_count(&b)));
    let script = json!([{"op": "new_part"}, {"op": "sketch_rect", "plane": "Top Plane", "widthMm": 10, "heightMm": 10}, {"op": "extrude", "depthMm": 5}]);
    let r = b.call("swx_run_script", json!({"script": script}));
    check!(b, "a script that makes a new part is refused too, and creates nothing", r["errorCode"] == "low_commit_memory" && doc_count(&b) == before, s(&r));
    for (verb, args) in [
        ("swx_open", json!({"path": "C:\\designs\\x.sldprt"})),
        ("swx_import", json!({"path": "C:\\designs\\x.step"})),
        ("swx_render_image", json!({"width": 100, "height": 100})),
        ("swx_show_part", json!({})),
        ("swx_selftest", json!({"level": "write"})),
    ] {
        let r = b.call(verb, args);
        check!(b, &format!("{verb} is refused at critical"), r["errorCode"] == "low_commit_memory", s(&r));
    }
    let r = b.call("swx_selftest", json!({"level": "read"}));
    check!(b, "a read-only self-test is not refused", r["errorCode"] != "low_commit_memory" && r["success"] == true, s(&r["summary"]));
    let r = b.call("swx_new_document", json!({"type": "part", "ignoreMemoryPressure": true}));
    check!(
        b,
        "an override without a reason is still refused",
        r["errorCode"] == "low_commit_memory" && r["error"].as_str().unwrap_or("").contains("needs a reason"),
        s(&r)
    );
    let r = b.call("swx_new_document", json!({"type": "part", "ignoreMemoryPressure": true, "reason": "Drew said build it anyway"}));
    check!(
        b,
        "ignoreMemoryPressure with a reason runs it, and the reply says so",
        r["success"] == true && r["memoryOverride"]["overridden"] == true && doc_count(&b) == before + 1,
        s(&r)
    );
    let l = ledger(&b);
    check!(
        b,
        "the override and the refusals are in the ledger, each line with its memory sample",
        l.iter().any(|e| e["action"] == "memory_guard_overridden" && e["detail"]["reason"] == "Drew said build it anyway")
            && l.iter().any(|e| e["action"] == "memory_guard_refused" && e["mem"]["commitAvailMb"] == 4300),
        s(&json!(l))
    );
    check!(b, "nothing was quit or terminated", !m.quit_happened() && m.nothing_terminated(), "quit.jsonl / terminated.jsonl");
}

#[test]
fn high_memory_proceeds_and_warns() {
    // 12 % available: high, not critical.
    let m = Machine::new("mem-high", incident(9400), 2000);
    let b = m.boot();
    b.call("swx_start", json!({}));
    let r = b.call("swx_new_document", json!({"type": "part"}));
    check!(
        b,
        "high pressure: the document is made, and the _hint warns with the holders",
        r["success"] == true && r["_hint"].as_str().unwrap_or("").contains("MEMORY HIGH")
            && r["memoryPressure"]["pressure"] == "high",
        s(&r)
    );
}

#[test]
fn the_remedy_for_the_bridges_own_empty_session_is_stop_then_start() {
    let m = Machine::new("mem-ours", incident(4300), 10854);
    let b = m.boot_as_bridge_started(json!({"a": "exited"}));
    b.call("swx_start", json!({}));
    let r = b.call("swx_new_document", json!({"type": "part"}));
    check!(
        b,
        "a session the bridge started, with no documents open: swx_stop then swx_start frees about 10.6 GB",
        r["errorCode"] == "low_commit_memory" && r["solidworksSession"]["bridgeStarted"] == true
            && r["solidworksSession"]["openDocuments"] == 0
            && r["remedy"].as_str().unwrap_or("").contains("swx_stop")
            && r["remedy"].as_str().unwrap_or("").contains("frees about 10.6 GB"),
        s(&r)
    );
    check!(b, "the guard itself never quits anything", !m.quit_happened() && m.nothing_terminated(), "quit.jsonl / terminated.jsonl");
}

#[test]
fn a_long_selftest_stops_rather_than_end_a_session_that_is_not_its_own() {
    // Commit is fine; SOLIDWORKS is over its 6 GB budget; the session is NOT
    // the bridge's.
    let m = Machine::new("mem-stop", incident(40000), 9000);
    let b = m.boot();
    b.call("swx_start", json!({}));
    let r = b.call("swx_selftest", json!({"level": "write", "only": ["T01", "T03"]}));
    let rows = r["results"].as_array().cloned().unwrap_or_default();
    check!(
        b,
        "the run STOPS for memory before its first check, with a full report of what ran",
        r["success"] == true && r["stoppedFor"] == "memory" && r["complete"] == false
            && r["stopped"]["beforeCheck"] == "T01"
            && r["stopped"]["why"].as_str().unwrap_or("").contains("not started by the bridge")
            && !rows.iter().any(|x| x["name"].as_str().unwrap_or("").starts_with("T0")),
        s(&r)
    );
    check!(b, "the reply's hint leads with the stop", r["_hint"].as_str().unwrap_or("").starts_with("THE RUN STOPPED FOR MEMORY"), s(&r["_hint"]));
    check!(
        b,
        "it never tried to end the user's session: no quit, no swx_stop attempt, nothing terminated",
        !m.quit_happened() && m.nothing_terminated()
            && !ledger(&b).iter().any(|e| e["action"] == "solidworks_quit_refused" || e["action"] == "solidworks_recycled"),
        s(&json!(ledger(&b)))
    );
}

#[test]
fn a_long_selftest_with_a_document_open_stops_even_in_its_own_session() {
    let m = Machine::new("mem-busy", incident(40000), 9000);
    let b = m.boot_as_bridge_started(json!({"a": "exited"}));
    b.call("swx_start", json!({}));
    b.call("swx_new_document", json!({"type": "part"}));
    let r = b.call("swx_selftest", json!({"level": "write", "only": ["T01"]}));
    check!(
        b,
        "a document is open: no recycle, the run stops and says why",
        r["stoppedFor"] == "memory" && r["stopped"]["why"].as_str().unwrap_or("").contains("1 document(s) are open")
            && r["recycled"] == json!([]),
        s(&r)
    );
    check!(b, "...and nothing was quit or terminated", !m.quit_happened() && m.nothing_terminated(), "quit.jsonl / terminated.jsonl");
}

#[test]
fn a_long_selftest_recycles_its_own_empty_session_and_carries_on() {
    // SOLIDWORKS over budget in a session the bridge started, nothing open.
    // After the quit the simulator's commit recovers (afterQuit).
    let mut mem = incident(40000);
    mem["afterQuit"] = json!({"commitAvailMB": 52000});
    let m = Machine::new("mem-recycle", mem, 9000);
    let b = m.boot_as_bridge_started(json!({"a": "exited"}));
    b.call("swx_start", json!({}));
    let r = b.call("swx_selftest", json!({"level": "write", "only": ["T01", "T03"]}));
    let rec = r["recycled"].as_array().cloned().unwrap_or_default();
    check!(
        b,
        "ONE recycle, before the first check, with what it freed",
        rec.len() == 1 && rec[0]["beforeCheck"] == "T01" && rec[0]["afterCheck"].is_null()
            && rec[0]["freedMb"] == 12000 && rec[0]["solidworksPrivateMbBefore"] == 9000,
        s(&r)
    );
    let rows = r["results"].as_array().cloned().unwrap_or_default();
    let t01 = rows.iter().find(|x| x["name"].as_str().unwrap_or("").starts_with("T01")).cloned().unwrap_or(Value::Null);
    check!(
        b,
        "the run carried on and completed, each check row carrying swPrivateMbAfter",
        r["complete"] == true && r.get("stoppedFor").is_none() && t01["pass"] == true
            && r["_hint"].as_str().unwrap_or("").contains("recycled the bridge's own SOLIDWORKS session once")
            && t01.as_object().map(|o| o.contains_key("swPrivateMbAfter")).unwrap_or(false),
        s(&r)
    );
    check!(
        b,
        "the recycle went through swx_stop (a quit happened, ledgered) and never killed anything",
        m.quit_happened() && m.nothing_terminated() && ledger(&b).iter().any(|e| e["action"] == "solidworks_recycled"),
        s(&json!(ledger(&b)))
    );
}

#[test]
fn a_recycle_that_cannot_quit_stops_the_run_and_says_where() {
    // The bridge's own empty session, but SOLIDWORKS declines ExitApp (rung a),
    // and the ladder is pinned at rung a: the quit does not happen.
    let m = Machine::new("mem-declined", incident(40000), 9000);
    let b = m.boot_as_bridge_started(json!({"a": "declined"}));
    b.call("swx_start", json!({}));
    let r = b.call("swx_selftest", json!({"level": "write", "only": ["T01"]}));
    check!(
        b,
        "swx_stop did not stop it: the run stops for memory at the recycle, naming swx_stop and its answer",
        r["stoppedFor"] == "memory" && r["stopped"]["recycleFailedAt"] == "swx_stop"
            && r["stopped"]["detail"]["stopped"] != true && r["recycled"] == json!([])
            && !r["results"].as_array().map(|a| a.iter().any(|x| x["name"].as_str().unwrap_or("").starts_with("T01"))).unwrap_or(true),
        s(&r)
    );
    check!(b, "...and nothing was terminated", m.nothing_terminated(), "terminated.jsonl exists");
}

/// ATTRIBUTION ON THE CONNECTED EDITION (0.10.7), with the measured numbers:
/// the launch's root was pid 53900 (created 1792014529, startProcessPassThru),
/// sldworks.exe came up as pid 70644 (created 1792014533) with ppid 40520 — the
/// chain re-parents, so no parent walk reaches the root, and 0.10.6 left
/// `attributedSolidworks` null and `bridgeStarted:false` for a session it had
/// launched four seconds earlier. The ONE new sldworks.exe of the launch window
/// is now the bridge's.
#[test]
fn a_launch_whose_chain_reparents_still_owns_the_solidworks_it_started() {
    let m = Machine::new("mem-attrib", incident(4300), 10854);
    std::fs::write(m.dir.join("sldworks-created"), "1792014533").unwrap();
    std::fs::write(m.dir.join("sldworks-parent"), "40520").unwrap();
    let scratch = TempDir::new("mem-attrib-scratch");
    std::fs::write(scratch.join("mock-solidworks-session"), "70644").unwrap();
    std::fs::write(
        scratch.join("launch-state.json"),
        json!({
            "attempt": {
                "id": 7, "startedAt": 1792014520u64, "shortcut": "SOLIDWORKS.lnk", "route": "startProcess",
                "invokedAt": 1792014528u64, "stage": "attached", "stageAt": 1792014611u64, "finished": true,
                "outcome": "attached", "runBeginSeen": true, "baselineKnown": true, "baselinePids": [6076, 90552],
                "attribution": {"pid": 53900, "createdAt": 1792014529u64, "source": "startProcessPassThru"},
            },
            "preferredRoute": "startProcess", "consecutiveFailures": 0,
        })
        .to_string(),
    )
    .unwrap();
    let b = Bridge::start_in(scratch, &m.env());
    b.call("swx_start", json!({}));
    let st = b.call("swx_status", json!({}));
    let claim = st.pointer("/launch/attributedSolidworks").cloned().unwrap_or(Value::Null);
    check!(
        b,
        "swx_status: the launch now names its SOLIDWORKS — the one new sldworks.exe of the launch window",
        claim == json!({"pid": 70644, "createdAt": 1792014533u64, "how": "newProcessInLaunchWindow"}),
        s(&st["launch"])
    );
    check!(
        b,
        "...ledgered with how it was decided",
        ledger(&b).iter().any(|e| e["action"] == "solidworks_attributed" && e["detail"]["how"] == "newProcessInLaunchWindow"),
        s(&json!(ledger(&b)))
    );
    let r = b.call("swx_new_document", json!({"type": "part"}));
    check!(
        b,
        "so the memory guard knows the session is the bridge's (recyclable when empty)",
        r["errorCode"] == "low_commit_memory" && r["solidworksSession"]["bridgeStarted"] == true
            && r["remedy"].as_str().unwrap_or("").contains("swx_stop"),
        s(&r)
    );
}

/// THE WINDOW CLOSES AT THE ATTACH: a SOLIDWORKS created AFTER the launch
/// attached (the user's own, started later) is never the launch's, however new
/// it is to the record.
#[test]
fn a_solidworks_started_after_the_attach_is_never_claimed() {
    let m = Machine::new("mem-attrib-late", incident(40000), 900);
    std::fs::write(m.dir.join("sldworks-created"), "1792014700").unwrap();
    std::fs::write(m.dir.join("sldworks-parent"), "40520").unwrap();
    let scratch = TempDir::new("mem-attrib-late-scratch");
    std::fs::write(scratch.join("mock-solidworks-session"), "70644").unwrap();
    std::fs::write(
        scratch.join("launch-state.json"),
        json!({
            "attempt": {
                "id": 8, "startedAt": 1792014520u64, "shortcut": "SOLIDWORKS.lnk", "route": "startProcess",
                "invokedAt": 1792014528u64, "stage": "attached", "stageAt": 1792014611u64, "finished": true,
                "outcome": "attached", "runBeginSeen": true, "baselineKnown": true, "baselinePids": [6076],
                "attribution": {"pid": 53900, "createdAt": 1792014529u64, "source": "startProcessPassThru"},
            },
            "preferredRoute": "startProcess", "consecutiveFailures": 0,
        })
        .to_string(),
    )
    .unwrap();
    let b = Bridge::start_in(scratch, &m.env());
    b.call("swx_start", json!({}));
    let st = b.call("swx_status", json!({}));
    check!(
        b,
        "swx_status: a sldworks.exe created after the attach is NOT claimed, and the refusal is ledgered",
        st.pointer("/launch/attributedSolidworks").map(|v| v.is_null()).unwrap_or(true)
            && ledger(&b).iter().any(|e| e["action"] == "solidworks_attribution_refused"),
        s(&st["launch"])
    );
}