app
SOLIDWORKS Bridge
Public Made by Adomby adom
Launch, model and quit SOLIDWORKS from any Adom container. Nothing is ever lost.
← Commit history
0.11.3 source
23 files changed
+5665−27
BRIDGE_VERSION+1−1Cargo.lock+1−1Cargo.toml+1−1README.md+35−1SKILL.md+4−1bridge.json+1−1docs/LIVE-RESULTS.md+45install.shpackage.json+1−1src/comhost/mock.rs+29src/compat.rs+8src/launch.rs+66src/launchos.rs+11−1src/perflog.rs+161−11src/readiness.rs+130−4src/verbs.rs+33−2src/verbs3.rs+161−1tests/common/mod.rs+5tests/e2e.rs+1−1tests/restart.rs+323tools/cswa/reports/cswa-2026-10-15-sw2026-0.11.2.json+4571tools/cswa/tb34.py+77uninstall.shBRIDGE_VERSION+1−1@@ -1 +1 @@-0.11.2+0.11.3
Cargo.lock+1−1@@ -122,7 +122,7 @@ dependencies = [ [[package]] name = "swx-bridge"-version = "0.11.2"+version = "0.11.3" dependencies = [ "miniz_oxide", "serde",
Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "swx-bridge"-version = "0.11.2"+version = "0.11.3" edition = "2021" rust-version = "1.80" description = "Adom SOLIDWORKS bridge — swx_* verbs over the SOLIDWORKS COM API, as a single native binary"
README.md+35−1@@ -506,7 +506,41 @@ not. ## Roadmap -- v0.11.2 (this): **the File ▸ Open was the launch's own.** The laptop's+- v0.11.3 (this): **a quick restart is not ready; a reply is not an effect.**+ Two live findings.++ The good one: the HideFileExt fix is PROVEN on Drew's laptop with extensions+ hidden. Every verb passed by the title, by the stem and by stem + `.SLDPRT`+ (`titles.hiddenExtensions`).++ The bad one, from the ledger: a quit then an immediate start was called+ `ready` 4 s after attach. A `swx_new_document` 11 s after attach returned OK.+ SOLIDWORKS (pid 26316) died a second later.++ Now:+ - **A marker counts only if it is beyond the launch.** The performance log's+ state is recorded when no SOLIDWORKS is writing it (launch, quit, or a first+ sight of a log still holding the last session). A marker counts only beyond+ that recorded length, unless the file has been rewritten since (shorter, or+ different bytes where it ended).+ - **A fresh attach** (the bridge's own launch, or a young process) is ready+ only with StartupProcessCompleted TRUE, this session's marker, and+ `SWX_READY_SETTLE_SECS` (20 s) since attach.+ - `readiness.evidence` lists each signal with its age, and `readiness.why`+ says what holds it.+ - The transition is ledgered as `solidworks_ready`.+ - The ready latch stays keyed to (pid, creation time).+ - **Verify by effect.** After `swx_new_document`, `swx_open` and+ `swx_import`, the live session is read again: the same process, still+ running, a non-zero document count, and the document in the list. A fresh+ session is read again after 1.5 s. Failure is `host_app_died` (with the pid,+ the ledger line and the crash markers) or `document_not_created`, never ok.+ - **A start within 60 s of a quit waits** (up to 30 s) for that session's+ sldworks.exe and per-session children to be gone, never the platform+ daemons. It is ledgered as `launch_waited_for_previous_exit`.++ 691 tests.+- v0.11.2: **the File ▸ Open was the launch's own.** The laptop's ledger had the sequence: - the 3DEXPERIENCE helper sign-in took 2 min 13 s; - the supervisor called that a stall, killed the chain and invoked the shortcut
SKILL.md+4−1@@ -99,7 +99,10 @@ BEFORE you do it: dialog is the user's to answer. A launch retry never re-invokes over a running SOLIDWORKS, and the 3DEXPERIENCE helper sign-in is never treated as a stall (a second invoke at a starting SOLIDWORKS raised a File ▸ Open,- measured 2026-10-15).+ measured 2026-10-15). After any (re)start, WAIT for `swx_status`+ `solidworks.ready` before a document verb — a fresh attach settles 20 s, and+ a document command sent sooner crashed SOLIDWORKS twice (2026-10-01,+ 2026-10-15). A document verb that reports `host_app_died` created NOTHING. 9. **Never end a session the user is working in, and never pile windows on them.** Every quit and sweep refuses `user_is_active` when SOLIDWORKS is in front with recent input, or documents appeared that the bridge did not open;
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "solidworks", "displayName": "SOLIDWORKS",- "version": "0.11.2",+ "version": "0.11.3", "description": "Bridge for SOLIDWORKS desktop CAD — create and open documents, a modeling DSL, file management (find/open/save/export/Pack and Go), custom properties, BOM generation, design analysis (mass properties, bodies, parameters, interference, rebuild health) and background window/dialog etiquette, over the SOLIDWORKS COM API. Single native binary: no interpreter, no PowerShell, ~10ms cold start.", "author": "Adom Inc.", "license": "MIT",
docs/LIVE-RESULTS.md+45@@ -22,6 +22,51 @@ Built in 4 features, measured live: | Colour | [200, 0, 0] (set before the material, kept after it) | red requested | | Density / mass | 1020.0 kg/m^3 / 0.0021148 kg | ABS 1020 / 0.0021148 | +## HideFileExt, measured 2026-10-15 (bridge 0.11.2, SOLIDWORKS 2026)++On Drew's laptop, with Windows' "Hide extensions for known file types" turned+ON (HideFileExt=1, SOLIDWORKS restarted). This is Michael's 2021 condition,+reproduced on our machine to prove the 0.10.10 fix:++| Check | Result |+|---|---|+| `swx_new_document` title read back | `Part1-1792103965000`, with no extension. `swx_docs` lists it the same way |+| `swx_run_script` by path | ok, `bridgeCreatedDocument:true` |+| `swx_design_info`, `swx_get_parameters` | PASS by the reported title, by the stem, and by the stem + `.SLDPRT` |+| `swx_set_parameter`, `swx_export_step` (15,944 B), `swx_save`, `swx_close_doc` | PASS by the stem |+| Left open | nothing |++`compat::OP_FACTS` carries it as `titles.hiddenExtensions`.++### The restart that followed (the 0.11.3 finding)++The second phase restarted SOLIDWORKS with extensions shown. From the ledger:++| Time (Z) | Event |+|---|---|+| 22:40:01 | quit (processGone) |+| 22:40:02 | launch |+| 22:40:07 | `sldworksUp` |+| 22:40:39 | attached |+| 22:40:43 | `solidworks.ready` TRUE, 4 s after attach (the first phase's start took 22 s to ready) |+| 22:40:50 | `swx_new_document` OK, title `Part1-1792104049001.SLDPRT`, ledger `document_created` |+| 22:40:51 | `swx_docs`: `[]`; SOLIDWORKS pid 26316 had DIED |+| 22:40:58 | `swx_stop`: `host_app_not_running` |++This was the 2026-10-01 crash again: a document command sent while an add-in+was still initialising.++0.11.3 makes these changes:+- A performance-log marker counts only if it lies beyond the state the file was+ in when no SOLIDWORKS was writing it (launch, quit, or a first sight of a+ stale log), unless the file has been rewritten since.+- A fresh attach is ready only with StartupProcessCompleted TRUE, this session's+ own marker, and 20 s after attach.+- `swx_new_document`, `swx_open` and `swx_import` verify the effect on the live+ session: same process, still running, the document in the list. If the effect+ is missing they return `host_app_died` / `document_not_created`, never ok.+- A start within 60 s of a quit waits for that session's process tree to be gone.+ ## SOLIDWORKS 2021 (community) Run 2026-10-15 by Michael (issue #1) with bridge **0.10.9** on **SOLIDWORKS 2021**
install.shpackage.json+1−1@@ -1,6 +1,6 @@ { "slug": "solidworks-bridge",- "version": "0.11.2",+ "version": "0.11.3", "type": "app", "description": "Skills for your container so your AI knows how to drive the SOLIDWORKS bridge (swx_* verbs). The bridge runtime itself is the release zip — a single native swx-bridge.exe; Adom Bridge loads that.", "tags": [
src/comhost/mock.rs+29@@ -1137,6 +1137,19 @@ impl Backend for MockBackend { let _ = std::fs::remove_file(&trigger); } }+ // SOLIDWORKS DIES SHORTLY AFTER A DOCUMENT COMMAND (0.11.3) — the+ // 2026-10-15 22:40 crash: `mock-dies-after-new-document` arms a countdown+ // of commands that still answer (default 1: the identity save); then the+ // process is gone, its documents with it.+ let countdown = crate::scratch::root().join("mock-death-countdown");+ if let Some(k) = std::fs::read_to_string(&countdown).ok().and_then(|t| t.trim().parse::<u64>().ok()) {+ if k == 0 {+ let _ = std::fs::remove_file(&countdown);+ self.finish_exit();+ } else {+ let _ = std::fs::write(&countdown, (k - 1).to_string());+ }+ } let out = self.dispatch(cmd, args); // The simulated APPLICATION's session outlives the com host, because a // real one does. Written after every command so a respawn resumes from@@ -2676,6 +2689,22 @@ impl MockBackend { } let hidden = !doc.visible; self.docs.push(doc);+ if fault("mock-dies-after-new-document") {+ let n = std::fs::read_to_string(crate::scratch::root().join("mock-dies-after-new-document"))+ .ok()+ .and_then(|t| t.trim().parse::<u64>().ok())+ .unwrap_or(1);+ let _ = std::fs::write(crate::scratch::root().join("mock-death-countdown"), n.to_string());+ let _ = std::fs::remove_file(crate::scratch::root().join("mock-dies-after-new-document"));+ }+ // THE REPLY IS NOT THE EFFECT (0.11.3): `mock-newdoc-vanishes` —+ // the call reports a document that is not there.+ if fault("mock-newdoc-vanishes") {+ let info = self.doc_info(&key);+ self.docs.retain(|d| d.path != key);+ self.active = None;+ return Ok(json!({"created": info, "template": template, "type": kind}));+ } // A hidden document is not made the active one (UNMEASURED live; // modelled conservatively). if !hidden {
src/compat.rs+8@@ -122,7 +122,14 @@ pub const LIVE_2026_10_14_C: Measurement = Measurement { year: 2026, major: 34, /// one bug (titles and HideFileExt, fixed in 0.10.10), in verbs, not ops. pub const LIVE_2021_10_15: Measurement = Measurement { year: 2021, major: 29, edition: "desktop", date: "2026-10-15", bridge: "0.10.9", by: "community" }; +/// 2026-10-15 22:38Z, bridge 0.11.2, SOLIDWORKS 2026, Drew's laptop with+/// Windows' "Hide extensions for known file types" ON (HideFileExt=1,+/// SOLIDWORKS restarted) — Michael's 2021 condition, reproduced: the 0.10.10+/// title fix, proven.+pub const LIVE_2026_10_15_HIDEEXT: Measurement = Measurement { year: 2026, major: 34, edition: "connected", date: "2026-10-15", bridge: "0.11.2", by: "adom" };+ const M2026_2021: &[Measurement] = &[LIVE_2026_10_14, LIVE_2021_10_15];+const M2026_HIDEEXT: &[Measurement] = &[LIVE_2026_10_15_HIDEEXT]; const M2026C_2021: &[Measurement] = &[LIVE_2026_10_14_C, LIVE_2021_10_15]; const M2026B: &[Measurement] = &[LIVE_2026_10_14_B]; const UNMEASURED: &[Measurement] = &[];@@ -226,6 +233,7 @@ pub const OP_FACTS: &[OpFact] = &[ OpFact { id: "hole.counterbore", what: "a counterbored hole (two cuts)", checks: "not run live (0.11.0)", measured: UNMEASURED }, OpFact { id: "hole.countersink", what: "a countersunk hole (a drafted cut, then the hole)", checks: "not run live (0.11.0)", measured: UNMEASURED }, OpFact { id: "set_material.density", what: "a density in kg/m³ (the document's own, or checked against the material's)", checks: "not run live (0.11.0)", measured: UNMEASURED },+ OpFact { id: "titles.hiddenExtensions", what: "documents addressed by title while Windows hides known extensions: swx_new_document reads back 'Part1-…' (no .SLDPRT); swx_design_info and swx_get_parameters by the reported title, the stem and stem+.SLDPRT; swx_set_parameter, swx_export_step, swx_save and swx_close_doc by the stem; nothing left open", checks: "the focused HideFileExt test, 2026-10-15 22:38-22:41Z", measured: M2026_HIDEEXT }, OpFact { id: "save_as", what: "save_as as a script step", checks: "not in the live battery (swx_save_as, the verb, is)", measured: UNMEASURED }, OpFact { id: "rebuild", what: "rebuild as a script step", checks: "not in the live battery", measured: UNMEASURED }, OpFact { id: "zoom_fit", what: "zoom_fit as a script step", checks: "not in the live battery", measured: UNMEASURED },
src/launch.rs+66@@ -615,6 +615,66 @@ pub fn dialog_grace() -> Duration { Duration::from_millis(secs_env("SWX_LAUNCH_DIALOG_GRACE_MS", 90_000)) } +/// A START RIGHT AFTER A QUIT (0.11.3). MEASURED 2026-10-15: a quit at+/// 22:40:01, a launch at 22:40:02 — and the new SOLIDWORKS died 11 s after+/// attach. A start within `SWX_START_AFTER_QUIT_SECS` (60) of a quit this bridge+/// made first waits, up to `SWX_START_AFTER_QUIT_WAIT_SECS` (30), for that+/// session's process tree to be gone: its sldworks.exe and the per-session+/// children (`quit::SESSION_CHILDREN`) — never the platform daemons, which+/// survive a quit by design.+pub fn previous_session_remaining(census: &[ProcInfo], prev_pid: u32, prev_created: Option<u64>, quit_at_secs: u64) -> Vec<ProcInfo> {+ census+ .iter()+ .filter(|p| {+ (p.is("SLDWORKS.exe") && p.pid == prev_pid && (prev_created.is_none() || p.created_at.is_none() || p.created_at == prev_created))+ || (crate::quit::SESSION_CHILDREN.iter().any(|c| p.is(c))+ && (p.ppid == Some(prev_pid) || p.created_at.map(|c| c <= quit_at_secs).unwrap_or(true)))+ })+ .cloned()+ .collect()+}++/// Wait (bounded) for the last quit's process tree to be gone, ledgered.+/// `None` when no quit was recent.+pub fn wait_for_previous_exit(os: &dyn LaunchOs) -> Option<Value> {+ let q: Value = std::fs::read_to_string(crate::scratch::root().join("last-quit.json")).ok().and_then(|t| serde_json::from_str(&t).ok())?;+ let at_ms = q.get("atMs").and_then(|v| v.as_u64())?;+ let pid = q.get("pid").and_then(|v| v.as_u64())? as u32;+ let created = q.get("createdAt").and_then(|v| v.as_u64());+ let now_ms = crate::launchos::epoch_ms() as u64;+ if now_ms.saturating_sub(at_ms) > secs_env("SWX_START_AFTER_QUIT_SECS", 60) * 1000 {+ return None;+ }+ let started = std::time::Instant::now();+ let deadline = started + Duration::from_secs(secs_env("SWX_START_AFTER_QUIT_WAIT_SECS", 30));+ let mut remaining: Vec<ProcInfo>;+ let mut readable = true;+ loop {+ match os.processes() {+ Ok(c) => remaining = previous_session_remaining(&c, pid, created, at_ms / 1000),+ Err(_) => {+ readable = false;+ remaining = Vec::new();+ }+ }+ if remaining.is_empty() || std::time::Instant::now() >= deadline || !readable {+ break;+ }+ std::thread::sleep(Duration::from_millis(250));+ }+ let gone = readable && remaining.is_empty();+ let v = json!({+ "previous": {"pid": pid, "createdAt": created},+ "quitSecondsAgo": now_ms.saturating_sub(at_ms) / 1000,+ "waitedMs": started.elapsed().as_millis() as u64,+ "gone": gone,+ "censusReadable": readable,+ "remaining": remaining.iter().map(|p| json!({"pid": p.pid, "image": p.image})).collect::<Vec<_>>(),+ });+ crate::ledger::record("launch_waited_for_previous_exit", v.clone());+ Some(v)+}+ /// A SOLIDWORKS that this launch did not find running before it began: any /// sldworks.exe outside the FIRST route's baseline. While one exists, no route /// is invoked again — a second invoke reaches it as an "open" request.@@ -1629,6 +1689,12 @@ fn run_supervisor(channel: Channel, os: Box<dyn LaunchOs>) { // WHAT RAN BEFORE THIS LAUNCH BEGAN — the FIRST route's baseline. Any // sldworks.exe outside it is this launch's, whichever route started it. let first_baseline: Vec<u32> = os.processes().map(|c| c.iter().map(|p| p.pid).collect()).unwrap_or_default();+ // THE PERFORMANCE LOG AS NO SOLIDWORKS IS WRITING IT (0.11.3): a marker the+ // session this launch starts writes must lie beyond this (or the file be+ // rewritten) — see perflog::Baseline.+ if os.processes().map(|c| !c.iter().any(|p| p.is("SLDWORKS.exe"))).unwrap_or(false) {+ crate::perflog::record_baseline("launch", None);+ } for (index, route) in plan.iter().enumerate() { // NEVER RE-INVOKE OVER A RUNNING SOLIDWORKS (0.11.2). Before a retry, // watch a moment for a SOLIDWORKS the stalled route started anyway; if
src/launchos.rs+11−1@@ -960,7 +960,17 @@ impl LaunchOs for FakeOs { continue; } let image = r.get("image").and_then(|i| i.as_str()).unwrap_or("").to_string();- if reaped(&image) {+ // `reapedAfterQuitMs` (0.11.3): a per-session child that outlives+ // the quit by this long — what a start right after a quit must+ // wait out.+ let lingers = r.get("reapedAfterQuitMs").and_then(|x| x.as_u64()).map(|n| {+ let first_quit = std::fs::read_to_string(self.dir.join("quit.jsonl")).unwrap_or_default().lines().filter_map(|l| {+ let v: Value = serde_json::from_str(l).ok()?;+ v.get("effectiveAtMs").or_else(|| v.get("atMs")).and_then(|x| x.as_u64())+ }).min();+ first_quit.map(|q| (epoch_ms() as u64) < q + n).unwrap_or(true)+ });+ if reaped(&image) && lingers != Some(true) { continue; } out.push(ProcInfo {
src/perflog.rs+161−11@@ -56,6 +56,12 @@ pub fn path() -> Option<PathBuf> { } fn tail() -> Option<String> {+ tail_bytes().map(|(b, _)| String::from_utf8_lossy(&b).to_string())+}++/// The tail as BYTES, with the file offset it starts at — positions compare+/// exactly only before a lossy UTF-8 conversion.+fn tail_bytes() -> Option<(Vec<u8>, u64)> { use std::io::{Read, Seek, SeekFrom}; let mut f = std::fs::File::open(path()?).ok()?; let len = f.metadata().ok()?.len();@@ -63,7 +69,98 @@ fn tail() -> Option<String> { f.seek(SeekFrom::Start(start)).ok()?; let mut buf = Vec::new(); f.read_to_end(&mut buf).ok()?;- Some(String::from_utf8_lossy(&buf).to_string())+ Some((buf, start))+}++/// `n` bytes of the log ending at `end` (or fewer at the start of the file).+fn bytes_before(path: &std::path::Path, end: u64, n: u64) -> Option<Vec<u8>> {+ use std::io::{Read, Seek, SeekFrom};+ let mut f = std::fs::File::open(path).ok()?;+ let from = end.saturating_sub(n);+ f.seek(SeekFrom::Start(from)).ok()?;+ let mut buf = vec![0u8; (end - from) as usize];+ f.read_exact(&mut buf).ok()?;+ Some(buf)+}++// ── THE LAUNCH BASELINE (0.11.3) ────────────────────────────────────────────+// MEASURED 2026-10-15 22:40 (hosted 0.11.2): a quit at 22:40:01, a launch at+// 22:40:02, COM attached at 22:40:39 — and `ready` at 22:40:43. A document+// command at 22:40:50 "succeeded", and SOLIDWORKS died a second later: the+// 2026-10-01 crash, an add-in still initialising. The log is tied to a session+// by its modification time, which says nothing about WHICH lines are the new+// session's: a marker the PREVIOUS session wrote, still in the file when the new+// one touched it, read as this start completing. So the file's state is+// recorded when no SOLIDWORKS can be writing it — when a launch begins, when a+// quit has verifiably finished — and a marker counts for a session that started+// after that only if it lies BEYOND the recorded length, unless the file has+// been REWRITTEN since (shorter now, or different bytes where the recorded file+// ended).++/// The log's state at a moment no SOLIDWORKS session was writing it.+#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]+pub struct Baseline {+ /// The file's length then.+ pub len: u64,+ /// sha256 of the (up to) 256 bytes that ended the file then: still there+ /// unchanged means the file was APPENDED to; different, it was rewritten.+ pub end_fp: String,+ /// When it was taken (epoch seconds).+ pub at_secs: u64,+ /// Why (launch / quit / first sight of a session whose log was still the+ /// previous session's).+ pub why: String,+}++const END_FP_BYTES: u64 = 256;++/// The log's state now, if there is a log.+pub fn snapshot(why: &str) -> Option<Baseline> {+ let p = path()?;+ let len = std::fs::metadata(&p).ok()?.len();+ let end_fp = crate::sha256::hex_of(&bytes_before(&p, len, END_FP_BYTES)?);+ Some(Baseline { len, end_fp, at_secs: crate::launchos::epoch_secs(), why: why.to_string() })+}++fn baselines_path() -> PathBuf {+ crate::scratch::root().join("perflog-baselines.json")+}++pub fn baselines() -> Vec<Baseline> {+ std::fs::read_to_string(baselines_path()).ok().and_then(|t| serde_json::from_str(&t).ok()).unwrap_or_default()+}++/// Record the log's state now (keeps the last 8). `at_override`: the moment the+/// record speaks for (a session's creation time, for a first-sight record).+pub fn record_baseline(why: &str, at_override: Option<u64>) -> Option<Baseline> {+ let mut b = snapshot(why)?;+ if let Some(a) = at_override {+ b.at_secs = a;+ }+ let mut all = baselines();+ all.push(b.clone());+ let keep = all.len().saturating_sub(8);+ let all: Vec<Baseline> = all.into_iter().skip(keep).collect();+ let _ = std::fs::write(baselines_path(), serde_json::to_string(&all).unwrap_or_else(|_| "[]".into()));+ Some(b)+}++/// The latest record taken at or before a session started: everything the file+/// held then was written by earlier sessions.+pub fn baseline_for(session_start: u64) -> Option<Baseline> {+ baselines().into_iter().filter(|b| b.at_secs <= session_start).max_by_key(|b| b.at_secs)+}++/// Has the file been rewritten since `b` (shorter, or different bytes where it+/// ended)? `None` = could not tell.+pub fn rewritten_since(b: &Baseline) -> Option<bool> {+ let p = path()?;+ let len = std::fs::metadata(&p).ok()?.len();+ if len < b.len {+ return Some(true);+ }+ let now = bytes_before(&p, b.len, END_FP_BYTES)?;+ Some(crate::sha256::hex_of(&now) != b.end_fp) } /// How long the log must have been QUIET before a `LOAD_ADDIN` after this@@ -197,10 +294,33 @@ fn mtime_secs(path: &std::path::Path) -> Option<u64> { /// start, so a log that cannot be tied to the session never lets COM decide /// alone, and a log still being written holds COM's `true`. pub fn startup_complete(session_start: Option<u64>) -> (LogVerdict, String) {+ let base = session_start.and_then(baseline_for);+ let (v, why, _) = startup_complete_since(session_start, base.as_ref());+ (v, why)+}++/// What the region read came from: the baseline used, whether the file was+/// rewritten since it, and where the region began (file offset).+#[derive(Clone, Debug, Default, PartialEq)]+pub struct Region {+ pub baseline: Option<Baseline>,+ pub rewritten: Option<bool>,+ pub from_offset: u64,+ /// The file offset of the marker that decided `Complete`, if one did.+ pub marker_offset: Option<u64>,+ pub marker: Option<String>,+}++/// `startup_complete`, reading only what a session that started after `base`+/// can have written (0.11.3): when the file was APPENDED to since `base`, the+/// region starts at `base.len`; when it was rewritten (or there is no+/// baseline), at the last start header, as before.+pub fn startup_complete_since(session_start: Option<u64>, base: Option<&Baseline>) -> (LogVerdict, String, Region) {+ let mut region = Region { baseline: base.cloned(), ..Default::default() }; let Some(path) = path() else {- return (LogVerdict::Unavailable, "no SOLIDWORKS performance log to read".into());+ return (LogVerdict::Unavailable, "no SOLIDWORKS performance log to read".into(), region); };- let Some(t) = tail() else {+ let Some((raw, tail_start)) = tail_bytes() else { // ABSENT AND UNREADABLE ARE DIFFERENT FACTS (adversary pass 45, V1). A // log that exists — or a configured path that is missing — and cannot // be read says the edition DOES write one and this bridge did not see@@ -212,17 +332,32 @@ pub fn startup_complete(session_start: Option<u64>) -> (LogVerdict, String) { } else { format!("the configured performance log path is missing ({})", path.display()) },+ region, ); };- let t: &str = match t.rfind(LOG_HEADER) {- Some(h) => &t[h..],- None => &t,+ // WHERE THIS SESSION'S TEXT CAN BEGIN. Appended since the baseline: after+ // the recorded length — what lies before it is an earlier session's, its+ // markers included. Rewritten (or no baseline): the whole tail.+ let mut from_rel = 0usize;+ if let Some(b) = base {+ let rw = rewritten_since(b);+ region.rewritten = rw;+ if rw == Some(false) {+ from_rel = (b.len.saturating_sub(tail_start) as usize).min(raw.len());+ }+ }+ let scoped = String::from_utf8_lossy(&raw[from_rel..]).to_string();+ let (t, header_rel): (&str, usize) = match scoped.rfind(LOG_HEADER) {+ Some(h) => (&scoped[h..], h),+ None => (&scoped, 0), };+ region.from_offset = tail_start + from_rel as u64 + header_rel as u64; let mtime = mtime_secs(&path); let Some(start) = session_start else { return ( LogVerdict::NotThisSession, "this SOLIDWORKS process's creation time is unknown, so the log cannot be tied to it".into(),+ region, ); }; let mt = match mtime {@@ -235,9 +370,10 @@ pub fn startup_complete(session_start: Option<u64>) -> (LogVerdict, String) { an earlier session, not this one", start - mt ),+ region, ) }- None => return (LogVerdict::NotThisSession, "the log's modification time could not be read".into()),+ None => return (LogVerdict::NotThisSession, "the log's modification time could not be read".into(), region), }; let is_platform = |l: &str| is_load_event(l) && l.to_ascii_lowercase().contains(PLATFORM_ADDIN_DLL); // Every line with its byte offset, so positions compare exactly.@@ -266,10 +402,12 @@ pub fn startup_complete(session_start: Option<u64>) -> (LogVerdict, String) { LogVerdict::Loading, format!( "this session's startup lines changed {quiet}s ago ({addins} LOAD_ADDIN \- line(s)) and the log holds no 3DEXPERIENCE marker yet: a start in progress — \+ line(s)) and the log holds no 3DEXPERIENCE marker {}yet: a start in progress — \ held until the marker arrives or no startup line changes for {}s",+ if from_rel > 0 { "written since the launch " } else { "" }, quiet_window() ),+ region, ); } if platform {@@ -280,6 +418,7 @@ pub fn startup_complete(session_start: Option<u64>) -> (LogVerdict, String) { has not been written, and no startup line has changed for {quiet}s: the platform \ load has not finished (a dialog, a sign-in?)" ),+ region, ); } return (@@ -290,10 +429,13 @@ pub fn startup_complete(session_start: Option<u64>) -> (LogVerdict, String) { {ON_DEMAND_QUIET_SECS}s): the add-in load phase is over — ready only if COM also \ says the start completed" ),+ region, ); }; let last_addin = lines.iter().rev().find(|(_, l)| is_load_event(l)).map(|(o, _)| *o);- match last_addin {+ region.marker = Some(name.to_string());+ region.marker_offset = Some(region.from_offset + m as u64);+ let verdict_and_why = match last_addin { Some(a) if a > m => { // A START loads the PLATFORM add-in — it is what writes the marker — // so a LOAD_ADDIN for it after the last marker is a start in@@ -331,9 +473,17 @@ pub fn startup_complete(session_start: Option<u64>) -> (LogVerdict, String) { } _ => ( LogVerdict::Complete,- format!("{name} written after the last LOAD_ADDIN line, in a log written since this process started"),+ format!(+ "{name} written after the last LOAD_ADDIN line, in a log written since this process started{}",+ match (®ion.baseline, region.rewritten) {+ (Some(b), Some(false)) => format!(", and beyond the {} bytes the file held before this launch ({})", b.len, b.why),+ (Some(b), Some(true)) => format!(" (the file was rewritten since the {} record)", b.why),+ _ => String::new(),+ }+ ), ),- }+ };+ (verdict_and_why.0, verdict_and_why.1, region) } /// THE FILE'S SHAPE, for the record (adversary pass 44, F7): its length now and
src/readiness.rs+130−4@@ -37,6 +37,15 @@ //! that does not become ready within `TIMEOUT_SECS` is `readinessTimedOut`, still //! starting. Once a session (by process id) is verified ready it stays ready. //!+//! A QUICK RESTART (0.11.3, measured 2026-10-15): `ready` came 4 s after attach+//! and a document command 11 s after attach killed SOLIDWORKS. So the log is+//! read only beyond its state when no SOLIDWORKS was writing it+//! (`perflog::Baseline`: a launch, a quit, or a first sight of a log still+//! holding the previous session), and a FRESH attach — the bridge's own launch,+//! or a process first seen young — needs StartupProcessCompleted TRUE and+//! `settle_secs()` since attach on top of the marker. `evidence` lists what was+//! used and how old it is; the ready transition is ledgered.+//! //! Every assessment also reads `GetDocumentCount` (in `startup_state`): a //! non-zero count at ANY poll records the session as having held a document //! (`session_history`).@@ -52,6 +61,33 @@ pub const RETRY_AFTER_SECS: u64 = 5; /// The grace, overridable (`SWX_READINESS_GRACE_SECS`) so the suite need not /// wait a real minute. It only ever unlocks READ verbs.+/// THE SETTLE AFTER A FRESH ATTACH (0.11.3, `SWX_READY_SETTLE_SECS`). MEASURED+/// 2026-10-15 22:40 (hosted 0.11.2): a quick restart was called `ready` 4 s+/// after COM attached; a document command 11 s after attach "succeeded" and+/// SOLIDWORKS died a second later — the 2026-10-01 crash again (8 s after+/// attach, an add-in still initialising). A session this bridge has just seen+/// start is ready only with COM's StartupProcessCompleted TRUE, this session's+/// own marker, AND this long since it attached.+pub fn settle_secs() -> u64 {+ std::env::var("SWX_READY_SETTLE_SECS").ok().and_then(|v| v.trim().parse().ok()).unwrap_or(20)+}++/// When THIS session attached, as far as the bridge knows: the launch that+/// attached it (the attempt's attach time, when the attempt is about this+/// process or one created after the attempt began).+fn launch_attach_anchor(pid: i64, created: Option<u64>) -> Option<u64> {+ let a = crate::launch::attempt()?;+ if !a.finished || a.outcome.as_deref() != Some("attached") {+ return None;+ }+ let ours = match (a.attributed_sldworks, created) {+ (Some((p, c)), Some(cr)) if p as i64 == pid && c == cr => true,+ (_, Some(cr)) => cr + 5 >= a.started_at,+ _ => false,+ };+ ours.then_some(a.stage_at)+}+ fn grace_secs() -> u64 { std::env::var("SWX_READINESS_GRACE_SECS") .ok()@@ -61,6 +97,9 @@ fn grace_secs() -> u64 { struct Seen { first: Instant,+ /// The same moment, in epoch seconds — the settle's anchor for a session+ /// first seen young.+ first_epoch: u64, ready: bool, /// The performance log's length when this session was first seen (F7): a /// rewrite at the next start shrinks it; an appended log only grows.@@ -103,16 +142,33 @@ pub fn assess(ctx: &crate::verbs::Ctx) -> Value { .and_then(|ps| ps.iter().find(|x| x.pid == p).and_then(|x| x.created_at)) }) .or_else(|| state.get("processCreatedAt").and_then(|v| v.as_u64()));- let (log, log_why) = crate::perflog::startup_complete(created);+ // THE LOG, READ ONLY WHERE THIS SESSION CAN HAVE WRITTEN (0.11.3): beyond+ // the state the file was in when no SOLIDWORKS was writing it (a launch+ // began, a quit finished), unless it has been rewritten since. A session+ // first seen while the log is still the previous session's records that+ // state itself.+ if let Some(c) = created {+ let written = crate::perflog::path().and_then(|p| {+ std::fs::metadata(&p).and_then(|m| m.modified()).ok().and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()).map(|d| d.as_secs())+ });+ if written.map(|w| w < c).unwrap_or(false) && crate::perflog::baseline_for(c).is_none() {+ crate::perflog::record_baseline("firstSightWhileTheLogWasStillTheLastSession's", Some(c));+ }+ }+ let base = created.and_then(crate::perflog::baseline_for);+ let (log, log_why, region) = crate::perflog::startup_complete_since(created, base.as_ref()); use crate::perflog::LogVerdict as L; let mut guard = SESSIONS.lock().unwrap_or_else(|e| e.into_inner()); let map = guard.get_or_insert_with(HashMap::new); let key = (pid.unwrap_or(-1), created); let shape = crate::perflog::shape(); let len_now = shape.get("lengthNow").and_then(|v| v.as_u64());- let seen = map- .entry(key)- .or_insert(Seen { first: Instant::now(), ready: false, log_len_at_first_sight: len_now });+ let seen = map.entry(key).or_insert(Seen {+ first: Instant::now(),+ first_epoch: crate::launchos::epoch_secs(),+ ready: false,+ log_len_at_first_sight: len_now,+ }); let len_first = seen.log_len_at_first_sight; let age = seen.first.elapsed().as_secs(); let mut based_on: Vec<&str> = Vec::new();@@ -167,10 +223,64 @@ pub fn assess(ctx: &crate::verbs::Ctx) -> Value { (L::NotThisSession, _) => None, } };+ // A FRESH ATTACH (0.11.3): a session the bridge saw start — attached by its+ // own launch, or first seen while the process was young — is ready only with+ // StartupProcessCompleted TRUE and `settle_secs()` since it attached.+ let now_secs = crate::launchos::epoch_secs();+ let launch_anchor = launch_attach_anchor(pid.unwrap_or(-1), created);+ let young_at_first_sight = created.map(|c| seen.first_epoch.saturating_sub(c) < long_running_secs()).unwrap_or(false);+ let anchor: Option<u64> = match (launch_anchor, young_at_first_sight) {+ (Some(a), _) => Some(a),+ (None, true) => Some(seen.first_epoch),+ (None, false) => None,+ };+ let fresh = anchor.is_some() && !seen.ready;+ let since_attach = anchor.map(|a| now_secs.saturating_sub(a));+ let mut held_by: Option<String> = None;+ let mut verdict = verdict;+ if verdict == Some(true) && fresh {+ if com != Some(true) {+ held_by = Some("a fresh start is ready only with StartupProcessCompleted TRUE, and COM has not said so".into());+ verdict = Some(false);+ } else if since_attach.map(|s| s < settle_secs()).unwrap_or(false) {+ held_by = Some(format!(+ "settling: attached {}s ago, and a fresh start is ready only {}s after attach (SWX_READY_SETTLE_SECS) — \+ document commands 8 s and 11 s after attach crashed SOLIDWORKS (2026-10-01, 2026-10-15)",+ since_attach.unwrap_or(0),+ settle_secs()+ ));+ verdict = Some(false);+ }+ }+ if held_by.is_some() {+ based_on.push("settleAfterAttach");+ } let ready = verdict == Some(true);+ // THE EVIDENCE, with its age — what the verdict was built from.+ let log_age = crate::perflog::path()+ .and_then(|p| std::fs::metadata(&p).and_then(|m| m.modified()).ok())+ .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())+ .map(|d| now_secs.saturating_sub(d.as_secs()));+ let evidence = json!([+ {"signal": "StartupProcessCompleted", "value": com},+ {"signal": "performanceLog", "verdict": log.name(), "marker": region.marker, "markerOffset": region.marker_offset,+ "readFromOffset": region.from_offset,+ "launchBaseline": region.baseline.as_ref().map(|b| json!({"length": b.len, "why": b.why, "ageSeconds": now_secs.saturating_sub(b.at_secs)})),+ "rewrittenSinceBaseline": region.rewritten,+ "logLastWrittenSecondsAgo": log_age},+ {"signal": "settleAfterAttach", "attachedSecondsAgo": since_attach, "required": settle_secs(),+ "anchor": if launch_anchor.is_some() { "launchAttach" } else if anchor.is_some() { "firstSeenYoung" } else { "notAFreshStart" },+ "satisfied": since_attach.map(|s| s >= settle_secs()).unwrap_or(true)},+ ]); if ready && pid.is_some() { if !seen.ready { persist_ready(pid.unwrap_or(-1), created);+ // THE TRANSITION IS ON THE RECORD, with what decided it — so a+ // crash after it can be laid beside the evidence.+ crate::ledger::record(+ "solidworks_ready",+ json!({"processId": pid, "processCreatedAt": created, "basedOn": based_on, "evidence": evidence}),+ ); } seen.ready = true; }@@ -201,6 +311,8 @@ pub fn assess(ctx: &crate::verbs::Ctx) -> Value { "processId": pid, "processCreatedAt": created, "basedOn": based_on,+ "evidence": evidence,+ "why": held_by.clone().unwrap_or_else(|| log_why.clone()), "startupProcessCompleted": com, "performanceLog": { "verdict": log.name(),@@ -224,6 +336,20 @@ pub fn assess(ctx: &crate::verbs::Ctx) -> Value { }) } +/// How long ago THIS session attached, as far as the bridge knows: its own+/// launch's attach, or its first sight if the process was young then. `None` =+/// not a session the bridge saw start.+pub fn attached_secs_ago(pid: i64, created: Option<u64>) -> Option<u64> {+ let now = crate::launchos::epoch_secs();+ if let Some(a) = launch_attach_anchor(pid, created) {+ return Some(now.saturating_sub(a));+ }+ let g = SESSIONS.lock().unwrap_or_else(|e| e.into_inner());+ let seen = g.as_ref()?.get(&(pid, created))?;+ let young = created.map(|c| seen.first_epoch.saturating_sub(c) < long_running_secs()).unwrap_or(false);+ young.then(|| now.saturating_sub(seen.first_epoch))+}+ /// A session is long-running past this many seconds (`SWX_LONG_RUNNING_SECS`). pub fn long_running_secs() -> u64 { std::env::var("SWX_LONG_RUNNING_SECS").ok().and_then(|v| v.trim().parse().ok()).unwrap_or(600)
src/verbs.rs+33−2@@ -810,7 +810,16 @@ fn swx_progress(ctx: &Ctx, _args: &Value) -> Value { /// with an empty name that a launch route provably raised is cancelled here /// too — ledgered — so a launch never leaves the session blocked. fn swx_start(ctx: &Ctx, args: &Value) -> Value {+ // A START RIGHT AFTER A QUIT waits for that session to be gone (0.11.3).+ let waited = if arg_str(args, "app").map(|a| a == "visualize").unwrap_or(false) {+ None+ } else {+ crate::launch::wait_for_previous_exit(crate::launchos::os().as_ref())+ }; let mut out = swx_start_inner(ctx, args);+ if let (Some(w), Value::Object(m)) = (waited, &mut out) {+ m.insert("waitedForPreviousExit".into(), w);+ } let cancelled = crate::dialogs::cancel_launch_file_dialogs(crate::launchos::os().as_ref()); if !cancelled.is_empty() { if let Value::Object(m) = &mut out {@@ -1810,6 +1819,14 @@ fn swx_stop(ctx: &Ctx, args: &Value) -> Value { "solidworks_stopped", json!({"rung": winning, "authorized": grant.user_write, "identity": id.to_json()}), );+ // THE QUIT IS REMEMBERED (0.11.3): a start right after it waits for this+ // session's process tree to be gone, and the performance log's state now+ // — no SOLIDWORKS writing it — bounds what the NEXT session may claim.+ crate::perflog::record_baseline("quit", None);+ let _ = std::fs::write(+ crate::scratch::root().join("last-quit.json"),+ json!({"pid": id.pid, "createdAt": id.created_at, "atMs": crate::launchos::epoch_ms() as u64}).to_string(),+ ); } let rungs_json: Vec<Value> = tries.iter().map(|t| t.to_json()).collect(); let census_json = |c: &Result<Vec<crate::launchos::ProcInfo>, String>| -> Value {@@ -2230,11 +2247,24 @@ fn swx_open(ctx: &Ctx, args: &Value) -> Value { m.insert("launch".into(), Value::Bool(may)); m.insert("readOnly".into(), Value::Bool(read_only)); }+ let session_before = crate::verbs3::session_identity(ctx); match ctx.call("open", call_args, 280) { Err(e) => sidecar_error(e),- Ok(r) => ok_merge(+ Ok(r) => {+ // THE EFFECT (0.11.3): the document is open in the SAME, LIVE session.+ // A SOLIDWORKS that was not running before the open (a classic+ // install the open launched) is read as the session now answering.+ let before = session_before.or_else(|| crate::verbs3::session_identity(ctx));+ let opened_path = r.pointer("/doc/path").and_then(|p| p.as_str()).filter(|p| !p.is_empty()).map(String::from).unwrap_or_else(|| path.clone());+ let opened_title = r.pointer("/doc/title").and_then(|t| t.as_str()).map(String::from);+ let effect = match crate::verbs3::verify_effect(ctx, "swx_open", before, opened_title.as_deref(), Some(&opened_path)) {+ Ok(v) => v,+ Err(e) => return e,+ };+ ok_merge( r, json!({+ "effect": effect, "windowEtiquette": "background", "progress": job.finished(), "_hint": "Open and active, READ-ONLY by default — so the bridge does not hold a \@@ -2247,7 +2277,8 @@ fn swx_open(ctx: &Ctx, args: &Value) -> Value { answers host_app_launch_blocked instead. On a classic desktop install \ it will launch it, and the progress frame reports what that cost.", }),- ),+ )+ } } }
src/verbs3.rs+161−1@@ -3928,6 +3928,142 @@ pub(crate) fn settle_document_visible(ctx: &Ctx, kind: &str, visibility: &Value) v } +// ── VERIFY BY EFFECT (0.11.3) ───────────────────────────────────────────────+// MEASURED 2026-10-15 22:40:50 (hosted 0.11.2): swx_new_document returned OK,+// with a title and a ledger `document_created` — and swx_docs one second later+// said []: SOLIDWORKS (pid 26316) had died right after the document command, 11 s+// after attach. A reply is not an effect. After a document-creating verb the+// bridge reads, from the LIVE session: the process is still the same one and+// still in the process census, the document count is not zero, and the document+// is in the list. Fresh sessions are read again after a short pause, because+// that death came a second after the reply.++/// The running session's (pid, creation time), from the host and the census.+pub(crate) fn session_identity(ctx: &Ctx) -> Option<(i64, Option<u64>)> {+ let s = ctx.call("startup_state", json!({}), 20).ok()?;+ if s.get("running").and_then(|v| v.as_bool()) != Some(true) {+ return None;+ }+ let pid = s.get("processId").and_then(|v| v.as_i64())?;+ let created = u32::try_from(pid)+ .ok()+ .and_then(|p| crate::launchos::os().processes().ok().and_then(|ps| ps.iter().find(|x| x.pid == p).and_then(|x| x.created_at)))+ .or_else(|| s.get("processCreatedAt").and_then(|v| v.as_u64()));+ Some((pid, created))+}++fn effect_recheck_ms() -> u64 {+ std::env::var("SWX_EFFECT_RECHECK_MS").ok().and_then(|v| v.trim().parse().ok()).unwrap_or(1500)+}++/// One reading of the effect: Ok(evidence), or Err((died, why)).+fn read_effect(ctx: &Ctx, before: (i64, Option<u64>), title: Option<&str>, path: Option<&str>) -> Result<Value, (bool, String)> {+ let (pid, created) = before;+ let census = crate::launchos::os().processes().ok();+ let in_census = census.as_ref().map(|ps| ps.iter().any(|p| p.pid as i64 == pid && (created.is_none() || p.created_at.is_none() || p.created_at == created)));+ // THE LIVE SESSION ANSWERS FIRST; the process census decides only when it+ // cannot (a dead SOLIDWORKS takes its COM server with it).+ let state = match ctx.call("startup_state", json!({}), 20) {+ Ok(s) => s,+ Err(e) => {+ if in_census == Some(false) {+ return Err((true, format!("the com host could not answer ({}) and SOLIDWORKS pid {pid} is gone from the process census", e.message)));+ }+ return Ok(json!({"verified": false, "processId": pid, "inProcessCensus": in_census,+ "why": format!("the com host could not answer ({}); the process is {}", e.message,+ if in_census == Some(true) { "still running" } else { "of unknown state" })}));+ }+ };+ if state.get("running").and_then(|v| v.as_bool()) != Some(true) {+ return Err((true, format!("SOLIDWORKS (pid {pid}) is no longer running")));+ }+ let now_pid = state.get("processId").and_then(|v| v.as_i64());+ if now_pid != Some(pid) {+ return Err((true, format!("SOLIDWORKS pid {pid} is gone: the session now answering is pid {now_pid:?}")));+ }+ let count = state.get("documentCount").and_then(|v| v.as_u64());+ if count == Some(0) {+ return Err((false, "SOLIDWORKS reports ZERO open documents".into()));+ }+ let docs = ctx.call("docs", json!({}), 30).map_err(|e| (false, format!("the document list could not be read ({})", e.message)))?;+ // A list too long to enumerate (leaked import temps) cannot show the+ // document either way: the live count and the live process stand.+ if docs.get("truncated").and_then(|t| t.as_bool()) == Some(true) {+ return Ok(json!({"verified": true, "processId": pid, "processCreatedAt": created, "documentCount": count,+ "inProcessCensus": in_census, "documentListTruncated": true}));+ }+ let list = docs.get("docs").and_then(|d| d.as_array()).cloned().unwrap_or_default();+ let found = list.iter().any(|d| {+ let dp = d.get("path").and_then(|p| p.as_str()).filter(|p| !p.is_empty());+ let dt = d.get("title").and_then(|t| t.as_str()).unwrap_or("");+ match (path, dp) {+ (Some(p), Some(q)) => crate::verbs::same_path(p, q),+ _ => title.map(|t| crate::verbs::same_title(t, dt)).unwrap_or(false),+ }+ });+ if !found && (title.is_some() || path.is_some()) {+ return Err((false, format!("the document ({}) is not in SOLIDWORKS' document list", path.or(title).unwrap_or("?"))));+ }+ Ok(json!({"verified": true, "processId": pid, "processCreatedAt": created, "documentCount": count, "inProcessCensus": in_census}))+}++/// THE EFFECT CHECK. `Ok(evidence)` to merge into the reply; `Err(reply)` —+/// `host_app_died` or `document_not_created` — never an ok.+pub(crate) fn verify_effect(ctx: &Ctx, verb: &str, before: Option<(i64, Option<u64>)>, title: Option<&str>, path: Option<&str>) -> Result<Value, Value> {+ let Some(before) = before else {+ return Ok(json!({"verified": false, "why": "the session's identity could not be read before the command"}));+ };+ let mut reads = 1;+ let mut r = read_effect(ctx, before, title, path);+ // A FRESH SESSION IS READ AGAIN: the 2026-10-15 death came a second after+ // the reply.+ let fresh = crate::readiness::attached_secs_ago(before.0, before.1).map(|s| s < 180).unwrap_or(false);+ if r.is_ok() && fresh && effect_recheck_ms() > 0 {+ std::thread::sleep(std::time::Duration::from_millis(effect_recheck_ms()));+ reads = 2;+ r = read_effect(ctx, before, title, path);+ }+ match r {+ Ok(mut v) => {+ v["reads"] = json!(reads);+ Ok(v)+ }+ Err((died, why)) => {+ let evidence = crate::perflog::crash_evidence();+ let code = if died { "host_app_died" } else { "document_not_created" };+ crate::ledger::record(+ code,+ json!({"verb": verb, "processId": before.0, "processCreatedAt": before.1, "documentReported": path.or(title),+ "why": why, "crashEvidence": evidence}),+ );+ let mut out = err_code(+ code,+ if died {+ format!("{verb} reported success, then SOLIDWORKS stopped: {why}. The document does not exist.")+ } else {+ format!("{verb} reported success, but {why}: the document was NOT created")+ },+ if died {+ "SOLIDWORKS died right after the command (measured 2026-10-15: 11 s after attach, a fresh start). \+ Nothing was created. Quote `crashEvidence`; let the user restart it (swx_start), and wait for \+ swx_status solidworks.ready before any document verb."+ } else {+ "The command's reply is not the effect. swx_docs shows what is really open; retry once SOLIDWORKS \+ is ready."+ },+ );+ if let Value::Object(m) = &mut out {+ m.insert("processId".into(), json!(before.0));+ m.insert("processCreatedAt".into(), json!(before.1));+ m.insert("documentReported".into(), json!(path.or(title)));+ m.insert("crashEvidence".into(), json!(evidence));+ m.insert("ledger".into(), json!(code));+ }+ Err(out)+ }+ }+}+ pub fn new_document(ctx: &Ctx, args: &Value) -> Value { gate!(ctx); let kind = arg_str(args, "type").unwrap_or("part").to_string();@@ -3957,6 +4093,7 @@ pub fn new_document(ctx: &Ctx, args: &Value) -> Value { call_args["scratchPath"] = json!(path.to_string_lossy()); } let started = std::time::Instant::now();+ let session_before = session_identity(ctx); match ctx.call("new_document", call_args, 110) { // A FAILED new_document IS THE EXHAUSTION SIGNAL. On 2026-09-03 both the // part and the assembly template came back with no document at 17.4 GB@@ -4012,6 +4149,19 @@ pub fn new_document(ctx: &Ctx, args: &Value) -> Value { None => ctx.remember_scratch(&now_titled, session), } }+ // THE EFFECT, before anything is recorded as created (0.11.3).+ let made_title = identity.get("title").and_then(|v| v.as_str()).map(String::from)+ .or_else(|| r.get("created").and_then(|c| c.get("title")).and_then(|t| t.as_str()).map(String::from));+ let made_path = identity.get("path").and_then(|p| p.as_str()).filter(|p| !p.is_empty()).map(String::from);+ let effect = match verify_effect(ctx, "swx_new_document", session_before, made_title.as_deref(), made_path.as_deref()) {+ Ok(v) => v,+ Err(e) => {+ if let Some(t) = &made_title {+ ctx.forget_scratch_doc(t, made_path.as_deref());+ }+ return e;+ }+ }; crate::ledger::record( "document_created", json!({@@ -4019,6 +4169,7 @@ pub fn new_document(ctx: &Ctx, args: &Value) -> Value { "type": kind, "template": r.get("template").cloned(), "visible": visible,+ "effect": effect, }), ); let mut r = r;@@ -4040,6 +4191,7 @@ pub fn new_document(ctx: &Ctx, args: &Value) -> Value { let titled_only = identity.get("identity").and_then(|v| v.as_str()) == Some("titleOnly"); ok_merge(r, json!({ "documentIdentity": identity,+ "effect": effect, "windowEtiquette": "background", "progress": job.finished(), "_hint": if !visible {@@ -4206,6 +4358,7 @@ pub fn import(ctx: &Ctx, args: &Value) -> Value { let before_docs = ownership_context(ctx).1; let before_titles: Vec<String> = before_docs.iter().map(doc_title).collect(); let before_count = Some(before_docs.len() as u64);+ let session_before = session_identity(ctx); let mut host_args = json!({"filePath": path}); if args.get("dissolve").and_then(|v| v.as_bool()).unwrap_or(false) { host_args["dissolve"] = json!(true);@@ -4301,9 +4454,16 @@ pub fn import(ctx: &Ctx, args: &Value) -> Value { None => ctx.remember_scratch(&now_titled, session), } }+ let made_title = identity.get("title").and_then(|v| v.as_str()).map(String::from)+ .or_else(|| r.get("imported").and_then(|c| c.get("title")).and_then(|t| t.as_str()).map(String::from));+ let made_path = identity.get("path").and_then(|p| p.as_str()).filter(|p| !p.is_empty()).map(String::from);+ let effect = match verify_effect(ctx, "swx_import", session_before, made_title.as_deref(), made_path.as_deref()) {+ Ok(v) => v,+ Err(e) => return e,+ }; crate::ledger::record( "document_created",- json!({"title": r.get("imported").and_then(|c| c.get("title")).cloned(), "via": "import"}),+ json!({"title": r.get("imported").and_then(|c| c.get("title")).cloned(), "via": "import", "effect": effect}), ); let mut r = r; if let Some(o) = r.as_object_mut() {
tests/common/mod.rs+5@@ -158,6 +158,11 @@ impl Bridge { .env("SWX_MOCK", "1") .env("ADOM_BIND_HOST", "127.0.0.1") .env("SWX_SCRATCH_DIR", scratch.path())+ // The fresh-attach settle (0.11.3) is 20 s in production; a test that+ // is ABOUT it sets its own.+ .env("SWX_READY_SETTLE_SECS", "0")+ // ...and so is the effect re-read of a fresh session (1.5 s).+ .env("SWX_EFFECT_RECHECK_MS", "0") // ab injects these; absent here on purpose so the callback path is // exercised in its "ab unreachable" shape. .env_remove("ADOM_DIRECT_API_URL")
tests/e2e.rs+1−1@@ -1646,7 +1646,7 @@ fn ownership_does_not_survive_a_solidworks_restart_or_a_close() { b, "a new SOLIDWORKS session REUSES the title Part1, exactly as the real one does", after_restart == "Part1",- after_restart.clone()+ format!("{after_restart} {}", s(&r)) ); let r = b.call("swx_reset_workspace", json!({"titles": ["nothing"]})); let tracked = r["trackedScratchDocuments"].as_array().cloned().unwrap_or_default();
tests/restart.rsadded+323@@ -0,0 +1,323 @@+//! A QUICK RESTART IS NOT READY (0.11.3) — from the laptop's ledger,+//! 2026-10-15, hosted 0.11.2, SOLIDWORKS 2026:+//!+//! | 22:40:01 | quit (processGone) |+//! | 22:40:02 | launch |+//! | 22:40:07 | sldworksUp |+//! | 22:40:39 | attached |+//! | 22:40:43 | `solidworks.ready` TRUE — 4 s after attach |+//! | 22:40:50 | swx_new_document OK, title `Part1-…SLDPRT`, ledger `document_created` |+//! | 22:40:51 | swx_docs: [] — SOLIDWORKS (pid 26316) had DIED |+//!+//! The 2026-10-01 crash again: a document command while an add-in was still+//! initialising. Everything here runs in the simulator.++mod common;++use common::{Bridge, TempDir};+use serde_json::{json, Value};+use std::time::{Duration, SystemTime};++fn s(v: &Value) -> String {+ serde_json::to_string_pretty(v).unwrap_or_default()+}++fn ledger(b: &Bridge) -> Vec<Value> {+ b.call("swx_action_ledger", json!({"limit": 500}))["actions"].as_array().cloned().unwrap_or_default()+}++fn now() -> u64 {+ SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs()+}++fn session(scratch: &TempDir) {+ std::fs::write(+ scratch.join("mock-solidworks-open-docs.json"),+ json!({"running": true, "untitled": 0, "active": Value::Null, "docs": [], "files": {}}).to_string(),+ )+ .unwrap();+}++/// A session the simulated machine started `age` seconds ago.+fn young_session(scratch: &TempDir, age: u64) {+ session(scratch);+ std::fs::write(scratch.join("mock-sldworks-created"), (now() - age).to_string()).unwrap();+}++fn set_mtime(p: &std::path::Path, secs_ago: u64) {+ std::fs::File::options()+ .write(true)+ .open(p)+ .unwrap()+ .set_modified(SystemTime::now() - Duration::from_secs(secs_ago))+ .unwrap();+}++/// The previous session's whole start, as its log holds it.+const PREVIOUS: &str = "; SolidWorks generated log file\n<AD2> \"LOAD_ADDIN\" \"SWK3DCompassAddin.dll\" \"3DEXPERIENCE for WORKS\"\n\+<3DXLOAD_TIME>24000</3DXLOAD_TIME>\n<PROCMEM> CMD:AppRunTime 1\n<PROCMEM> CMD:AppRunTime 2\n";++#[test]+fn a_marker_the_previous_session_wrote_never_makes_the_new_one_ready() {+ let scratch = TempDir::new("restart-stale");+ young_session(&scratch, 3);+ let log = scratch.join("SolidWorksPerformance.log");+ std::fs::write(&log, PREVIOUS).unwrap();+ // Last written 30 s ago: before this SOLIDWORKS started.+ set_mtime(&log, 30);+ let logp = log.to_string_lossy().to_string();+ let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[("SWX_PERF_LOG", &logp)]);+ b.call("swx_start", json!({}));+ let st = b.call("swx_status", json!({}));+ check!(+ b,+ "first sight: the log is still the previous session's — not ready, and its state is recorded as the baseline",+ st["solidworks"]["ready"] == false && scratch.join("perflog-baselines.json").exists(),+ s(&st["solidworks"]["readiness"])+ );+ // The NEW session touches the file — a line, no header, no add-in yet. The+ // old reading took the text after the last header: the previous session's+ // marker after its last LOAD_ADDIN — "complete".+ std::fs::write(&log, format!("{PREVIOUS}<PROCMEM> CMD:SessionStart\n")).unwrap();+ let r = b.call("swx_new_document", json!({"type": "part"}));+ let ev = r["readiness"].clone();+ check!(+ b,+ "a quick restart is NOT ready on the previous session's marker: host_app_starting",+ r["errorCode"] == "host_app_starting",+ s(&r)+ );+ let full = b.call("swx_status", json!({}));+ let pl = full["solidworks"]["readiness"]["evidence"][1].clone();+ check!(+ b,+ "...the evidence says the log was read from beyond the launch baseline, and holds no marker of this session",+ pl["launchBaseline"]["length"].as_u64() == Some(PREVIOUS.len() as u64)+ && pl["readFromOffset"].as_u64() == Some(PREVIOUS.len() as u64)+ && pl["marker"].is_null()+ && pl["rewrittenSinceBaseline"] == false,+ format!("{}\n{}", s(&full["solidworks"]["readiness"]), s(&ev))+ );+ // THIS session loads its add-ins and writes its own marker: ready.+ std::fs::write(+ &log,+ format!("{PREVIOUS}<PROCMEM> CMD:SessionStart\n<AD2> \"LOAD_ADDIN\" \"SWK3DCompassAddin.dll\" \"3DEXPERIENCE for WORKS\"\n<3DXLOAD_TIME>21000</3DXLOAD_TIME>\n"),+ )+ .unwrap();+ let r = b.call("swx_new_document", json!({"type": "part"}));+ check!(b, "this session's own marker, beyond the baseline: ready, the document is made", r["success"] == true, s(&r));+ let ready = ledger(&b).into_iter().find(|e| e["action"] == "solidworks_ready").unwrap_or(Value::Null);+ check!(+ b,+ "...and the transition is LEDGERED with the evidence that decided it",+ ready["detail"]["evidence"][1]["markerOffset"].as_u64().map(|o| o > PREVIOUS.len() as u64).unwrap_or(false),+ s(&ready)+ );+}++#[test]+fn a_rewritten_log_is_read_whole_and_its_marker_counts() {+ let scratch = TempDir::new("restart-rewritten");+ young_session(&scratch, 3);+ let log = scratch.join("SolidWorksPerformance.log");+ std::fs::write(&log, format!("{PREVIOUS}{}", "<PROCMEM> CMD:AppRunTime n\n".repeat(40))).unwrap();+ set_mtime(&log, 30);+ let logp = log.to_string_lossy().to_string();+ let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[("SWX_PERF_LOG", &logp)]);+ b.call("swx_start", json!({}));+ b.call("swx_status", json!({}));+ // REWRITTEN at the new start (measured 2026-10-01: one header, at the top).+ std::fs::write(&log, PREVIOUS).unwrap();+ let r = b.call("swx_new_document", json!({"type": "part"}));+ check!(b, "a log rewritten since the baseline is this session's: its marker counts", r["success"] == true, s(&r));+}++#[test]+fn a_log_rewritten_past_the_old_length_is_known_by_its_bytes_not_its_size() {+ let scratch = TempDir::new("restart-rewritten-long");+ young_session(&scratch, 3);+ let log = scratch.join("SolidWorksPerformance.log");+ std::fs::write(&log, PREVIOUS).unwrap();+ set_mtime(&log, 30);+ let logp = log.to_string_lossy().to_string();+ let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[("SWX_PERF_LOG", &logp)]);+ b.call("swx_start", json!({}));+ b.call("swx_status", json!({}));+ // Rewritten, this session's marker EARLY in it, and already LONGER than the+ // old file: only the bytes where the old file ended can tell.+ let mut fresh = String::from("; SolidWorks generated log file\n<AD2> \"LOAD_ADDIN\" \"SWK3DCompassAddin.dll\" \"3DEXPERIENCE for WORKS\"\n<3DXLOAD_TIME>19000</3DXLOAD_TIME>\n");+ while fresh.len() < PREVIOUS.len() * 3 {+ fresh.push_str("<PROCMEM> CMD:AppRunTime this-session\n");+ }+ std::fs::write(&log, fresh).unwrap();+ let r = b.call("swx_new_document", json!({"type": "part"}));+ check!(b, "rewritten (different bytes where the old file ended): its early marker counts", r["success"] == true, s(&r));+}++#[test]+fn the_ready_latch_belongs_to_one_process_identity() {+ let scratch = TempDir::new("restart-latch");+ session(&scratch);+ std::fs::write(scratch.join("mock-startup-incomplete"), "").unwrap();+ let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[("SWX_PERF_LOG", "")]);+ b.call("swx_start", json!({}));+ let st = b.call("swx_status", json!({}));+ let pid = st["solidworks"]["readiness"]["processId"].as_i64().unwrap();+ let created = st["solidworks"]["readiness"]["processCreatedAt"].as_u64().unwrap();+ // A latch for the SAME pid with ANOTHER creation time — the previous+ // session's — and one for another pid.+ std::fs::write(+ scratch.join("ready-sessions.json"),+ json!({format!("{pid}:{}", created - 7): {"readyAtMs": 1}, format!("{}:{created}", pid + 1): {"readyAtMs": 1}}).to_string(),+ )+ .unwrap();+ let st = b.call("swx_status", json!({}));+ check!(+ b,+ "a latch from another process identity never makes this session ready",+ st["solidworks"]["ready"] == false+ && !st["solidworks"]["readiness"]["basedOn"].as_array().map(|a| a.iter().any(|x| x == "readyBeforeThisBridgeRestarted")).unwrap_or(true),+ s(&st["solidworks"]["readiness"])+ );+ std::fs::write(scratch.join("ready-sessions.json"), json!({format!("{pid}:{created}"): {"readyAtMs": 1}}).to_string()).unwrap();+ let st = b.call("swx_status", json!({}));+ check!(b, "...THIS identity's latch does (a bridge restart keeps a verified session ready)", st["solidworks"]["ready"] == true, s(&st["solidworks"]["readiness"]));+}++#[test]+fn a_fresh_start_settles_after_attach_and_needs_com_to_say_it_completed() {+ let scratch = TempDir::new("restart-settle");+ young_session(&scratch, 2);+ let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[("SWX_PERF_LOG", ""), ("SWX_READY_SETTLE_SECS", "3")]);+ b.call("swx_start", json!({}));+ let r = b.call("swx_new_document", json!({"type": "part"}));+ check!(+ b,+ "attached a moment ago: host_app_starting — settling, with the evidence and its age",+ r["errorCode"] == "host_app_starting"+ && r["readiness"]["basedOn"].as_array().map(|a| a.iter().any(|x| x == "settleAfterAttach")).unwrap_or(false),+ s(&r)+ );+ let st = b.call("swx_status", json!({}));+ let settle = st["solidworks"]["readiness"]["evidence"][2].clone();+ check!(+ b,+ "...the settle evidence: required 3 s, not yet satisfied, anchored on the young session's first sight",+ settle["required"] == 3 && settle["satisfied"] == false && settle["anchor"] == "firstSeenYoung"+ && st["solidworks"]["readiness"]["why"].as_str().unwrap_or("").contains("settling"),+ s(&st["solidworks"]["readiness"])+ );+ std::thread::sleep(Duration::from_millis(3300));+ let r = b.call("swx_new_document", json!({"type": "part"}));+ check!(b, "after the settle: ready, the document is made", r["success"] == true, s(&r));++ // COM UNSURE on a fresh start: never ready on the log alone.+ let scratch2 = TempDir::new("restart-com");+ young_session(&scratch2, 2);+ std::fs::write(scratch2.join("mock-startup-unreadable"), "").unwrap();+ let log = scratch2.join("SolidWorksPerformance.log");+ std::fs::write(&log, PREVIOUS).unwrap();+ let logp = log.to_string_lossy().to_string();+ let b2 = Bridge::start_in(TempDir::borrowed(&scratch2.0), &[("SWX_PERF_LOG", &logp)]);+ b2.call("swx_start", json!({}));+ let st = b2.call("swx_status", json!({}));+ check!(+ b2,+ "a fresh start with a complete log but StartupProcessCompleted unknown is NOT ready",+ st["solidworks"]["ready"] == false+ && st["solidworks"]["readiness"]["why"].as_str().unwrap_or("").contains("StartupProcessCompleted"),+ s(&st["solidworks"]["readiness"])+ );+}++#[test]+fn a_document_solidworks_dies_right_after_is_never_reported_created() {+ let scratch = TempDir::new("restart-died");+ session(&scratch);+ let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[]);+ b.call("swx_start", json!({}));+ // The command answers, the identity save answers — then the process is gone.+ std::fs::write(scratch.join("mock-dies-after-new-document"), "1").unwrap();+ let r = b.call("swx_new_document", json!({"type": "part"}));+ check!(+ b,+ "swx_new_document: host_app_died, with the pid and the ledger line — never ok",+ r["success"] == false && r["errorCode"] == "host_app_died" && r["processId"].is_i64() && r["ledger"] == "host_app_died",+ s(&r)+ );+ let l = ledger(&b);+ check!(+ b,+ "...the ledger records the death, and NO document_created",+ l.iter().any(|e| e["action"] == "host_app_died" && e["detail"]["verb"] == "swx_new_document")+ && !l.iter().any(|e| e["action"] == "document_created"),+ s(&json!(l))+ );++ // A reply that names a document SOLIDWORKS does not have.+ let scratch2 = TempDir::new("restart-vanish");+ session(&scratch2);+ let b2 = Bridge::start_in(TempDir::borrowed(&scratch2.0), &[]);+ b2.call("swx_start", json!({}));+ // Another document is open, so the count alone cannot tell.+ let other = b2.call("swx_new_document", json!({"type": "part"}));+ check!(b2, "a first, real document", other["success"] == true, s(&other));+ std::fs::write(scratch2.join("mock-newdoc-vanishes"), "").unwrap();+ let r = b2.call("swx_new_document", json!({"type": "part", "keepUnsaved": true}));+ check!(+ b2,+ "a document missing from the live list: document_not_created, never ok",+ r["success"] == false && r["errorCode"] == "document_not_created",+ s(&r)+ );+ std::fs::remove_file(scratch2.join("mock-newdoc-vanishes")).unwrap();+ let ok = b2.call("swx_new_document", json!({"type": "part"}));+ check!(b2, "...and a real document reports the effect it verified", ok["success"] == true && ok["effect"]["verified"] == true, s(&ok));+}++#[test]+fn a_start_right_after_a_quit_waits_for_the_quit_sessions_process_tree() {+ let m = TempDir::new("restart-quit");+ std::fs::write(m.join("quit-script.json"), json!({"a": "exited"}).to_string()).unwrap();+ std::fs::write(m.join("windows.json"), "[]").unwrap();+ std::fs::write(m.join("sldworks.json"), json!({"responding": true, "hwnd": 6622700, "privateMB": 900, "handles": 4000}).to_string()).unwrap();+ // sldProcMon outlives the quit by 1.5 s; the platform daemons survive it+ // by design and must never be waited for.+ std::fs::write(+ m.join("preexisting.json"),+ json!([+ {"pid": 6076, "image": "3DEXPERIENCELauncher.exe", "ageSeconds": 30000},+ {"pid": 701, "image": "ENOPLMCSAClient.exe", "ageSeconds": 30000},+ {"pid": 800, "image": "sldProcMon.exe", "ageSeconds": 500, "reapedAfterQuitMs": 1500}+ ])+ .to_string(),+ )+ .unwrap();+ let b = Bridge::start_in(+ TempDir::new("restart-quit-scratch"),+ &[+ ("SWX_LAUNCH_FAKE_DIR", &m.path()),+ ("SWX_ALLOW_USER_WRITES", "1"),+ ("SWX_QUIT_SETTLE_MS", "80"),+ ("SWX_QUIT_EXIT_WAIT_SECS", "3"),+ ],+ );+ b.call("swx_start", json!({}));+ let st = b.call("swx_stop", json!({"userAuthorized": true, "confirm": true, "reason": "test: restart", "maxRung": "a"}));+ check!(b, "the quit goes through", st["stopped"] == true, s(&st));+ let r = b.call("swx_start", json!({}));+ let w = r["waitedForPreviousExit"].clone();+ check!(+ b,+ "the start right after it WAITED for the quit session's sldProcMon — not for the platform daemons",+ w["gone"] == true && w["waitedMs"].as_u64().unwrap_or(0) >= 700+ && !s(&w).contains("ENOPLMCSAClient") && !s(&w).contains("3DEXPERIENCELauncher"),+ s(&r)+ );+ check!(+ b,+ "...ledgered as launch_waited_for_previous_exit",+ ledger(&b).iter().any(|e| e["action"] == "launch_waited_for_previous_exit" && e["detail"]["gone"] == true),+ s(&json!(ledger(&b)))+ );+}
tools/cswa/reports/cswa-2026-10-15-sw2026-0.11.2.jsonadded+4571@@ -0,0 +1,4571 @@+{+ "tool": "cswa-check",+ "when": "2026-10-15T23:04:22Z",+ "whenEpoch": 1792105462,+ "target": "adom_drew2",+ "bridgeVersion": "0.11.2",+ "solidworks": {+ "majorVersion": 34,+ "edition": "connected",+ "versionSupport": {+ "lacks": [],+ "majorVersion": 34,+ "revision": "34.3.0",+ "supported": true,+ "supportedFrom": 2021,+ "tested": true,+ "testedOn": [+ 2026,+ 2021+ ],+ "year": 2026+ }+ },+ "summary": "8 of 8 CSWA parts within tolerance",+ "passed": 8,+ "ran": 8,+ "skipped": 1,+ "stopped": null,+ "allPassed": true,+ "parts": [+ {+ "id": "cswa-00-lego-2x4",+ "title": "LEGO 2x4 brick (spec 0: the acceptance brick, not an exam part)",+ "official": false,+ "source": "adom/solidworks-bridge issue #1 (Michael, SOLIDWORKS 2021: volumeM3 2.0733615208e-6 from swx_mass_properties); examples/lego-2x4.json",+ "expected": {+ "massG": 2.114829,+ "volumeMm3": 2073.3615208,+ "tolerancePct": 1.0+ },+ "material": {+ "name": "ABS",+ "densityKgM3": 1020+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 13690,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":12.2,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 10 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":10,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[],\"featuresDeleted\":0,\"passes\":0,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch_rect\",\"result\":{\"createdPlane\":null,\"entities\":[{\"rect\":{\"cornersMm\":[[-15.9,-7.9],[15.9,7.9]]}}],\"heightMm\":15.8,\"mapped\":false,\"plane\":\"Top Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"sketch.plane.top\",\"sketch.rect\"]},\"resolvedPlane\":null,\"sketch\":\"Sketch1\",\"sketchNormal\":[0.0,1.0,0.0],\"sketchedOn\":\"Top Plane\",\"transformInverted\":false,\"widthMm\":31.8},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":9.6,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,1.0,0.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude1\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch1\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"sketch_rect\",\"result\":{\"createdPlane\":null,\"entities\":[{\"rect\":{\"cornersMm\":[[-14.7,-6.7],[14.7,6.7]]}}],\"heightMm\":13.4,\"mapped\":false,\"plane\":\"Top Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"sketch.plane.top\",\"sketch.rect\"]},\"resolvedPlane\":null,\"sketch\":\"Sketch2\",\"sketchNormal\":[0.0,1.0,0.0],\"sketchedOn\":\"Top Plane\",\"transformInverted\":false,\"widthMm\":29.4},\"step\":4},{\"op\":\"cut\",\"result\":{\"depth2Mm\":null,\"depthMm\":8.6,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,1.0,0.0],\"value\":true},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Cut-Extrude1\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"cut.one.reversed\"]},\"reverse\":true,\"sketch\":\"Sketch2\",\"throughAll\":false,\"upToFace\":null},\"step\":5},{\"op\":\"sketch\",\"result\":{\"createdPlane\":null,\"entities\":[{\"circle\":{\"centerMm\":[-8.0,0.0],\"radiusMm\":3.255}},{\"circle\":{\"centerMm\":[-8.0,0.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[0.0,0.0],\"radiusMm\":3.255}},{\"circle\":{\"centerMm\":[0.0,0.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[8.0,0.0],\"radiusMm\":3.255}},{\"circle\":{\"centerMm\":[8.0,0.0],\"radiusMm\":2.4}}],\"mapped\":false,\"plane\":\"Top Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"sketch.plane.top\",\"sketch.circle\",\"sketch.multiProfile\"]},\"resolvedPlane\":null,\"sketch\":\"Sketch3\",\"sketchNormal\":[0.0,1.0,0.0],\"sketchedOn\":\"Top Plane\",\"transformInverted\":false},\"step\":6},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":8.6,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,1.0,0.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude2\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch3\",\"throughAll\":false,\"upToFace\":null},\"step\":7},{\"op\":\"sketch\",\"result\":{\"createdPlane\":\"Plane1\",\"entities\":[{\"circle\":{\"centerMm\":[-12.0,-4.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[-12.0,4.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[-4.0,-4.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[-4.0,4.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[4.0,-4.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[4.0,4.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[12.0,-4.0],\"radiusMm\":2.4}},{\"circle\":{\"centerMm\":[12.0,4.0],\"radiusMm\":2.4}}],\"mapped\":true,\"plane\":{\"offsetFrom\":\"Top Plane\",\"offsetMm\":9.6},\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"sketch.offset.top.positive\",\"sketch.circle\",\"sketch.multiProfile\"]},\"resolvedPlane\":{\"offsetFrom\":\"Top Plane\",\"offsetMm\":9.6,\"plane\":\"Plane1\",\"verified\":true},\"sketch\":\"Sketch4\",\"sketchNormal\":[0.0,1.0,0.0],\"sketchedOn\":\"Plane1\",\"transformInverted\":false},\"step\":8},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":1.7,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":[0.0,1.0,0.0],\"sketchNormal\":[0.0,1.0,0.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude3\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch4\",\"throughAll\":false,\"upToFace\":null},\"step\":9},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"ABS\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":1020.0,\"densityRequested\":1020.0,\"material\":\"ABS\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":10}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 12.2,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 10 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 10,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [],+ "featuresDeleted": 0,+ "passes": 0,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch_rect",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "rect": {+ "cornersMm": [+ [+ -15.9,+ -7.9+ ],+ [+ 15.9,+ 7.9+ ]+ ]+ }+ }+ ],+ "heightMm": 15.8,+ "mapped": false,+ "plane": "Top Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "sketch.plane.top",+ "sketch.rect"+ ]+ },+ "resolvedPlane": null,+ "sketch": "Sketch1",+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchedOn": "Top Plane",+ "transformInverted": false,+ "widthMm": 31.8+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 9.6,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude1",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch1",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "sketch_rect",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "rect": {+ "cornersMm": [+ [+ -14.7,+ -6.7+ ],+ [+ 14.7,+ 6.7+ ]+ ]+ }+ }+ ],+ "heightMm": 13.4,+ "mapped": false,+ "plane": "Top Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "sketch.plane.top",+ "sketch.rect"+ ]+ },+ "resolvedPlane": null,+ "sketch": "Sketch2",+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchedOn": "Top Plane",+ "transformInverted": false,+ "widthMm": 29.4+ },+ "step": 4+ },+ {+ "op": "cut",+ "result": {+ "depth2Mm": null,+ "depthMm": 8.6,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "value": true+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Cut-Extrude1",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "cut.one.reversed"+ ]+ },+ "reverse": true,+ "sketch": "Sketch2",+ "throughAll": false,+ "upToFace": null+ },+ "step": 5+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "circle": {+ "centerMm": [+ -8.0,+ 0.0+ ],+ "radiusMm": 3.255+ }+ },+ {+ "circle": {+ "centerMm": [+ -8.0,+ 0.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ 0.0,+ 0.0+ ],+ "radiusMm": 3.255+ }+ },+ {+ "circle": {+ "centerMm": [+ 0.0,+ 0.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ 8.0,+ 0.0+ ],+ "radiusMm": 3.255+ }+ },+ {+ "circle": {+ "centerMm": [+ 8.0,+ 0.0+ ],+ "radiusMm": 2.4+ }+ }+ ],+ "mapped": false,+ "plane": "Top Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "sketch.plane.top",+ "sketch.circle",+ "sketch.multiProfile"+ ]+ },+ "resolvedPlane": null,+ "sketch": "Sketch3",+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchedOn": "Top Plane",+ "transformInverted": false+ },+ "step": 6+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 8.6,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude2",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch3",+ "throughAll": false,+ "upToFace": null+ },+ "step": 7+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": "Plane1",+ "entities": [+ {+ "circle": {+ "centerMm": [+ -12.0,+ -4.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ -12.0,+ 4.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ -4.0,+ -4.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ -4.0,+ 4.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ 4.0,+ -4.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ 4.0,+ 4.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ 12.0,+ -4.0+ ],+ "radiusMm": 2.4+ }+ },+ {+ "circle": {+ "centerMm": [+ 12.0,+ 4.0+ ],+ "radiusMm": 2.4+ }+ }+ ],+ "mapped": true,+ "plane": {+ "offsetFrom": "Top Plane",+ "offsetMm": 9.6+ },+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "sketch.offset.top.positive",+ "sketch.circle",+ "sketch.multiProfile"+ ]+ },+ "resolvedPlane": {+ "offsetFrom": "Top Plane",+ "offsetMm": 9.6,+ "plane": "Plane1",+ "verified": true+ },+ "sketch": "Sketch4",+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchedOn": "Plane1",+ "transformInverted": false+ },+ "step": 8+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 1.7,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude3",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch4",+ "throughAll": false,+ "upToFace": null+ },+ "step": 9+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "ABS"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 1020.0,+ "densityRequested": 1020.0,+ "material": "ABS",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 10+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ -0.0159,+ 0.0,+ -0.0079,+ 0.0159,+ 0.0113,+ 0.0079+ ],+ "centerOfMass": [+ 3.4214491115036863e-19,+ 0.006193169977140961,+ -1.994781431613623e-19+ ],+ "centerOfMassMm": [+ 0.0,+ 6.19317,+ -0.0+ ],+ "density": 1020.0,+ "densityKgM3": 1020.0,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 1047,+ "error": "",+ "massG": 2.114828751242137,+ "massKg": 0.002114828751242137,+ "materialName": "ABS",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[-0.0159,0.0,-0.0079,0.0159,0.0113,0.0079],\"centerOfMass\":[3.4214491115036863e-19,0.006193169977140961,-1.994781431613623e-19],\"centerOfMassMm\":[0.0,6.19317,-0.0],\"density\":1020.0,\"densityKgM3\":1020.0,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":2.114828751242137,\"massKg\":0.002114828751242137,\"materialName\":\"ABS\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.003776753621558533,\"surfaceAreaMm2\":3776.753621558533,\"timeoutSeconds\":120,\"volumeM3\":2.0733615208256247e-6,\"volumeMm3\":2073.3615208256247}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.003776753621558533,+ "surfaceAreaMm2": 3776.753621558533,+ "timeoutSeconds": 120,+ "volumeM3": 2.0733615208256247e-06,+ "volumeMm3": 2073.3615208256247+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 2.114829,+ "measured": 2.114828751242137,+ "offPct": 1.1762552090642981e-05,+ "pass": true+ },+ {+ "quantity": "volumeMm3",+ "expected": 2073.3615208,+ "measured": 2073.3615208256247,+ "offPct": 1.2358943781890103e-09,+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 14.7+ },+ {+ "id": "cswa-01-3dengr-q5-block",+ "title": "3dengr Q5: a 100 x 20 x 60 block in 6061",+ "official": false,+ "source": "https://www.3dengr.com/cswa-practice-questions.html",+ "expected": {+ "massG": 324.0,+ "volumeMm3": 120000.0,+ "centerOfMassMm": [+ 50.0,+ 10.0,+ 30.0+ ],+ "tolerancePct": 1.0+ },+ "material": {+ "name": "6061 Alloy",+ "densityKgM3": 2700+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 8044,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":6.5,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 4 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":4,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[\"Sketch1\",\"Boss-Extrude1\",\"Cut-Extrude1\",\"Boss-Extrude2\",\"Plane1\",\"Sketch4\",\"Boss-Extrude3\",\"Sketch2\",\"Sketch3\"],\"featuresDeleted\":9,\"passes\":2,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch_rect\",\"result\":{\"createdPlane\":null,\"entities\":[{\"rect\":{\"cornersMm\":[[0.0,0.0],[100.0,20.0]]}}],\"heightMm\":20.0,\"mapped\":false,\"plane\":\"Front Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"sketch.plane.front\",\"sketch.rect\"]},\"resolvedPlane\":null,\"sketch\":\"Sketch5\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Front Plane\",\"transformInverted\":false,\"widthMm\":100.0},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":60.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude4\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch5\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"6061 Alloy\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":2700.0,\"densityRequested\":2700.0,\"material\":\"6061 Alloy\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":4}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 6.5,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 4 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 4,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [+ "Sketch1",+ "Boss-Extrude1",+ "Cut-Extrude1",+ "Boss-Extrude2",+ "Plane1",+ "Sketch4",+ "Boss-Extrude3",+ "Sketch2",+ "Sketch3"+ ],+ "featuresDeleted": 9,+ "passes": 2,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch_rect",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "rect": {+ "cornersMm": [+ [+ 0.0,+ 0.0+ ],+ [+ 100.0,+ 20.0+ ]+ ]+ }+ }+ ],+ "heightMm": 20.0,+ "mapped": false,+ "plane": "Front Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "sketch.plane.front",+ "sketch.rect"+ ]+ },+ "resolvedPlane": null,+ "sketch": "Sketch5",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Front Plane",+ "transformInverted": false,+ "widthMm": 100.0+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 60.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude4",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch5",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "6061 Alloy"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 2700.0,+ "densityRequested": 2700.0,+ "material": "6061 Alloy",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 4+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ 0.0,+ 0.0,+ 0.0,+ 0.1,+ 0.02,+ 0.06+ ],+ "centerOfMass": [+ 0.05,+ 0.01,+ 0.03+ ],+ "centerOfMassMm": [+ 50.0,+ 10.0,+ 30.0+ ],+ "density": 2700.0,+ "densityKgM3": 2700.0,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 1377,+ "error": "",+ "massG": 323.99999999999994,+ "massKg": 0.32399999999999995,+ "materialName": "6061 Alloy",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[0.0,0.0,0.0,0.1,0.02,0.06],\"centerOfMass\":[0.05,0.01,0.03],\"centerOfMassMm\":[50.0,10.0,30.0],\"density\":2700.0,\"densityKgM3\":2700.0,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":323.99999999999994,\"massKg\":0.32399999999999995,\"materialName\":\"6061 Alloy\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.0184,\"surfaceAreaMm2\":18400.0,\"timeoutSeconds\":120,\"volumeM3\":0.00012,\"volumeMm3\":120000.0}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.0184,+ "surfaceAreaMm2": 18400.0,+ "timeoutSeconds": 120,+ "volumeM3": 0.00012,+ "volumeMm3": 120000.0+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 324.0,+ "measured": 323.99999999999994,+ "offPct": 1.75442650804963e-14,+ "pass": true+ },+ {+ "quantity": "volumeMm3",+ "expected": 120000.0,+ "measured": 120000.0,+ "offPct": 0.0,+ "pass": true+ },+ {+ "quantity": "centerOfMassMm",+ "expected": [+ 50.0,+ 10.0,+ 30.0+ ],+ "measured": [+ 50.0,+ 10.0,+ 30.0+ ],+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 9.4+ },+ {+ "id": "cswa-02-3dengr-q6-hole",+ "title": "3dengr Q6/Q7: the block with a \u00d820 hole through it along Y at X 25, Z 30",+ "official": false,+ "source": "https://www.3dengr.com/cswa-practice-questions.html",+ "expected": {+ "massG": 307.04,+ "centerOfMassMm": [+ 51.38,+ 10.0,+ 30.0+ ],+ "tolerancePct": 1.0+ },+ "material": {+ "name": "6061 Alloy",+ "densityKgM3": 2700+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 10254,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":8.2,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 5 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":5,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[\"Sketch5\",\"Boss-Extrude4\"],\"featuresDeleted\":2,\"passes\":1,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch_rect\",\"result\":{\"createdPlane\":null,\"entities\":[{\"rect\":{\"cornersMm\":[[0.0,0.0],[100.0,20.0]]}}],\"heightMm\":20.0,\"mapped\":false,\"plane\":\"Front Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"sketch.plane.front\",\"sketch.rect\"]},\"resolvedPlane\":null,\"sketch\":\"Sketch6\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Front Plane\",\"transformInverted\":false,\"widthMm\":100.0},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":60.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude5\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch6\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"hole\",\"result\":{\"depthMm\":null,\"diameterMm\":20.0,\"face\":{\"atPointMm\":[25.0,20.0,30.0],\"heightMm\":20.0,\"normal\":[-0.0,1.0,-0.0],\"pickedBy\":\"geometry\",\"plane\":\"Top Plane\"},\"feature\":\"Cut-Extrude2\",\"features\":[\"Cut-Extrude2\"],\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"hole.simple\",\"what\":\"a plain hole: a circle on the face's plane, cut blind or through all\"}],\"variants\":[\"hole.simple\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"steps\":[{\"op\":\"sketch\",\"result\":{\"createdPlane\":\"Plane2\",\"entities\":[{\"circle\":{\"centerMm\":[25.0,-30.0],\"radiusMm\":10.0}}],\"mapped\":true,\"plane\":{\"offsetFrom\":\"Top Plane\",\"offsetMm\":20.0},\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"radiusMm\":10.0,\"resolvedPlane\":{\"offsetFrom\":\"Top Plane\",\"offsetMm\":20.0,\"plane\":\"Plane2\",\"verified\":true},\"sketch\":\"Sketch7\",\"sketchNormal\":[0.0,1.0,0.0],\"sketchedOn\":\"Plane2\",\"transformInverted\":false}},{\"op\":\"cut\",\"result\":{\"depth2Mm\":null,\"depthMm\":0.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":[0.0,1.0,0.0],\"sketchNormal\":[0.0,1.0,0.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":1,\"feature\":\"Cut-Extrude2\",\"reverse\":false,\"sketch\":\"Sketch7\",\"throughAll\":true,\"upToFace\":null}}],\"throughAll\":true},\"step\":4},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"6061 Alloy\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":2700.0,\"densityRequested\":2700.0,\"material\":\"6061 Alloy\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":5}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 8.2,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 5 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 5,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [+ "Sketch5",+ "Boss-Extrude4"+ ],+ "featuresDeleted": 2,+ "passes": 1,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch_rect",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "rect": {+ "cornersMm": [+ [+ 0.0,+ 0.0+ ],+ [+ 100.0,+ 20.0+ ]+ ]+ }+ }+ ],+ "heightMm": 20.0,+ "mapped": false,+ "plane": "Front Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "sketch.plane.front",+ "sketch.rect"+ ]+ },+ "resolvedPlane": null,+ "sketch": "Sketch6",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Front Plane",+ "transformInverted": false,+ "widthMm": 100.0+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 60.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude5",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch6",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "hole",+ "result": {+ "depthMm": null,+ "diameterMm": 20.0,+ "face": {+ "atPointMm": [+ 25.0,+ 20.0,+ 30.0+ ],+ "heightMm": 20.0,+ "normal": [+ -0.0,+ 1.0,+ -0.0+ ],+ "pickedBy": "geometry",+ "plane": "Top Plane"+ },+ "feature": "Cut-Extrude2",+ "features": [+ "Cut-Extrude2"+ ],+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "hole.simple",+ "what": "a plain hole: a circle on the face's plane, cut blind or through all"+ }+ ],+ "variants": [+ "hole.simple"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "steps": [+ {+ "op": "sketch",+ "result": {+ "createdPlane": "Plane2",+ "entities": [+ {+ "circle": {+ "centerMm": [+ 25.0,+ -30.0+ ],+ "radiusMm": 10.0+ }+ }+ ],+ "mapped": true,+ "plane": {+ "offsetFrom": "Top Plane",+ "offsetMm": 20.0+ },+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "radiusMm": 10.0,+ "resolvedPlane": {+ "offsetFrom": "Top Plane",+ "offsetMm": 20.0,+ "plane": "Plane2",+ "verified": true+ },+ "sketch": "Sketch7",+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchedOn": "Plane2",+ "transformInverted": false+ }+ },+ {+ "op": "cut",+ "result": {+ "depth2Mm": null,+ "depthMm": 0.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 1,+ "feature": "Cut-Extrude2",+ "reverse": false,+ "sketch": "Sketch7",+ "throughAll": true,+ "upToFace": null+ }+ }+ ],+ "throughAll": true+ },+ "step": 4+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "6061 Alloy"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 2700.0,+ "densityRequested": 2700.0,+ "material": "6061 Alloy",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 5+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ 0.0,+ 0.0,+ 0.0,+ 0.1,+ 0.02,+ 0.06+ ],+ "centerOfMass": [+ 0.05138132283342444,+ 0.009999999999999998,+ 0.029999999999999995+ ],+ "centerOfMassMm": [+ 51.381323,+ 10.0,+ 30.0+ ],+ "density": 2700.0,+ "densityKgM3": 2700.0,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 1759,+ "error": "",+ "massG": 307.0353996706151,+ "massKg": 0.3070353996706151,+ "materialName": "6061 Alloy",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[0.0,0.0,0.0,0.1,0.02,0.06],\"centerOfMass\":[0.05138132283342444,0.009999999999999998,0.029999999999999995],\"centerOfMassMm\":[51.381323,10.0,30.0],\"density\":2700.0,\"densityKgM3\":2700.0,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":307.0353996706151,\"massKg\":0.3070353996706151,\"materialName\":\"6061 Alloy\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.01902831853071796,\"surfaceAreaMm2\":19028.31853071796,\"timeoutSeconds\":120,\"volumeM3\":0.0001137168146928204,\"volumeMm3\":113716.8146928204}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.01902831853071796,+ "surfaceAreaMm2": 19028.31853071796,+ "timeoutSeconds": 120,+ "volumeM3": 0.0001137168146928204,+ "volumeMm3": 113716.8146928204+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 307.04,+ "measured": 307.0353996706151,+ "offPct": 0.0014982834109282007,+ "pass": true+ },+ {+ "quantity": "centerOfMassMm",+ "expected": [+ 51.38,+ 10.0,+ 30.0+ ],+ "measured": [+ 51.381323,+ 10.0,+ 30.0+ ],+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 12.0+ },+ {+ "id": "cswa-03-3dengr-q8-hole30",+ "title": "3dengr Q8: the hole changed to \u00d830",+ "official": false,+ "source": "https://www.3dengr.com/cswa-practice-questions.html",+ "expected": {+ "massG": 285.83,+ "tolerancePct": 1.0+ },+ "material": {+ "name": "6061 Alloy",+ "densityKgM3": 2700+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 10687,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":8.5,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 5 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":5,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[\"Sketch6\",\"Boss-Extrude5\",\"Plane2\",\"Sketch7\",\"Cut-Extrude2\"],\"featuresDeleted\":5,\"passes\":1,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch_rect\",\"result\":{\"createdPlane\":null,\"entities\":[{\"rect\":{\"cornersMm\":[[0.0,0.0],[100.0,20.0]]}}],\"heightMm\":20.0,\"mapped\":false,\"plane\":\"Front Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"sketch.plane.front\",\"sketch.rect\"]},\"resolvedPlane\":null,\"sketch\":\"Sketch8\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Front Plane\",\"transformInverted\":false,\"widthMm\":100.0},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":60.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude6\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch8\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"hole\",\"result\":{\"depthMm\":null,\"diameterMm\":30.0,\"face\":{\"atPointMm\":[25.0,20.0,30.0],\"heightMm\":20.0,\"normal\":[-0.0,1.0,-0.0],\"pickedBy\":\"geometry\",\"plane\":\"Top Plane\"},\"feature\":\"Cut-Extrude3\",\"features\":[\"Cut-Extrude3\"],\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"hole.simple\",\"what\":\"a plain hole: a circle on the face's plane, cut blind or through all\"}],\"variants\":[\"hole.simple\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"steps\":[{\"op\":\"sketch\",\"result\":{\"createdPlane\":\"Plane3\",\"entities\":[{\"circle\":{\"centerMm\":[25.0,-30.0],\"radiusMm\":15.0}}],\"mapped\":true,\"plane\":{\"offsetFrom\":\"Top Plane\",\"offsetMm\":20.0},\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"radiusMm\":15.0,\"resolvedPlane\":{\"offsetFrom\":\"Top Plane\",\"offsetMm\":20.0,\"plane\":\"Plane3\",\"verified\":true},\"sketch\":\"Sketch9\",\"sketchNormal\":[0.0,1.0,0.0],\"sketchedOn\":\"Plane3\",\"transformInverted\":false}},{\"op\":\"cut\",\"result\":{\"depth2Mm\":null,\"depthMm\":0.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":[0.0,1.0,0.0],\"sketchNormal\":[0.0,1.0,0.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":1,\"feature\":\"Cut-Extrude3\",\"reverse\":false,\"sketch\":\"Sketch9\",\"throughAll\":true,\"upToFace\":null}}],\"throughAll\":true},\"step\":4},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"6061 Alloy\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":2700.0,\"densityRequested\":2700.0,\"material\":\"6061 Alloy\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":5}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 8.5,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 5 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 5,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [+ "Sketch6",+ "Boss-Extrude5",+ "Plane2",+ "Sketch7",+ "Cut-Extrude2"+ ],+ "featuresDeleted": 5,+ "passes": 1,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch_rect",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "rect": {+ "cornersMm": [+ [+ 0.0,+ 0.0+ ],+ [+ 100.0,+ 20.0+ ]+ ]+ }+ }+ ],+ "heightMm": 20.0,+ "mapped": false,+ "plane": "Front Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "sketch.plane.front",+ "sketch.rect"+ ]+ },+ "resolvedPlane": null,+ "sketch": "Sketch8",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Front Plane",+ "transformInverted": false,+ "widthMm": 100.0+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 60.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude6",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch8",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "hole",+ "result": {+ "depthMm": null,+ "diameterMm": 30.0,+ "face": {+ "atPointMm": [+ 25.0,+ 20.0,+ 30.0+ ],+ "heightMm": 20.0,+ "normal": [+ -0.0,+ 1.0,+ -0.0+ ],+ "pickedBy": "geometry",+ "plane": "Top Plane"+ },+ "feature": "Cut-Extrude3",+ "features": [+ "Cut-Extrude3"+ ],+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "hole.simple",+ "what": "a plain hole: a circle on the face's plane, cut blind or through all"+ }+ ],+ "variants": [+ "hole.simple"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "steps": [+ {+ "op": "sketch",+ "result": {+ "createdPlane": "Plane3",+ "entities": [+ {+ "circle": {+ "centerMm": [+ 25.0,+ -30.0+ ],+ "radiusMm": 15.0+ }+ }+ ],+ "mapped": true,+ "plane": {+ "offsetFrom": "Top Plane",+ "offsetMm": 20.0+ },+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "radiusMm": 15.0,+ "resolvedPlane": {+ "offsetFrom": "Top Plane",+ "offsetMm": 20.0,+ "plane": "Plane3",+ "verified": true+ },+ "sketch": "Sketch9",+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchedOn": "Plane3",+ "transformInverted": false+ }+ },+ {+ "op": "cut",+ "result": {+ "depth2Mm": null,+ "depthMm": 0.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": [+ 0.0,+ 1.0,+ 0.0+ ],+ "sketchNormal": [+ 0.0,+ 1.0,+ 0.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 1,+ "feature": "Cut-Extrude3",+ "reverse": false,+ "sketch": "Sketch9",+ "throughAll": true,+ "upToFace": null+ }+ }+ ],+ "throughAll": true+ },+ "step": 4+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "6061 Alloy"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 2700.0,+ "densityRequested": 2700.0,+ "material": "6061 Alloy",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 5+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ 0.0,+ 0.0,+ 0.0,+ 0.1,+ 0.02,+ 0.06+ ],+ "centerOfMass": [+ 0.05333855767238339,+ 0.009999999999999998,+ 0.03+ ],+ "centerOfMassMm": [+ 53.338558,+ 10.0,+ 30.0+ ],+ "density": 2700.0,+ "densityKgM3": 2700.0,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 1085,+ "error": "",+ "massG": 285.829649258884,+ "massKg": 0.285829649258884,+ "materialName": "6061 Alloy",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[0.0,0.0,0.0,0.1,0.02,0.06],\"centerOfMass\":[0.05333855767238339,0.009999999999999998,0.03],\"centerOfMassMm\":[53.338558,10.0,30.0],\"density\":2700.0,\"densityKgM3\":2700.0,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":285.829649258884,\"massKg\":0.285829649258884,\"materialName\":\"6061 Alloy\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.01887123889803847,\"surfaceAreaMm2\":18871.238898038468,\"timeoutSeconds\":120,\"volumeM3\":0.00010586283305884592,\"volumeMm3\":105862.83305884592}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.01887123889803847,+ "surfaceAreaMm2": 18871.238898038468,+ "timeoutSeconds": 120,+ "volumeM3": 0.00010586283305884592,+ "volumeMm3": 105862.83305884592+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 285.83,+ "measured": 285.829649258884,+ "offPct": 0.00012270969317231364,+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 11.8+ },+ {+ "id": "cswa-04-3dengr-q9-l-bracket",+ "title": "3dengr Q9: an L-bracket in AISI 1020, ONE polyline sketch",+ "official": false,+ "source": "https://www.3dengr.com/cswa-practice-questions.html",+ "expected": {+ "massG": 410.8,+ "centerOfMassMm": [+ 26.54,+ 16.54,+ 20.0+ ],+ "tolerancePct": 1.0+ },+ "material": {+ "name": "AISI 1020",+ "densityKgM3": 7900+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 6099,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":4.7,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 4 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":4,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[\"Sketch8\",\"Boss-Extrude6\",\"Plane3\",\"Sketch9\",\"Cut-Extrude3\"],\"featuresDeleted\":5,\"passes\":1,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch\",\"result\":{\"createdPlane\":null,\"entities\":[{\"line\":{\"fromMm\":[0.0,0.0],\"toMm\":[80.0,0.0]}},{\"line\":{\"fromMm\":[80.0,0.0],\"toMm\":[80.0,10.0]}},{\"line\":{\"fromMm\":[80.0,10.0],\"toMm\":[10.0,10.0]}},{\"line\":{\"fromMm\":[10.0,10.0],\"toMm\":[10.0,60.0]}},{\"line\":{\"fromMm\":[10.0,60.0],\"toMm\":[0.0,60.0]}},{\"line\":{\"fromMm\":[0.0,60.0],\"toMm\":[0.0,0.0]}}],\"mapped\":false,\"plane\":\"Front Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"sketch.line\",\"what\":\"lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine\"}],\"variants\":[\"sketch.plane.front\",\"sketch.multiProfile\",\"sketch.line\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"resolvedPlane\":null,\"sketch\":\"Sketch10\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Front Plane\",\"transformInverted\":false},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":40.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude7\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch10\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"AISI 1020\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":7900.000000000001,\"densityRequested\":7900.0,\"material\":\"AISI 1020\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":4}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 4.7,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 4 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 4,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [+ "Sketch8",+ "Boss-Extrude6",+ "Plane3",+ "Sketch9",+ "Cut-Extrude3"+ ],+ "featuresDeleted": 5,+ "passes": 1,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "line": {+ "fromMm": [+ 0.0,+ 0.0+ ],+ "toMm": [+ 80.0,+ 0.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 80.0,+ 0.0+ ],+ "toMm": [+ 80.0,+ 10.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 80.0,+ 10.0+ ],+ "toMm": [+ 10.0,+ 10.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 10.0,+ 10.0+ ],+ "toMm": [+ 10.0,+ 60.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 10.0,+ 60.0+ ],+ "toMm": [+ 0.0,+ 60.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 0.0,+ 60.0+ ],+ "toMm": [+ 0.0,+ 0.0+ ]+ }+ }+ ],+ "mapped": false,+ "plane": "Front Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "sketch.line",+ "what": "lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine"+ }+ ],+ "variants": [+ "sketch.plane.front",+ "sketch.multiProfile",+ "sketch.line"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "resolvedPlane": null,+ "sketch": "Sketch10",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Front Plane",+ "transformInverted": false+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 40.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude7",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch10",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "AISI 1020"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 7900.000000000001,+ "densityRequested": 7900.0,+ "material": "AISI 1020",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 4+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ 0.0,+ 0.0,+ 0.0,+ 0.08,+ 0.06,+ 0.04+ ],+ "centerOfMass": [+ 0.026538461538461535,+ 0.016538461538461537,+ 0.019999999999999997+ ],+ "centerOfMassMm": [+ 26.538462,+ 16.538462,+ 20.0+ ],+ "density": 7900.000000000001,+ "densityKgM3": 7900.000000000001,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 1230,+ "error": "",+ "massG": 410.80000000000007,+ "massKg": 0.41080000000000005,+ "materialName": "AISI 1020",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[0.0,0.0,0.0,0.08,0.06,0.04],\"centerOfMass\":[0.026538461538461535,0.016538461538461537,0.019999999999999997],\"centerOfMassMm\":[26.538462,16.538462,20.0],\"density\":7900.000000000001,\"densityKgM3\":7900.000000000001,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":410.80000000000007,\"massKg\":0.41080000000000005,\"materialName\":\"AISI 1020\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.0138,\"surfaceAreaMm2\":13800.0,\"timeoutSeconds\":120,\"volumeM3\":0.000052,\"volumeMm3\":52000.0}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.0138,+ "surfaceAreaMm2": 13800.0,+ "timeoutSeconds": 120,+ "volumeM3": 5.2e-05,+ "volumeMm3": 52000.0+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 410.8,+ "measured": 410.80000000000007,+ "offPct": 1.3837248992407013e-14,+ "pass": true+ },+ {+ "quantity": "centerOfMassMm",+ "expected": [+ 26.54,+ 16.54,+ 20.0+ ],+ "measured": [+ 26.538462,+ 16.538462,+ 20.0+ ],+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 7.3+ },+ {+ "id": "cswa-05-tool-block-step1",+ "title": "Official Tool Block, Step 1 (Q3): A 81, B 57, C 43",+ "official": true,+ "source": "https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf (Dassault CSWA Sample Exam, 2017 edition; archive http://web.archive.org/web/20251230104817/https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf)",+ "expected": {+ "massG": 939.54,+ "tolerancePct": 1.0+ },+ "material": {+ "name": "AISI 1020",+ "densityKgM3": 7900+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 6621,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":4.9,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 4 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":4,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[\"Sketch10\",\"Boss-Extrude7\"],\"featuresDeleted\":2,\"passes\":1,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch\",\"result\":{\"createdPlane\":null,\"entities\":[{\"line\":{\"fromMm\":[0.0,18.0],\"toMm\":[18.243084987875623,14.783251905279968]}},{\"arc\":{\"ccw\":true,\"centerMm\":[21.5424003635473,33.494599212511915],\"endMm\":[38.0,24.0],\"radiusMm\":19.0,\"startMm\":[18.243084987875623,14.783251905279968]}},{\"line\":{\"fromMm\":[38.0,24.0],\"toMm\":[62.00000000000001,24.0]}},{\"line\":{\"fromMm\":[67.0,19.0],\"toMm\":[67.0,0.0]}},{\"line\":{\"fromMm\":[67.0,0.0],\"toMm\":[38.0,-33.0]}},{\"line\":{\"fromMm\":[38.0,-33.0],\"toMm\":[32.788067396763054,-33.0]}},{\"arc\":{\"ccw\":false,\"centerMm\":[54.69696969696975,-13.999999999999972],\"endMm\":[26.012264996781063,-18.264705882352946],\"radiusMm\":29.000000000000053,\"startMm\":[32.788067396763054,-33.0]}},{\"arc\":{\"ccw\":true,\"centerMm\":[21.066626255369176,-18.999999999999964],\"endMm\":[21.06662625536923,-14.0],\"radiusMm\":5.000000000000048,\"startMm\":[26.012264996781063,-18.264705882352946]}},{\"line\":{\"fromMm\":[21.06662625536923,-14.0],\"toMm\":[-7.0,-14.0]}},{\"line\":{\"fromMm\":[-14.0,-7.0],\"toMm\":[-14.0,11.000000000000002]}},{\"line\":{\"fromMm\":[-7.0,18.0],\"toMm\":[0.0,18.0]}},{\"line\":{\"fromMm\":[-14.0,11.000000000000002],\"toMm\":[-7.0,18.0]}},{\"line\":{\"fromMm\":[-7.0,-14.0],\"toMm\":[-14.0,-7.0]}},{\"line\":{\"fromMm\":[62.00000000000001,24.0],\"toMm\":[67.0,19.0]}},{\"circle\":{\"centerMm\":[0.0,0.0],\"radiusMm\":7.0}}],\"mapped\":false,\"plane\":\"Front Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"sketch.line\",\"what\":\"lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine\"},{\"variant\":\"sketch.arc\",\"what\":\"arcs of a closed contour (arc, arc3, tangentArc, slot, rounded rect): ISketchManager::CreateArc\"}],\"variants\":[\"sketch.plane.front\",\"sketch.circle\",\"sketch.multiProfile\",\"sketch.line\",\"sketch.arc\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"resolvedPlane\":null,\"sketch\":\"Sketch11\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Front Plane\",\"transformInverted\":false},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":43.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude8\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch11\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"AISI 1020\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":7900.0,\"densityRequested\":7900.0,\"material\":\"AISI 1020\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":4}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 4.9,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 4 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 4,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [+ "Sketch10",+ "Boss-Extrude7"+ ],+ "featuresDeleted": 2,+ "passes": 1,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "line": {+ "fromMm": [+ 0.0,+ 18.0+ ],+ "toMm": [+ 18.243084987875623,+ 14.783251905279968+ ]+ }+ },+ {+ "arc": {+ "ccw": true,+ "centerMm": [+ 21.5424003635473,+ 33.494599212511915+ ],+ "endMm": [+ 38.0,+ 24.0+ ],+ "radiusMm": 19.0,+ "startMm": [+ 18.243084987875623,+ 14.783251905279968+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 38.0,+ 24.0+ ],+ "toMm": [+ 62.00000000000001,+ 24.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 67.0,+ 19.0+ ],+ "toMm": [+ 67.0,+ 0.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 67.0,+ 0.0+ ],+ "toMm": [+ 38.0,+ -33.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 38.0,+ -33.0+ ],+ "toMm": [+ 32.788067396763054,+ -33.0+ ]+ }+ },+ {+ "arc": {+ "ccw": false,+ "centerMm": [+ 54.69696969696975,+ -13.999999999999972+ ],+ "endMm": [+ 26.012264996781063,+ -18.264705882352946+ ],+ "radiusMm": 29.000000000000053,+ "startMm": [+ 32.788067396763054,+ -33.0+ ]+ }+ },+ {+ "arc": {+ "ccw": true,+ "centerMm": [+ 21.066626255369176,+ -18.999999999999964+ ],+ "endMm": [+ 21.06662625536923,+ -14.0+ ],+ "radiusMm": 5.000000000000048,+ "startMm": [+ 26.012264996781063,+ -18.264705882352946+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 21.06662625536923,+ -14.0+ ],+ "toMm": [+ -7.0,+ -14.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -14.0,+ -7.0+ ],+ "toMm": [+ -14.0,+ 11.000000000000002+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -7.0,+ 18.0+ ],+ "toMm": [+ 0.0,+ 18.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -14.0,+ 11.000000000000002+ ],+ "toMm": [+ -7.0,+ 18.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -7.0,+ -14.0+ ],+ "toMm": [+ -14.0,+ -7.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 62.00000000000001,+ 24.0+ ],+ "toMm": [+ 67.0,+ 19.0+ ]+ }+ },+ {+ "circle": {+ "centerMm": [+ 0.0,+ 0.0+ ],+ "radiusMm": 7.0+ }+ }+ ],+ "mapped": false,+ "plane": "Front Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "sketch.line",+ "what": "lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine"+ },+ {+ "variant": "sketch.arc",+ "what": "arcs of a closed contour (arc, arc3, tangentArc, slot, rounded rect): ISketchManager::CreateArc"+ }+ ],+ "variants": [+ "sketch.plane.front",+ "sketch.circle",+ "sketch.multiProfile",+ "sketch.line",+ "sketch.arc"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "resolvedPlane": null,+ "sketch": "Sketch11",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Front Plane",+ "transformInverted": false+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 43.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude8",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch11",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "AISI 1020"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 7900.0,+ "densityRequested": 7900.0,+ "material": "AISI 1020",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 4+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ -0.014,+ -0.033,+ 0.0,+ 0.067,+ 0.024,+ 0.043+ ],+ "centerOfMass": [+ 0.03062236692252704,+ 0.0003076468646468399,+ 0.0215+ ],+ "centerOfMassMm": [+ 30.622367,+ 0.307647,+ 21.5+ ],+ "density": 7900.0,+ "densityKgM3": 7900.0,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 1094,+ "error": "",+ "massG": 939.5395682014018,+ "massKg": 0.9395395682014018,+ "materialName": "AISI 1020",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[-0.014,-0.033,0.0,0.067,0.024,0.043],\"centerOfMass\":[0.03062236692252704,0.0003076468646468399,0.0215],\"centerOfMassMm\":[30.622367,0.307647,21.5],\"density\":7900.0,\"densityKgM3\":7900.0,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":939.5395682014018,\"massKg\":0.9395395682014018,\"materialName\":\"AISI 1020\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.01763006429786853,\"surfaceAreaMm2\":17630.06429786853,\"timeoutSeconds\":120,\"volumeM3\":0.00011892905926600024,\"volumeMm3\":118929.05926600024}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.01763006429786853,+ "surfaceAreaMm2": 17630.06429786853,+ "timeoutSeconds": 120,+ "volumeM3": 0.00011892905926600024,+ "volumeMm3": 118929.05926600024+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 939.54,+ "measured": 939.5395682014018,+ "offPct": 4.595851141290499e-05,+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 7.7+ },+ {+ "id": "cswa-06-tool-block-step2",+ "title": "Official Tool Block, Step 2 (Q4): A 84, B 59, C 45, all other dimensions the same",+ "official": true,+ "source": "https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf (Dassault CSWA Sample Exam, 2017 edition; archive http://web.archive.org/web/20251230104817/https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf)",+ "expected": {+ "massG": 1032.32,+ "tolerancePct": 1.0+ },+ "material": {+ "name": "AISI 1020",+ "densityKgM3": 7900+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 6408,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":4.7,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 4 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":4,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[\"Sketch11\",\"Boss-Extrude8\"],\"featuresDeleted\":2,\"passes\":1,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch\",\"result\":{\"createdPlane\":null,\"entities\":[{\"line\":{\"fromMm\":[0.0,18.0],\"toMm\":[20.10404235201319,14.455114912034407]}},{\"arc\":{\"ccw\":true,\"centerMm\":[23.40335772768487,33.166462219266364],\"endMm\":[41.0,26.0],\"radiusMm\":19.0,\"startMm\":[20.10404235201319,14.455114912034407]}},{\"line\":{\"fromMm\":[41.0,26.0],\"toMm\":[65.0,26.0]}},{\"line\":{\"fromMm\":[70.0,21.0],\"toMm\":[70.0,2.0]}},{\"line\":{\"fromMm\":[70.0,2.0],\"toMm\":[41.0,-33.0]}},{\"line\":{\"fromMm\":[41.0,-33.0],\"toMm\":[34.8339548426505,-33.0]}},{\"arc\":{\"ccw\":false,\"centerMm\":[56.74285714285731,-14.000000000000036],\"endMm\":[28.0581524426685,-18.264705882352946],\"radiusMm\":29.000000000000107,\"startMm\":[34.8339548426505,-33.0]}},{\"arc\":{\"ccw\":true,\"centerMm\":[23.112513701256617,-18.999999999999982],\"endMm\":[23.112513701256667,-14.0],\"radiusMm\":5.0000000000000515,\"startMm\":[28.0581524426685,-18.264705882352946]}},{\"line\":{\"fromMm\":[23.112513701256667,-14.0],\"toMm\":[-7.0,-14.0]}},{\"line\":{\"fromMm\":[-14.0,-7.0],\"toMm\":[-14.0,11.000000000000002]}},{\"line\":{\"fromMm\":[-7.0,18.0],\"toMm\":[0.0,18.0]}},{\"line\":{\"fromMm\":[-14.0,11.000000000000002],\"toMm\":[-7.0,18.0]}},{\"line\":{\"fromMm\":[-7.0,-14.0],\"toMm\":[-14.0,-7.0]}},{\"line\":{\"fromMm\":[65.0,26.0],\"toMm\":[70.0,21.0]}},{\"circle\":{\"centerMm\":[0.0,0.0],\"radiusMm\":7.0}}],\"mapped\":false,\"plane\":\"Front Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"sketch.line\",\"what\":\"lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine\"},{\"variant\":\"sketch.arc\",\"what\":\"arcs of a closed contour (arc, arc3, tangentArc, slot, rounded rect): ISketchManager::CreateArc\"}],\"variants\":[\"sketch.plane.front\",\"sketch.circle\",\"sketch.multiProfile\",\"sketch.line\",\"sketch.arc\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"resolvedPlane\":null,\"sketch\":\"Sketch12\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Front Plane\",\"transformInverted\":false},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":45.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude9\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch12\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"AISI 1020\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":7899.999999999999,\"densityRequested\":7900.0,\"material\":\"AISI 1020\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":4}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 4.7,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 4 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 4,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [+ "Sketch11",+ "Boss-Extrude8"+ ],+ "featuresDeleted": 2,+ "passes": 1,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "line": {+ "fromMm": [+ 0.0,+ 18.0+ ],+ "toMm": [+ 20.10404235201319,+ 14.455114912034407+ ]+ }+ },+ {+ "arc": {+ "ccw": true,+ "centerMm": [+ 23.40335772768487,+ 33.166462219266364+ ],+ "endMm": [+ 41.0,+ 26.0+ ],+ "radiusMm": 19.0,+ "startMm": [+ 20.10404235201319,+ 14.455114912034407+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 41.0,+ 26.0+ ],+ "toMm": [+ 65.0,+ 26.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 70.0,+ 21.0+ ],+ "toMm": [+ 70.0,+ 2.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 70.0,+ 2.0+ ],+ "toMm": [+ 41.0,+ -33.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 41.0,+ -33.0+ ],+ "toMm": [+ 34.8339548426505,+ -33.0+ ]+ }+ },+ {+ "arc": {+ "ccw": false,+ "centerMm": [+ 56.74285714285731,+ -14.000000000000036+ ],+ "endMm": [+ 28.0581524426685,+ -18.264705882352946+ ],+ "radiusMm": 29.000000000000107,+ "startMm": [+ 34.8339548426505,+ -33.0+ ]+ }+ },+ {+ "arc": {+ "ccw": true,+ "centerMm": [+ 23.112513701256617,+ -18.999999999999982+ ],+ "endMm": [+ 23.112513701256667,+ -14.0+ ],+ "radiusMm": 5.0000000000000515,+ "startMm": [+ 28.0581524426685,+ -18.264705882352946+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 23.112513701256667,+ -14.0+ ],+ "toMm": [+ -7.0,+ -14.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -14.0,+ -7.0+ ],+ "toMm": [+ -14.0,+ 11.000000000000002+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -7.0,+ 18.0+ ],+ "toMm": [+ 0.0,+ 18.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -14.0,+ 11.000000000000002+ ],+ "toMm": [+ -7.0,+ 18.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -7.0,+ -14.0+ ],+ "toMm": [+ -14.0,+ -7.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 65.0,+ 26.0+ ],+ "toMm": [+ 70.0,+ 21.0+ ]+ }+ },+ {+ "circle": {+ "centerMm": [+ 0.0,+ 0.0+ ],+ "radiusMm": 7.0+ }+ }+ ],+ "mapped": false,+ "plane": "Front Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "sketch.line",+ "what": "lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine"+ },+ {+ "variant": "sketch.arc",+ "what": "arcs of a closed contour (arc, arc3, tangentArc, slot, rounded rect): ISketchManager::CreateArc"+ }+ ],+ "variants": [+ "sketch.plane.front",+ "sketch.circle",+ "sketch.multiProfile",+ "sketch.line",+ "sketch.arc"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "resolvedPlane": null,+ "sketch": "Sketch12",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Front Plane",+ "transformInverted": false+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 45.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude9",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch12",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "AISI 1020"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 7899.999999999999,+ "densityRequested": 7900.0,+ "material": "AISI 1020",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 4+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ -0.014,+ -0.033,+ 0.0,+ 0.07,+ 0.026,+ 0.045+ ],+ "centerOfMass": [+ 0.03255336787850931,+ 0.0007907183444125464,+ 0.0225+ ],+ "centerOfMassMm": [+ 32.553368,+ 0.790718,+ 22.5+ ],+ "density": 7899.999999999999,+ "densityKgM3": 7899.999999999999,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 1037,+ "error": "",+ "massG": 1032.3206766712835,+ "massKg": 1.0323206766712836,+ "materialName": "AISI 1020",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[-0.014,-0.033,0.0,0.07,0.026,0.045],\"centerOfMass\":[0.03255336787850931,0.0007907183444125464,0.0225],\"centerOfMassMm\":[32.553368,0.790718,22.5],\"density\":7899.999999999999,\"densityKgM3\":7899.999999999999,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":1032.3206766712835,\"massKg\":1.0323206766712836,\"materialName\":\"AISI 1020\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.0188741376700506,\"surfaceAreaMm2\":18874.137670050597,\"timeoutSeconds\":120,\"volumeM3\":0.00013067350337611186,\"volumeMm3\":130673.50337611184}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.0188741376700506,+ "surfaceAreaMm2": 18874.137670050597,+ "timeoutSeconds": 120,+ "volumeM3": 0.00013067350337611186,+ "volumeMm3": 130673.50337611184+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 1032.32,+ "measured": 1032.3206766712835,+ "offPct": 6.55485976828616e-05,+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 7.5+ },+ {+ "id": "cswa-07-tool-block-step3",+ "title": "Official Tool Block, Step 3 (Q5): A 86, B 58, C 44, then remove material",+ "official": true,+ "source": "https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf (Dassault CSWA Sample Exam, 2017 edition; archive http://web.archive.org/web/20251230104817/https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf)",+ "expected": {+ "massG": 628.18,+ "tolerancePct": 1.0+ },+ "material": {+ "name": "AISI 1020",+ "densityKgM3": 7900+ },+ "runScript": {+ "_hint": "Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.",+ "_timeoutHint": "ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "bridgeCreatedDocument": true,+ "created": null,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "documentName": "Part1-1792105365003.SLDPRT",+ "durationMs": 20797,+ "error": "",+ "ops": [+ "new_part",+ "new_assembly",+ "clear_part",+ "sketch",+ "sketch_rect",+ "sketch_circle",+ "extrude",+ "cut",+ "set_material",+ "set_appearance",+ "fillet",+ "chamfer",+ "shell",+ "revolve",+ "revolve_cut",+ "mirror",+ "hole",+ "linear_pattern",+ "circular_pattern",+ "set_prop",+ "save_as",+ "rebuild",+ "zoom_fit"+ ],+ "output": "{\"_hint\":\"Each step reports what it built. Verify with swx_inspect_bodies (the geometry) or swx_mass_properties (the mass) rather than trusting the step list. This document was created by the bridge, so swx_close_doc {save:false} discards the whole thing safely; swx_save_as puts it on disk. A step that fails stops the script and says which one, leaving what was already built in place.\",\"_timeoutHint\":\"ab waits up to 420s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"bridgeCreatedDocument\":true,\"created\":null,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"documentName\":\"Part1-1792105365003.SLDPRT\",\"ops\":[\"new_part\",\"new_assembly\",\"clear_part\",\"sketch\",\"sketch_rect\",\"sketch_circle\",\"extrude\",\"cut\",\"set_material\",\"set_appearance\",\"fillet\",\"chamfer\",\"shell\",\"revolve\",\"revolve_cut\",\"mirror\",\"hole\",\"linear_pattern\",\"circular_pattern\",\"set_prop\",\"save_as\",\"rebuild\",\"zoom_fit\"],\"progress\":{\"confidence\":\"estimate\",\"elapsedSec\":18.7,\"estimatedSec\":30,\"etaSec\":0,\"percent\":100,\"phase\":\"run_script\",\"startKind\":\"warm\",\"stepLabel\":\"Running 11 modeling step(s)\"},\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"solidworksRevision\":\"34.3.0\",\"statusVerb\":\"swx_status\",\"stepCount\":11,\"steps\":[{\"op\":\"clear_part\",\"result\":{\"bodiesLeft\":0,\"cleared\":\"Part1-1792105365003.SLDPRT\",\"deleted\":[\"Sketch12\",\"Boss-Extrude9\"],\"featuresDeleted\":2,\"passes\":1,\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.6\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"clear_part\"]},\"route\":\"DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty\"},\"step\":1},{\"op\":\"sketch\",\"result\":{\"createdPlane\":null,\"entities\":[{\"line\":{\"fromMm\":[0.0,18.0],\"toMm\":[22.3613808357771,14.057085232755291]}},{\"arc\":{\"ccw\":true,\"centerMm\":[25.66069621144878,32.768432539987224],\"endMm\":[43.0,25.0],\"radiusMm\":18.99999999999998,\"startMm\":[22.3613808357771,14.057085232755291]}},{\"line\":{\"fromMm\":[43.0,25.0],\"toMm\":[67.0,25.0]}},{\"line\":{\"fromMm\":[72.0,20.0],\"toMm\":[72.0,1.0]}},{\"line\":{\"fromMm\":[72.0,1.0],\"toMm\":[43.0,-33.0]}},{\"line\":{\"fromMm\":[43.0,-33.0],\"toMm\":[37.296980052734526,-33.0]}},{\"arc\":{\"ccw\":false,\"centerMm\":[59.20588235294099,-13.99999999999998],\"endMm\":[30.521177652752534,-18.264705882352946],\"radiusMm\":28.999999999999883,\"startMm\":[37.296980052734526,-33.0]}},{\"arc\":{\"ccw\":true,\"centerMm\":[25.575538911340765,-18.99999999999997],\"endMm\":[25.5755389113407,-14.0],\"radiusMm\":4.9999999999999325,\"startMm\":[30.521177652752534,-18.264705882352946]}},{\"line\":{\"fromMm\":[25.5755389113407,-14.0],\"toMm\":[-7.0,-14.0]}},{\"line\":{\"fromMm\":[-14.0,-7.0],\"toMm\":[-14.0,11.000000000000002]}},{\"line\":{\"fromMm\":[-7.0,18.0],\"toMm\":[0.0,18.0]}},{\"line\":{\"fromMm\":[-14.0,11.000000000000002],\"toMm\":[-7.0,18.0]}},{\"line\":{\"fromMm\":[-7.0,-14.0],\"toMm\":[-14.0,-7.0]}},{\"line\":{\"fromMm\":[67.0,25.0],\"toMm\":[72.0,20.0]}},{\"circle\":{\"centerMm\":[0.0,0.0],\"radiusMm\":7.0}}],\"mapped\":false,\"plane\":\"Front Plane\",\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"sketch.line\",\"what\":\"lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine\"},{\"variant\":\"sketch.arc\",\"what\":\"arcs of a closed contour (arc, arc3, tangentArc, slot, rounded rect): ISketchManager::CreateArc\"}],\"variants\":[\"sketch.plane.front\",\"sketch.circle\",\"sketch.multiProfile\",\"sketch.line\",\"sketch.arc\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"resolvedPlane\":null,\"sketch\":\"Sketch13\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Front Plane\",\"transformInverted\":false},\"step\":2},{\"op\":\"extrude\",\"result\":{\"depth2Mm\":null,\"depthMm\":44.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":null,\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Boss-Extrude10\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"extrude.one\"]},\"reverse\":false,\"sketch\":\"Sketch13\",\"throughAll\":false,\"upToFace\":null},\"step\":3},{\"op\":\"set_material\",\"result\":{\"appearanceReapplied\":[],\"current\":{\"database\":\"SOLIDWORKS Materials\",\"name\":\"AISI 1020\"},\"database\":\"SOLIDWORKS Materials.sldmat\",\"densityKgM3\":7899.999999999999,\"densityRequested\":7900.0,\"material\":\"AISI 1020\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"set_material.density\",\"what\":\"a density in kg/m\u00b3 (the document's own, or checked against the material's)\"}],\"variants\":[\"set_material\",\"set_material.density\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"}},\"step\":4},{\"op\":\"sketch\",\"result\":{\"createdPlane\":\"Plane4\",\"entities\":[{\"circle\":{\"centerMm\":[72.0,28.70187343596344],\"radiusMm\":41.0}}],\"mapped\":true,\"plane\":{\"offsetFrom\":{\"face\":{\"atPointMm\":[-10.0,0.0,0.0]}},\"offsetMm\":-12.0},\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"sketch.faceOffset\",\"what\":\"a sketch on a plane offset from a picked face (along its outward normal)\"}],\"variants\":[\"sketch.faceOffset\",\"sketch.circle\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"radiusMm\":41.0,\"resolvedPlane\":{\"faceNormal\":[-0.0,-0.0,-1.0],\"faceOffsetMm\":-12.0,\"fromFace\":true,\"offsetFrom\":\"Front Plane\",\"offsetMm\":12.0,\"pickedBy\":\"geometry\",\"plane\":\"Plane4\",\"verified\":true},\"sketch\":\"Sketch14\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Plane4\",\"transformInverted\":false},\"step\":5},{\"op\":\"cut\",\"result\":{\"depth2Mm\":null,\"depthMm\":24.0,\"dir\":{\"flippedToFollowTheReference\":true,\"reference\":[-0.0,-0.0,-1.0],\"sketchNormal\":[0.0,0.0,1.0],\"value\":true},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Cut-Extrude4\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"cut.one.reversed\"]},\"reverse\":false,\"sketch\":\"Sketch14\",\"throughAll\":false,\"upToFace\":null},\"step\":6},{\"op\":\"sketch\",\"result\":{\"createdPlane\":null,\"entities\":[{\"rect\":{\"cornersMm\":[[-20.0,-40.0],[85.99999999999999,-13.999999999999998]]}}],\"heightMm\":26.0,\"mapped\":true,\"plane\":{\"face\":{\"atPointMm\":[-10.0,0.0,44.0]}},\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"sketch.face.front.positive\",\"what\":\"a sketch on a face facing +Z\"}],\"variants\":[\"sketch.face.front.positive\",\"sketch.rect\",\"select.multiSelectTyped\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"resolvedPlane\":{\"faceNormal\":[0.0,0.0,1.0],\"offsetFrom\":\"Front Plane\",\"offsetMm\":44.0,\"pickedBy\":\"geometry\",\"selectedVia\":\"MultiSelect2(typed array)\",\"viewDependent\":false},\"sketch\":\"Sketch15\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"the picked face\",\"transformInverted\":false,\"widthMm\":106.0},\"step\":7},{\"op\":\"cut\",\"result\":{\"depth2Mm\":null,\"depthMm\":19.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":[0.0,0.0,1.0],\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Cut-Extrude5\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"cut.one\"]},\"reverse\":false,\"sketch\":\"Sketch15\",\"throughAll\":false,\"upToFace\":null},\"step\":8},{\"op\":\"sketch\",\"result\":{\"createdPlane\":null,\"entities\":[{\"rect\":{\"cornersMm\":[[-20.0,-40.0],[20.0,40.0]]}}],\"heightMm\":80.0,\"mapped\":true,\"plane\":{\"face\":{\"atPointMm\":[-10.0,0.0,44.0]}},\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"sketch.face.front.positive\",\"what\":\"a sketch on a face facing +Z\"}],\"variants\":[\"sketch.face.front.positive\",\"sketch.rect\",\"select.multiSelectTyped\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"resolvedPlane\":{\"faceNormal\":[0.0,0.0,1.0],\"offsetFrom\":\"Front Plane\",\"offsetMm\":44.0,\"pickedBy\":\"geometry\",\"selectedVia\":\"MultiSelect2(typed array)\",\"viewDependent\":false},\"sketch\":\"Sketch16\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"the picked face\",\"transformInverted\":false,\"widthMm\":40.0},\"step\":9},{\"op\":\"cut\",\"result\":{\"depth2Mm\":null,\"depthMm\":19.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":[0.0,0.0,1.0],\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":0,\"feature\":\"Cut-Extrude6\",\"proven\":{\"live\":true,\"measuredOn\":[{\"bridge\":\"0.10.3\",\"by\":\"adom\",\"date\":\"2026-10-14\",\"edition\":\"connected\",\"major\":34,\"solidworks\":2026},{\"bridge\":\"0.10.9\",\"by\":\"community\",\"date\":\"2026-10-15\",\"edition\":\"desktop\",\"major\":29,\"solidworks\":2021}],\"variants\":[\"cut.one\"]},\"reverse\":false,\"sketch\":\"Sketch16\",\"throughAll\":false,\"upToFace\":null},\"step\":10},{\"op\":\"hole\",\"result\":{\"depthMm\":null,\"diameterMm\":11.0,\"face\":{\"atPointMm\":[58.0,11.0,44.0],\"heightMm\":44.0,\"normal\":[0.0,0.0,1.0],\"pickedBy\":\"geometry\",\"plane\":\"Front Plane\"},\"feature\":\"Cut-Extrude7\",\"features\":[\"Cut-Extrude7\"],\"proven\":{\"live\":false,\"measuredOn\":[],\"unmeasured\":[{\"variant\":\"hole.simple\",\"what\":\"a plain hole: a circle on the face's plane, cut blind or through all\"}],\"variants\":[\"hole.simple\"],\"why\":\"not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies\"},\"steps\":[{\"op\":\"sketch\",\"result\":{\"createdPlane\":\"Plane5\",\"entities\":[{\"circle\":{\"centerMm\":[58.0,11.0],\"radiusMm\":5.5}}],\"mapped\":true,\"plane\":{\"offsetFrom\":\"Front Plane\",\"offsetMm\":44.0},\"planeFrames\":\"plane transforms (they match the measured Front/Top axes)\",\"radiusMm\":5.5,\"resolvedPlane\":{\"offsetFrom\":\"Front Plane\",\"offsetMm\":44.0,\"plane\":\"Plane5\",\"verified\":true},\"sketch\":\"Sketch17\",\"sketchNormal\":[0.0,0.0,1.0],\"sketchedOn\":\"Plane5\",\"transformInverted\":false}},{\"op\":\"cut\",\"result\":{\"depth2Mm\":null,\"depthMm\":0.0,\"dir\":{\"flippedToFollowTheReference\":false,\"reference\":[0.0,0.0,1.0],\"sketchNormal\":[0.0,0.0,1.0],\"value\":false},\"direction\":\"one\",\"draftDeg\":null,\"draftInward\":null,\"endCondition\":1,\"feature\":\"Cut-Extrude7\",\"reverse\":false,\"sketch\":\"Sketch17\",\"throughAll\":true,\"upToFace\":null}}],\"throughAll\":true},\"step\":11}],\"success\":true,\"targetDocument\":\"Part1-1792105365003.SLDPRT\",\"timeoutSeconds\":420}",+ "progress": {+ "confidence": "estimate",+ "elapsedSec": 18.7,+ "estimatedSec": 30,+ "etaSec": 0,+ "percent": 100,+ "phase": "run_script",+ "startKind": "warm",+ "stepLabel": "Running 11 modeling step(s)"+ },+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "solidworksRevision": "34.3.0",+ "status": "ok",+ "statusVerb": "swx_status",+ "stepCount": 11,+ "steps": [+ {+ "op": "clear_part",+ "result": {+ "bodiesLeft": 0,+ "cleared": "Part1-1792105365003.SLDPRT",+ "deleted": [+ "Sketch12",+ "Boss-Extrude9"+ ],+ "featuresDeleted": 2,+ "passes": 1,+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.6",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "clear_part"+ ]+ },+ "route": "DeleteSelection2(swDelete_Children | swDelete_Absorbed), repeated until the tree is empty"+ },+ "step": 1+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "line": {+ "fromMm": [+ 0.0,+ 18.0+ ],+ "toMm": [+ 22.3613808357771,+ 14.057085232755291+ ]+ }+ },+ {+ "arc": {+ "ccw": true,+ "centerMm": [+ 25.66069621144878,+ 32.768432539987224+ ],+ "endMm": [+ 43.0,+ 25.0+ ],+ "radiusMm": 18.99999999999998,+ "startMm": [+ 22.3613808357771,+ 14.057085232755291+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 43.0,+ 25.0+ ],+ "toMm": [+ 67.0,+ 25.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 72.0,+ 20.0+ ],+ "toMm": [+ 72.0,+ 1.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 72.0,+ 1.0+ ],+ "toMm": [+ 43.0,+ -33.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 43.0,+ -33.0+ ],+ "toMm": [+ 37.296980052734526,+ -33.0+ ]+ }+ },+ {+ "arc": {+ "ccw": false,+ "centerMm": [+ 59.20588235294099,+ -13.99999999999998+ ],+ "endMm": [+ 30.521177652752534,+ -18.264705882352946+ ],+ "radiusMm": 28.999999999999883,+ "startMm": [+ 37.296980052734526,+ -33.0+ ]+ }+ },+ {+ "arc": {+ "ccw": true,+ "centerMm": [+ 25.575538911340765,+ -18.99999999999997+ ],+ "endMm": [+ 25.5755389113407,+ -14.0+ ],+ "radiusMm": 4.9999999999999325,+ "startMm": [+ 30.521177652752534,+ -18.264705882352946+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 25.5755389113407,+ -14.0+ ],+ "toMm": [+ -7.0,+ -14.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -14.0,+ -7.0+ ],+ "toMm": [+ -14.0,+ 11.000000000000002+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -7.0,+ 18.0+ ],+ "toMm": [+ 0.0,+ 18.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -14.0,+ 11.000000000000002+ ],+ "toMm": [+ -7.0,+ 18.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ -7.0,+ -14.0+ ],+ "toMm": [+ -14.0,+ -7.0+ ]+ }+ },+ {+ "line": {+ "fromMm": [+ 67.0,+ 25.0+ ],+ "toMm": [+ 72.0,+ 20.0+ ]+ }+ },+ {+ "circle": {+ "centerMm": [+ 0.0,+ 0.0+ ],+ "radiusMm": 7.0+ }+ }+ ],+ "mapped": false,+ "plane": "Front Plane",+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "sketch.line",+ "what": "lines of a closed contour (line, polyline, polygon, slot, rounded rect): ISketchManager::CreateLine"+ },+ {+ "variant": "sketch.arc",+ "what": "arcs of a closed contour (arc, arc3, tangentArc, slot, rounded rect): ISketchManager::CreateArc"+ }+ ],+ "variants": [+ "sketch.plane.front",+ "sketch.circle",+ "sketch.multiProfile",+ "sketch.line",+ "sketch.arc"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "resolvedPlane": null,+ "sketch": "Sketch13",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Front Plane",+ "transformInverted": false+ },+ "step": 2+ },+ {+ "op": "extrude",+ "result": {+ "depth2Mm": null,+ "depthMm": 44.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": null,+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Boss-Extrude10",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "extrude.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch13",+ "throughAll": false,+ "upToFace": null+ },+ "step": 3+ },+ {+ "op": "set_material",+ "result": {+ "appearanceReapplied": [],+ "current": {+ "database": "SOLIDWORKS Materials",+ "name": "AISI 1020"+ },+ "database": "SOLIDWORKS Materials.sldmat",+ "densityKgM3": 7899.999999999999,+ "densityRequested": 7900.0,+ "material": "AISI 1020",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "set_material.density",+ "what": "a density in kg/m\u00b3 (the document's own, or checked against the material's)"+ }+ ],+ "variants": [+ "set_material",+ "set_material.density"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ }+ },+ "step": 4+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": "Plane4",+ "entities": [+ {+ "circle": {+ "centerMm": [+ 72.0,+ 28.70187343596344+ ],+ "radiusMm": 41.0+ }+ }+ ],+ "mapped": true,+ "plane": {+ "offsetFrom": {+ "face": {+ "atPointMm": [+ -10.0,+ 0.0,+ 0.0+ ]+ }+ },+ "offsetMm": -12.0+ },+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "sketch.faceOffset",+ "what": "a sketch on a plane offset from a picked face (along its outward normal)"+ }+ ],+ "variants": [+ "sketch.faceOffset",+ "sketch.circle"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "radiusMm": 41.0,+ "resolvedPlane": {+ "faceNormal": [+ -0.0,+ -0.0,+ -1.0+ ],+ "faceOffsetMm": -12.0,+ "fromFace": true,+ "offsetFrom": "Front Plane",+ "offsetMm": 12.0,+ "pickedBy": "geometry",+ "plane": "Plane4",+ "verified": true+ },+ "sketch": "Sketch14",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Plane4",+ "transformInverted": false+ },+ "step": 5+ },+ {+ "op": "cut",+ "result": {+ "depth2Mm": null,+ "depthMm": 24.0,+ "dir": {+ "flippedToFollowTheReference": true,+ "reference": [+ -0.0,+ -0.0,+ -1.0+ ],+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": true+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Cut-Extrude4",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "cut.one.reversed"+ ]+ },+ "reverse": false,+ "sketch": "Sketch14",+ "throughAll": false,+ "upToFace": null+ },+ "step": 6+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "rect": {+ "cornersMm": [+ [+ -20.0,+ -40.0+ ],+ [+ 85.99999999999999,+ -13.999999999999998+ ]+ ]+ }+ }+ ],+ "heightMm": 26.0,+ "mapped": true,+ "plane": {+ "face": {+ "atPointMm": [+ -10.0,+ 0.0,+ 44.0+ ]+ }+ },+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "sketch.face.front.positive",+ "what": "a sketch on a face facing +Z"+ }+ ],+ "variants": [+ "sketch.face.front.positive",+ "sketch.rect",+ "select.multiSelectTyped"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "resolvedPlane": {+ "faceNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "offsetFrom": "Front Plane",+ "offsetMm": 44.0,+ "pickedBy": "geometry",+ "selectedVia": "MultiSelect2(typed array)",+ "viewDependent": false+ },+ "sketch": "Sketch15",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "the picked face",+ "transformInverted": false,+ "widthMm": 106.0+ },+ "step": 7+ },+ {+ "op": "cut",+ "result": {+ "depth2Mm": null,+ "depthMm": 19.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Cut-Extrude5",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "cut.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch15",+ "throughAll": false,+ "upToFace": null+ },+ "step": 8+ },+ {+ "op": "sketch",+ "result": {+ "createdPlane": null,+ "entities": [+ {+ "rect": {+ "cornersMm": [+ [+ -20.0,+ -40.0+ ],+ [+ 20.0,+ 40.0+ ]+ ]+ }+ }+ ],+ "heightMm": 80.0,+ "mapped": true,+ "plane": {+ "face": {+ "atPointMm": [+ -10.0,+ 0.0,+ 44.0+ ]+ }+ },+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "sketch.face.front.positive",+ "what": "a sketch on a face facing +Z"+ }+ ],+ "variants": [+ "sketch.face.front.positive",+ "sketch.rect",+ "select.multiSelectTyped"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "resolvedPlane": {+ "faceNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "offsetFrom": "Front Plane",+ "offsetMm": 44.0,+ "pickedBy": "geometry",+ "selectedVia": "MultiSelect2(typed array)",+ "viewDependent": false+ },+ "sketch": "Sketch16",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "the picked face",+ "transformInverted": false,+ "widthMm": 40.0+ },+ "step": 9+ },+ {+ "op": "cut",+ "result": {+ "depth2Mm": null,+ "depthMm": 19.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 0,+ "feature": "Cut-Extrude6",+ "proven": {+ "live": true,+ "measuredOn": [+ {+ "bridge": "0.10.3",+ "by": "adom",+ "date": "2026-10-14",+ "edition": "connected",+ "major": 34,+ "solidworks": 2026+ },+ {+ "bridge": "0.10.9",+ "by": "community",+ "date": "2026-10-15",+ "edition": "desktop",+ "major": 29,+ "solidworks": 2021+ }+ ],+ "variants": [+ "cut.one"+ ]+ },+ "reverse": false,+ "sketch": "Sketch16",+ "throughAll": false,+ "upToFace": null+ },+ "step": 10+ },+ {+ "op": "hole",+ "result": {+ "depthMm": null,+ "diameterMm": 11.0,+ "face": {+ "atPointMm": [+ 58.0,+ 11.0,+ 44.0+ ],+ "heightMm": 44.0,+ "normal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "pickedBy": "geometry",+ "plane": "Front Plane"+ },+ "feature": "Cut-Extrude7",+ "features": [+ "Cut-Extrude7"+ ],+ "proven": {+ "live": false,+ "measuredOn": [],+ "unmeasured": [+ {+ "variant": "hole.simple",+ "what": "a plain hole: a circle on the face's plane, cut blind or through all"+ }+ ],+ "variants": [+ "hole.simple"+ ],+ "why": "not measured live: see `unmeasured` \u2014 verify this step's geometry with swx_inspect_bodies"+ },+ "steps": [+ {+ "op": "sketch",+ "result": {+ "createdPlane": "Plane5",+ "entities": [+ {+ "circle": {+ "centerMm": [+ 58.0,+ 11.0+ ],+ "radiusMm": 5.5+ }+ }+ ],+ "mapped": true,+ "plane": {+ "offsetFrom": "Front Plane",+ "offsetMm": 44.0+ },+ "planeFrames": "plane transforms (they match the measured Front/Top axes)",+ "radiusMm": 5.5,+ "resolvedPlane": {+ "offsetFrom": "Front Plane",+ "offsetMm": 44.0,+ "plane": "Plane5",+ "verified": true+ },+ "sketch": "Sketch17",+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchedOn": "Plane5",+ "transformInverted": false+ }+ },+ {+ "op": "cut",+ "result": {+ "depth2Mm": null,+ "depthMm": 0.0,+ "dir": {+ "flippedToFollowTheReference": false,+ "reference": [+ 0.0,+ 0.0,+ 1.0+ ],+ "sketchNormal": [+ 0.0,+ 0.0,+ 1.0+ ],+ "value": false+ },+ "direction": "one",+ "draftDeg": null,+ "draftInward": null,+ "endCondition": 1,+ "feature": "Cut-Extrude7",+ "reverse": false,+ "sketch": "Sketch17",+ "throughAll": true,+ "upToFace": null+ }+ }+ ],+ "throughAll": true+ },+ "step": 11+ }+ ],+ "success": true,+ "targetDocument": "Part1-1792105365003.SLDPRT",+ "timeoutSeconds": 420+ },+ "massProperties": {+ "_hint": "SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.",+ "_timeoutHint": "ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.",+ "boundingBox": [+ -0.014,+ -0.033,+ 0.0,+ 0.07200000000000001,+ 0.025,+ 0.044+ ],+ "centerOfMass": [+ 0.03174279639698831,+ -0.0008683174573996883,+ 0.017834837095750275+ ],+ "centerOfMassMm": [+ 31.742796,+ -0.868317,+ 17.834837+ ],+ "density": 7900.0,+ "densityKgM3": 7900.0,+ "doc": {+ "config": "Default",+ "dirty": true,+ "path": "C:/Users/drew/AppData/Local/adom-solidworks-bridge/exports/scratch/Part1-1792105365003.SLDPRT",+ "title": "Part1-1792105365003.SLDPRT",+ "type": "part"+ },+ "durationMs": 2150,+ "error": "",+ "massG": 628.1833833399141,+ "massKg": 0.6281833833399142,+ "materialName": "AISI 1020",+ "output": "{\"_hint\":\"SI units: kg, m^3, m^2, m. Mass is only as good as the material assignment \u2014 a 0 or default density means no material is set on the model, so report the density alongside the mass.\",\"_timeoutHint\":\"ab waits up to 120s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `swx_status` until it reports done.\",\"boundingBox\":[-0.014,-0.033,0.0,0.07200000000000001,0.025,0.044],\"centerOfMass\":[0.03174279639698831,-0.0008683174573996883,0.017834837095750275],\"centerOfMassMm\":[31.742796,-0.868317,17.834837],\"density\":7900.0,\"densityKgM3\":7900.0,\"doc\":{\"config\":\"Default\",\"dirty\":true,\"path\":\"C:\\\\Users\\\\drew\\\\AppData\\\\Local\\\\adom-solidworks-bridge\\\\exports\\\\scratch\\\\Part1-1792105365003.SLDPRT\",\"title\":\"Part1-1792105365003.SLDPRT\",\"type\":\"part\"},\"massG\":628.1833833399141,\"massKg\":0.6281833833399142,\"materialName\":\"AISI 1020\",\"readiness\":{\"basedOn\":[\"alreadyReadyThisSession\"],\"evaluatedAt\":\"gate\",\"readsAllowed\":true,\"ready\":true,\"running\":true,\"state\":\"ready\",\"why\":null},\"statusVerb\":\"swx_status\",\"success\":true,\"surfaceAreaM2\":0.01771252880409412,\"surfaceAreaMm2\":17712.52880409412,\"timeoutSeconds\":120,\"volumeM3\":0.00007951688396707775,\"volumeMm3\":79516.88396707775}",+ "readiness": {+ "basedOn": [+ "alreadyReadyThisSession"+ ],+ "evaluatedAt": "gate",+ "readsAllowed": true,+ "ready": true,+ "running": true,+ "state": "ready",+ "why": null+ },+ "schemaVersion": 1,+ "status": "ok",+ "statusVerb": "swx_status",+ "success": true,+ "surfaceAreaM2": 0.01771252880409412,+ "surfaceAreaMm2": 17712.52880409412,+ "timeoutSeconds": 120,+ "volumeM3": 7.951688396707775e-05,+ "volumeMm3": 79516.88396707775+ },+ "pass": true,+ "checks": [+ {+ "quantity": "massG",+ "expected": 628.18,+ "measured": 628.1833833399141,+ "offPct": 0.0005385940198978062,+ "pass": true+ }+ ],+ "fails": [],+ "seconds": 23.0+ },+ {+ "id": "cswa-08-tool-block-step4",+ "title": "Official Tool Block, Step 4 (Q6): a pocket 1 mm inside the front face's outline",+ "official": true,+ "source": "https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf (Dassault CSWA Sample Exam, 2017 edition; archive http://web.archive.org/web/20251230104817/https://www.solidworks.com/sites/default/files/2017-12/CSWASampleExam.pdf)",+ "expected": {+ "massG": 432.58,+ "tolerancePct": 1.0+ },+ "material": {+ "name": "AISI 1020",+ "densityKgM3": 7900+ },+ "skipped": "needs ops the bridge does not have yet: offsetEntities"+ }+ ]+}
tools/cswa/tb34.pyadded+77@@ -0,0 +1,77 @@+import math, sys+sys.path.insert(0,'.')+from tb2 import toolblock, area+def clip_halfplane(poly, nx, ny, c):+ # keep points with nx*x+ny*y <= c+ out=[]; n=len(poly)+ for i in range(n):+ P=poly[i]; Q=poly[(i+1)%n]+ pin=nx*P[0]+ny*P[1]<=c; qin=nx*Q[0]+ny*Q[1]<=c+ if pin: out.append(P)+ if pin!=qin:+ t=(c-nx*P[0]-ny*P[1])/((nx*(Q[0]-P[0])+ny*(Q[1]-P[1])))+ out.append((P[0]+t*(Q[0]-P[0]),P[1]+t*(Q[1]-P[1])))+ return out+def clip_disc(poly,cx,cy,r,n=720):+ for k in range(n):+ a=2*math.pi*k/n; nx,ny=math.cos(a),math.sin(a)+ poly=clip_halfplane(poly,nx,ny,nx*cx+ny*cy+r)+ if not poly: break+ return poly+def circle_poly(cx,cy,r,n=2000): return [(cx+r*math.cos(2*math.pi*i/n),cy+r*math.sin(2*math.pi*i/n)) for i in range(n)]+A,B,C=86,58,44+prof,_,info,P=toolblock(A,B,C,top=B-33.0,redge=B-57.0)+Aprof=area(P) # outer profile without holes+hole14=math.pi*49; hole11=math.pi*5.5**2+xstep=(A-52)-14.0 # hole coords+Pstep=clip_halfplane(P,1,0,xstep); Astep=area(Pstep)+print("profile area (no holes) %.2f ; step region (x<=%.0f) area %.2f"%(Aprof,xstep,Astep))+target3=628.18/0.0079; target4=432.58/0.0079+def vol3(cx,cy,zslot=24.0,zstep=19.0):+ Aslot=area(clip_disc(P,cx,cy,41.0))+ V=Aprof*C - Astep*zstep - Aslot*zslot - hole14*(C-zstep) - hole11*(C-zslot)+ return V,Aslot+xR=A-14.0+# hypotheses for R41 center+yc_flank36 = -11+math.sqrt(41**2-(xR-(43+29*(22/34.0)))**2)+cands=[("center on right edge, thru flank@36 -> (72,%.2f)"%yc_flank36,(xR,yc_flank36)),+ ("center top-right corner (72,25)",(xR,25.0)),+ ("pixel fit (72.4,28.6)",(72.4,28.6)),+ ("center (72,28.0)",(xR,28.0)),("center (72,29.5)",(xR,29.5))]+for name,(cx,cy) in cands:+ V,As=vol3(cx,cy); print("STEP3 %-50s slotA=%.1f V=%.1f mass=%.2f (key 628.18, diff %+.2f%%)"%(name,As,V,V*0.0079,(V/target3-1)*100))+# sensitivity: slot z-width 24 vs step side+cx,cy=xR,yc_flank36+for zs in (22,24,26):+ V,_=vol3(cx,cy,zslot=zs); print(" zslot=%d -> mass %.2f"%(zs,V*0.0079))+# STEP 4: pocket. Outline = outer profile offset 1 inward, clipped to x>=xstep+1 and y>=-13; depth 32 from front (leaves 12 at back)+def offset_inward(poly,d,n=None):+ # approximate inward offset by clipping with every edge's half-plane shifted by d (valid for convex-ish boundary parts; polygon here is non-convex, so do per-edge clipping only on edges we care about -> use generic approach: clip by each edge halfplane shifted inward)+ out=poly+ m=len(poly)+ # signed area to know orientation+ s=sum(poly[i][0]*poly[(i+1)%m][1]-poly[(i+1)%m][0]*poly[i][1] for i in range(m))+ ccw = s>0+ for i in range(m):+ P0=poly[i]; P1=poly[(i+1)%m]+ ex,ey=P1[0]-P0[0],P1[1]-P0[1]; L=math.hypot(ex,ey)+ if L<1e-9: continue+ # outward normal+ nx,ny=(ey/L,-ex/L) if ccw else (-ey/L,ex/L)+ c=nx*P0[0]+ny*P0[1]-d+ # only clip with edges that are on the right-lobe region boundary (x>xstep-5) to avoid the notch/left lobe edges eating the pocket wrongly+ if max(P0[0],P1[0])<xstep-1: continue+ if P0[1]<-13.5 and P1[1]<-13.5 and max(P0[0],P1[0])<xR-29: continue # skip V-notch edges (below pocket floor)+ out=clip_halfplane(out,nx,ny,c)+ if not out: break+ return out+Ppk=offset_inward(P,1.0)+Ppk=clip_halfplane(Ppk,-1,0,-(xstep+1.0)) # x >= xstep+1+Ppk=clip_halfplane(Ppk,0,-1,13.0) # y >= -13+Apk=area(Ppk); Apk_in=area(clip_disc(Ppk,cx,cy,41.0)); Apk_out=Apk-Apk_in+print("pocket area total %.2f (inside slot disc %.2f, outside %.2f); bbox x %.2f..%.2f y %.2f..%.2f"%(Apk,Apk_in,Apk_out,min(p[0] for p in Ppk),max(p[0] for p in Ppk),min(p[1] for p in Ppk),max(p[1] for p in Ppk)))+V3,_=vol3(cx,cy)+for name,pv in [("pocket depth 32 (floor 12 at back)",Apk_out*32+(Apk_in-hole11)*8),+ ("pocket depth 32, hole not excluded",Apk_out*32+Apk_in*8),+ ("pocket depth 12 only (front ear 8 + 4 into slot)",Apk_out*12+(Apk_in-hole11)*8)]:+ V4=V3-pv; print("STEP4 %-45s V=%.1f mass=%.2f (key 432.58, diff %+.2f%%)"%(name,V4,V4*0.0079,(V4/target4-1)*100))
uninstall.sh