app
SOLIDWORKS Bridge
Public Made by Adomby adom
Launch, model and quit SOLIDWORKS from any Adom container. Nothing is ever lost.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
//! 0.10.6 — FIXING THE MEMORY GROWTH AT ITS ROOT.
//!
//! MEASURED 2026-10-14 (~21:00Z, hosted 0.10.5, SOLIDWORKS 2026 fresh start,
//! 12 x [new_part + a 20x20x10 box] then swx_reset_workspace): SOLIDWORKS's
//! private bytes went 520 MB -> 913 -> 1191 -> then +83 MB per part to 2035 MB;
//! handles 2845 -> 4539, +~125 per part; GetDocumentCount back at 0 every time.
//! So every created-and-closed document cost ~83 MB and ~125 handles for good.
//!
//! 0.10.6 tried HIDDEN documents (ISldWorks::DocumentVisible around
//! NewDocument) and ONE reused part (clear_part). MEASURED LIVE (0.10.7's
//! brief): a hidden document cannot be modelled — SOLIDWORKS selects only in
//! the active document and a hidden one cannot be activated — while twelve
//! builds in one reused, VISIBLE part left SOLIDWORKS flat. So 0.10.7 makes
//! everything visible by default, refuses to model a hidden document up front
//! (`document_hidden`), and runs batteries in one reused part.
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()
}
fn boot(tag: &str, extra: &[(&str, &str)]) -> (Bridge, TempDir) {
let machine = TempDir::new(tag);
std::fs::write(machine.join("windows.json"), "[]").unwrap();
let mut env: Vec<(&str, &str)> = vec![("SWX_LAUNCH_FAKE_DIR", Box::leak(machine.path().into_boxed_str()))];
env.extend_from_slice(extra);
let b = Bridge::start_with(&env);
(b, machine)
}
/// Every ISldWorks::DocumentVisible call the simulator saw, in order.
fn visible_calls(b: &Bridge) -> Vec<Value> {
std::fs::read_to_string(b.scratch.join("document-visible.jsonl"))
.unwrap_or_default()
.lines()
.filter_map(|l| serde_json::from_str(l).ok())
.collect()
}
fn ledger(b: &Bridge) -> Vec<Value> {
b.call("swx_action_ledger", json!({"limit": 500}))["actions"].as_array().cloned().unwrap_or_default()
}
fn doc_count(b: &Bridge) -> usize {
b.call("swx_docs", json!({}))["docs"].as_array().map(|a| a.len()).unwrap_or(usize::MAX)
}
fn box_script(first: Value) -> Value {
json!([first,
{"op": "sketch_rect", "plane": "Top Plane", "widthMm": 20, "heightMm": 20, "anchor": "center"},
{"op": "extrude", "depthMm": 10}])
}
#[test]
fn a_hidden_creation_that_fails_still_puts_the_setting_back() {
let (b, _m) = boot("vis-fail", &[]);
b.call("swx_start", json!({}));
std::fs::write(b.scratch.join("mock-newdoc-fails"), "").unwrap();
let r = b.call("swx_new_document", json!({"type": "part", "visible": false}));
let calls = visible_calls(&b);
check!(
b,
"NewDocument failed inside the bracket: an error — and DocumentVisible was put back anyway",
r["success"] == false && r["visibility"]["documentVisibleRestored"] == true
&& calls.len() == 2 && calls[0]["visible"] == false && calls[1]["visible"] == true,
format!("{}\n{}", s(&r), s(&json!(calls)))
);
std::fs::remove_file(b.scratch.join("mock-newdoc-fails")).unwrap();
let v = b.call("swx_new_document", json!({"type": "part"}));
let shown = b.call("swx_show_part", json!({"path": v["documentIdentity"]["path"]}));
check!(
b,
"...so the next ordinary document is VISIBLE",
v["success"] == true && shown["visibility"]["wasVisible"] == true,
format!("{}\n{}", s(&v), s(&shown))
);
}
#[test]
fn a_setting_the_host_could_not_put_back_is_retried_and_otherwise_shouted() {
let (b, _m) = boot("vis-retry", &[]);
b.call("swx_start", json!({}));
// The host's three restores fail; the server's second chance works.
std::fs::write(b.scratch.join("mock-docvisible-restore-fails"), "").unwrap();
let r = b.call("swx_new_document", json!({"type": "part", "visible": false}));
check!(
b,
"the server retried the restore, it worked, and the retry is ledgered",
r["success"] == true && r["visibility"]["serverRetry"]["restored"] == true
&& r["visibility"]["documentVisibleRestored"] == true
&& ledger(&b).iter().any(|e| e["action"] == "document_visible_restored_on_retry"),
s(&r)
);
std::fs::write(b.scratch.join("mock-docvisible-restore-fails-always"), "").unwrap();
let r = b.call("swx_new_document", json!({"type": "part", "visible": false}));
check!(
b,
"a restore that cannot be done is a WARNING to tell the user, and ledgered",
r["visibility"]["documentVisibleRestored"] == false
&& r["visibility"]["warning"].as_str().unwrap_or("").contains("INVISIBLE")
&& ledger(&b).iter().any(|e| e["action"] == "document_visible_restore_failed"),
s(&r)
);
}
#[test]
fn com_respawn_replaces_only_the_bridges_host_and_never_calls_solidworks() {
let (b, _m) = boot("vis-respawn", &[("SWX_MOCK_SLOW_MS", "2500")]);
b.call("swx_start", json!({}));
b.call("swx_new_document", json!({"type": "part"}));
let before = b.call("swx_status", json!({}));
let docs = doc_count(&b);
let r = b.call("swx_com_respawn", json!({}));
check!(b, "swx_com_respawn needs a reason", r["errorCode"] == "reason_required", s(&r));
std::fs::write(b.scratch.join("mock-log-commands"), "").unwrap();
let r = b.call("swx_com_respawn", json!({"reason": "measure handles before and after"}));
let reached = std::fs::read_to_string(b.scratch.join("mock-commands.log")).unwrap_or_default();
check!(
b,
"swx_com_respawn: a new host, the old one left gracefully, and NOTHING reached SOLIDWORKS",
r["success"] == true && r["respawned"] == true && r["solidworksTouched"] == false && r["gracefulExit"] == true
&& r["oldHostPid"] == before["com"]["hostPid"] && r["newHostPid"] != r["oldHostPid"]
&& reached.trim().is_empty(),
format!("{}\nreached SOLIDWORKS: {reached:?}", s(&r))
);
let after = b.call("swx_status", json!({}));
check!(
b,
"...the same SOLIDWORKS session with the same documents, now served by the new host; ledgered",
after["com"]["hostPid"] == r["newHostPid"] && after["com"]["processId"] == before["com"]["processId"]
&& doc_count(&b) == docs
&& ledger(&b).iter().any(|e| e["action"] == "com_host_respawn" && e["detail"]["reason"] == "measure handles before and after"),
format!("{}\n{}", s(&before["com"]), s(&after["com"]))
);
// MID-VERB: a slow verb holds the host; the respawn refuses.
let refused = std::thread::scope(|sc| {
let slow = sc.spawn(|| b.call("swx_start", json!({})));
std::thread::sleep(std::time::Duration::from_millis(700));
let r = b.call("swx_com_respawn", json!({"reason": "while a verb is running"}));
let _ = slow.join();
r
});
check!(
b,
"swx_com_respawn while a verb holds the host: refused com_host_busy, naming the verb, nothing changed",
refused["errorCode"] == "com_host_busy" && refused["error"].as_str().unwrap_or("").contains("(start)"),
s(&refused)
);
}
/// THE MEASURED GROWTH, SIMULATED: every created document leaves SOLIDWORKS
/// 83 MB heavier (`growthPerDocumentMB`). A reused check creates nothing, so
/// it costs nothing; and when the budget is reached mid-battery, the run
/// closes its own shared part FIRST, so its bridge-started session can be
/// recycled (an open document would stop the run instead).
#[test]
fn reuse_keeps_solidworks_flat_and_the_shared_part_is_closed_before_a_recycle() {
let machine = TempDir::new("vis-growth");
std::fs::write(machine.join("windows.json"), "[]").unwrap();
std::fs::write(machine.join("quit-script.json"), json!({"a": "exited"}).to_string()).unwrap();
std::fs::write(machine.join("sldworks-created"), "1700000000").unwrap();
std::fs::write(
machine.join("sldworks.json"),
json!({"responding": true, "hwnd": 6622700, "privateMB": 520, "growthPerDocumentMB": 83, "handles": 2845}).to_string(),
)
.unwrap();
std::fs::write(
machine.join("memory.json"),
json!({"commitLimitMB": 78438, "commitAvailMB": 40000, "physTotalMB": 32153, "physAvailMB": 9000, "processes": []}).to_string(),
)
.unwrap();
let scratch = TempDir::new("vis-growth-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();
let b = Bridge::start_in(
scratch,
&[
("SWX_LAUNCH_FAKE_DIR", Box::leak(machine.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"),
// 600 MB: the shared part (one document, 603 MB) already passes it.
("SWX_SW_MEMORY_BUDGET_MB", "600"),
],
);
b.call("swx_start", json!({}));
let r = b.call("swx_selftest", json!({"level": "write", "only": ["T01", "T03", "T05"]}));
let rows = r["results"].as_array().cloned().unwrap_or_default();
let row = |id: &str| rows.iter().find(|x| x["name"].as_str().unwrap_or("").starts_with(id)).cloned().unwrap_or(Value::Null);
let rec = r["recycled"].as_array().cloned().unwrap_or_default();
check!(
b,
"after T01 built the shared part (603 MB > 600), the run CLOSED its own part and recycled before T03 — it did not stop",
r["complete"] == true && rec.len() == 1 && rec[0]["beforeCheck"] == "T03" && rec[0]["solidworksPrivateMbBefore"] == 603,
s(&r)
);
check!(
b,
"every check passed, T01 in the first shared part and T03/T05 in a new one",
r["summary"]["failed"] == 0 && row("T01")["swPrivateMbAfter"] == 603
&& row("T03")["reusedDocument"] == true && row("T05")["reusedDocument"] == true,
s(&json!(rows))
);
check!(b, "nothing was terminated", !machine.join("terminated.jsonl").exists(), "terminated.jsonl");
}
#[test]
fn a_hidden_document_is_bracketed_but_cannot_be_modelled() {
let (b, _m) = boot("vis-hidden", &[]);
b.call("swx_start", json!({}));
let r = b.call("swx_new_document", json!({"type": "part", "visible": false}));
check!(
b,
"swx_new_document visible:false: created hidden, DocumentVisible put back, a scratch file of its own",
r["success"] == true && r["visibility"]["documentVisibleRestored"] == true
&& r["visibility"]["visibleReadBack"] == false && r["visibility"]["scratchSaved"] == true
&& r["_hint"].as_str().unwrap_or("").contains("CANNOT BE MODELLED"),
s(&r)
);
let calls = visible_calls(&b);
check!(
b,
"DocumentVisible(false), then DocumentVisible(true), and ledgered",
calls.len() == 2 && calls[0]["visible"] == false && calls[1]["visible"] == true
&& ledger(&b).iter().any(|e| e["action"] == "document_visible_toggled"),
s(&json!(calls))
);
let path = r["documentIdentity"]["path"].as_str().unwrap_or("").to_string();
let built = b.call("swx_run_script", json!({"path": path, "script": [
{"op": "sketch_rect", "plane": "Top Plane", "widthMm": 20, "heightMm": 20, "anchor": "center"},
{"op": "extrude", "depthMm": 10}]}));
let ib = b.call("swx_inspect_bodies", json!({"path": path}));
check!(
b,
"modelling it is refused UP FRONT (document_hidden), naming why — nothing was built",
built["errorCode"] == "document_hidden"
&& built["error"].as_str().unwrap_or("").contains("cannot be activated")
&& ib["bodyCount"] == 0,
format!("{}\n{}", s(&built), s(&ib))
);
let prop = b.call("swx_run_script", json!({"path": path, "script": [{"op": "set_prop", "name": "Kind", "value": "hidden"}]}));
let out = b.scratch.join("hidden.step");
let ex = b.call("swx_export_step", json!({"path": path, "outputPath": out.to_string_lossy()}));
check!(b, "what selects nothing still works on it: a property, an export", prop["success"] == true && ex["success"] == true, format!("{}\n{}", s(&prop), s(&ex)));
let shown = b.call("swx_show_part", json!({"path": path}));
check!(
b,
"swx_show_part on it: attempted, read back, and SAID to stay hidden",
shown["visibility"]["madeVisible"] == false && shown["visibility"]["note"].as_str().unwrap_or("").contains("cannot be made visible"),
s(&shown)
);
let v = b.call("swx_new_document", json!({"type": "part"}));
check!(
b,
"swx_new_document with no visible: a visible document, and no DocumentVisible call at all",
v["success"] == true && v.get("visibility").is_none() && visible_calls(&b).len() == 2,
s(&v)
);
}
#[test]
fn a_script_is_visible_by_default_and_a_hidden_part_is_never_modelled() {
let (b, _m) = boot("vis-script", &[]);
b.call("swx_start", json!({}));
let r = b.call("swx_run_script", json!({"script": box_script(json!({"op": "new_part"}))}));
check!(
b,
"new_part with no visible: visible, and no DocumentVisible call (Michael wants to see his part)",
r["success"] == true && r["steps"][0]["result"].get("visibility").is_none() && visible_calls(&b).is_empty(),
s(&r)
);
let docs = doc_count(&b);
let r = b.call("swx_run_script", json!({"script": box_script(json!({"op": "new_part", "visible": false}))}));
check!(
b,
"new_part visible:false then a sketch: refused document_hidden BEFORE anything ran — no part made, no setting touched",
r["errorCode"] == "document_hidden" && r["error"].as_str().unwrap_or("").contains("step 2 (sketch_rect)")
&& r["_hint"].as_str().unwrap_or("").starts_with("Nothing was run")
&& doc_count(&b) == docs && visible_calls(&b).is_empty(),
s(&r)
);
let r = b.call("swx_run_script", json!({"script": [{"op": "new_part", "visible": false}, {"op": "set_prop", "name": "Kind", "value": "hidden"}]}));
check!(
b,
"a hidden part that is only given a property: allowed, and its variant is unmeasured live",
r["success"] == true && r["steps"][0]["result"]["proven"]["variants"] == json!(["new_part.invisible"])
&& r["steps"][0]["result"]["proven"]["live"] == false,
s(&r)
);
let bad = b.call("swx_run_script", json!({"script": box_script(json!({"op": "new_part", "visible": "no"}))}));
check!(b, "visible must be a boolean", bad["errorCode"] == "bad_script", s(&bad));
}
#[test]
fn a_battery_reuses_one_visible_part_and_clear_part_never_touches_anyone_elses() {
let (b, _m) = boot("vis-reuse", &[("SWX_ALLOW_USER_WRITES", "1")]);
// The simulated release is the one clear_part was measured on.
std::fs::write(b.scratch.join("mock-revision"), "34.3.0").unwrap();
b.call("swx_start", json!({}));
let made = b.call("swx_new_document", json!({"type": "part"}));
let p = made["documentIdentity"]["path"].as_str().unwrap_or("").to_string();
let first = b.call("swx_run_script", json!({"reuseDocument": p, "script": box_script(json!({"op": "new_part"}))}));
let docs = doc_count(&b);
let second = b.call("swx_run_script", json!({"reuseDocument": p, "script": [
{"op": "new_part"},
{"op": "sketch_circle", "plane": "Top Plane", "radiusMm": 5},
{"op": "extrude", "depthMm": 10}]}));
let ib = b.call("swx_inspect_bodies", json!({"path": p}));
check!(
b,
"reuseDocument: the leading new_part became clear_part; the box is gone, only the cylinder is left",
first["success"] == true && second["success"] == true && second["steps"][0]["op"] == "clear_part"
&& second["steps"][0]["result"]["featuresDeleted"] == 1
&& second["steps"][0]["result"]["proven"]["live"] == true
&& ib["bodyCount"] == 1
&& ib["bodies"][0]["volumeMm3"].as_f64().map(|v| (v - std::f64::consts::PI * 250.0).abs() < 1e-3) == Some(true),
format!("{}\n{}", s(&second), s(&ib))
);
check!(b, "...and no document was created by the reused runs", doc_count(&b) == docs, format!("{docs} -> {}", doc_count(&b)));
// A USER'S part.
let user = "C:\\mock\\plate.sldprt";
b.call("swx_open", json!({"path": user}));
let r = b.call("swx_run_script", json!({"path": user, "script": [{"op": "clear_part"}],
"allowUserWrites": true, "confirm": true, "reason": "the user asked to clear it"}));
check!(
b,
"clear_part on a part the bridge did not create: refused by the server, write grant or not",
r["errorCode"] == "clear_part_not_owned" && r["error"].as_str().unwrap_or("").contains("is not a part this bridge created"),
s(&r)
);
let r = b.call("swx_run_script", json!({"reuseDocument": user, "script": box_script(json!({"op": "new_part"}))}));
check!(b, "reuseDocument naming the user's part: refused", r["errorCode"] == "reuse_not_owned", s(&r));
let r = b.call("swx_run_script", json!({"reuseDocument": p, "script": [{"op": "new_part"}, {"op": "new_part"}]}));
check!(b, "with reuseDocument, new_part only as the first step", r["errorCode"] == "bad_script", s(&r));
// MEASURED (D): a reuseDocument that did not resolve read "needs a document".
let gone = b.call("swx_run_script", json!({"reuseDocument": "C:\\nowhere\\gone.SLDPRT", "script": box_script(json!({"op": "new_part"}))}));
check!(
b,
"a reuseDocument that is not open: the error names reuseDocument",
gone["success"] == false && gone["error"].as_str().unwrap_or("").contains("the document named by reuseDocument"),
s(&gone)
);
let hidden = b.call("swx_new_document", json!({"type": "part", "visible": false}));
let hp = hidden["documentIdentity"]["path"].as_str().unwrap_or("").to_string();
let r = b.call("swx_run_script", json!({"reuseDocument": hp, "script": box_script(json!({"op": "new_part"}))}));
check!(
b,
"a reuseDocument that is HIDDEN: document_hidden, and the error names reuseDocument",
r["errorCode"] == "document_hidden" && r["error"].as_str().unwrap_or("").contains("the document named by reuseDocument")
&& r["error"].as_str().unwrap_or("").contains("is hidden"),
s(&r)
);
}
#[test]
fn the_selftest_reuses_one_visible_document_and_releases_the_com_host_at_the_end() {
let (b, _m) = boot("vis-selftest", &[]);
b.call("swx_start", json!({}));
let r = b.call("swx_selftest", json!({"level": "write", "only": ["T01", "T03", "T15", "T17"]}));
let rows = r["results"].as_array().cloned().unwrap_or_default();
let row = |id: &str| rows.iter().find(|x| x["name"].as_str().unwrap_or("").starts_with(id)).cloned().unwrap_or(Value::Null);
check!(
b,
"every check passes; T01 and T03 in the shared part, T15 (a colour) and T17 (a feature by name) in their own",
r["summary"]["failed"] == 0 && row("T01")["pass"] == true && row("T03")["pass"] == true
&& row("T01")["reusedDocument"] == true && row("T03")["reusedDocument"] == true
&& row("T15")["reusedDocument"] == false && row("T17")["reusedDocument"] == false,
s(&r)
);
check!(
b,
"documentsCreated: one shared part, two of their own, one scratch part for the verbs — 4, not 5",
r["documentsCreated"] == 4,
s(&r["documentsCreated"])
);
check!(
b,
"everything VISIBLE: not one DocumentVisible call (a hidden part cannot be modelled)",
visible_calls(&b).is_empty(),
s(&json!(visible_calls(&b)))
);
check!(
b,
"the run ends by respawning the COM host, and reports it",
r["comRespawn"]["respawned"] == true && r["comRespawn"]["gracefulExit"] == true
&& ledger(&b).iter().any(|e| e["action"] == "com_host_respawn"),
s(&r["comRespawn"])
);
}
/// MEASURED 2026-10-14: at 86.9 % committed (9.9 GB available; Fusion 20.4 GB,
/// Chrome 9.7 GB, SOLIDWORKS only 1.5 GB), 0.10.6's self-test STOPPED before
/// T01. High pressure that SOLIDWORKS is not causing must not throttle the run.
#[test]
fn high_pressure_held_by_other_applications_does_not_stop_the_selftest() {
let machine = TempDir::new("vis-high");
std::fs::write(machine.join("windows.json"), "[]").unwrap();
std::fs::write(
machine.join("sldworks.json"),
json!({"responding": true, "hwnd": 6622700, "privateMB": 1536, "handles": 4000}).to_string(),
)
.unwrap();
std::fs::write(
machine.join("memory.json"),
json!({"commitLimitMB": 78438, "commitAvailMB": 10138, "physTotalMB": 32153, "physAvailMB": 2000,
"processes": [{"name": "Fusion360.exe", "pid": 41000, "privateMB": 20890},
{"name": "chrome.exe", "pid": 42000, "privateMB": 9933}]}).to_string(),
)
.unwrap();
let b = Bridge::start_with(&[("SWX_LAUNCH_FAKE_DIR", Box::leak(machine.path().into_boxed_str()))]);
b.call("swx_start", json!({}));
let r = b.call("swx_selftest", json!({"level": "write", "only": ["T01", "T03"]}));
check!(
b,
"the run COMPLETES at high pressure: no stop, no recycle, and the pressure is reported per check",
r["complete"] == true && r.get("stoppedFor").is_none() && r["recycled"] == json!([])
&& r["memoryPressureSeen"].as_array().map(|a| a.len() >= 2).unwrap_or(false)
&& r["memoryPressureSeen"][0]["why"].as_str().unwrap_or("").contains("carries on")
&& r["summary"]["failed"] == 0
&& r["_hint"].as_str().unwrap_or("").contains("held by other applications"),
s(&r)
);
check!(b, "nothing was quit or terminated", !machine.join("quit.jsonl").exists() && !machine.join("terminated.jsonl").exists(), "quit / terminated");
}
/// 0.10.8 — MEASURED on 0.10.7's live self-test: three checks failed because
/// clear_part's one DeleteSelection2 returned true and left a top-level sketch
/// (Sketch13, Sketch4, Sketch9) — one a previous check left unconsumed (a cut
/// that removed nothing keeps its sketch). clear_part now repeats until the
/// tree is empty, and reports its passes.
#[test]
fn clear_part_takes_a_second_pass_for_a_sketch_left_behind() {
let (b, _m) = boot("vis-clear-passes", &[]);
b.call("swx_start", json!({}));
let made = b.call("swx_new_document", json!({"type": "part"}));
let p = made["documentIdentity"]["path"].as_str().unwrap_or("").to_string();
// A cut from Top Plane with the body on +Y removes nothing: the step fails
// and its sketch stays in the tree, unconsumed.
let failed = b.call("swx_run_script", json!({"reuseDocument": p, "script": [
{"op": "new_part"},
{"op": "sketch_rect", "plane": "Top Plane", "widthMm": 20, "heightMm": 20, "anchor": "center"},
{"op": "extrude", "depthMm": 10},
{"op": "sketch_rect", "plane": "Top Plane", "widthMm": 10, "heightMm": 10, "anchor": "center"},
{"op": "cut", "depthMm": 5}]}));
let r = b.call("swx_run_script", json!({"reuseDocument": p, "script": box_script(json!({"op": "new_part"}))}));
let ib = b.call("swx_inspect_bodies", json!({"path": p}));
let deleted = r["steps"][0]["result"]["deleted"].as_array().cloned().unwrap_or_default();
check!(
b,
"the next clear_part took TWO passes — the features, then the sketch left behind — and the part holds only the new box",
failed["success"] == false && r["success"] == true && r["steps"][0]["result"]["passes"] == 2
&& deleted.iter().any(|d| d.as_str().unwrap_or("").starts_with("Sketch"))
&& ib["bodyCount"] == 1
&& ib["bodies"][0]["volumeMm3"].as_f64().map(|v| (v - 4000.0).abs() < 1e-6) == Some(true),
format!("{}\n{}", s(&r["steps"][0]), s(&ib))
);
}
/// When the shared part STILL cannot be cleared, the self-test does not fail
/// the check for it: the check runs in a fresh part, the row says why, and the
/// fresh part is counted. A check fails only on its own geometry.
#[test]
fn a_part_that_will_not_clear_falls_back_to_a_fresh_part_in_the_selftest() {
let (b, _m) = boot("vis-clear-fallback", &[]);
b.call("swx_start", json!({}));
std::fs::write(b.scratch.join("mock-clear-part-stuck"), "").unwrap();
let r = b.call("swx_selftest", json!({"level": "write", "only": ["T07", "T08"]}));
let rows = r["results"].as_array().cloned().unwrap_or_default();
let row = |id: &str| rows.iter().find(|x| x["name"].as_str().unwrap_or("").starts_with(id)).cloned().unwrap_or(Value::Null);
check!(
b,
"T08 could not reuse the part T07 left a sketch in: it ran in a FRESH part, passed, and the row says what was left",
r["summary"]["failed"] == 0 && row("T07")["pass"] == true && row("T08")["pass"] == true
&& row("T08")["reuseFallback"].as_str().unwrap_or("").starts_with("fresh part — clear_part left Sketch")
&& row("T07")["reuseFallback"].is_null(),
s(&json!(rows))
);
check!(
b,
"documentsCreated counts it: the shared part, the fallback part, the scratch part",
r["documentsCreated"] == 3,
s(&r["documentsCreated"])
);
}