app
SOLIDWORKS Bridge
Public Made by Adomby adom
Launch, model and quit SOLIDWORKS from any Adom container. Nothing is ever lost.
main
Drew Owens
0.9.9 source: user-presence guard; adversary pass 45 (unreadable log unverifiable, latch keyed by pid+creation); manife…
e772fef
19d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
//! HAS THIS SOLIDWORKS SESSION EVER HELD A DOCUMENT?
//!
//! MEASURED 2026-10-01 on Drew's machine (pid 20144, bridge-launched, attributed,
//! hosted 0.9.2): `swx_stop` rung (a) — UserControl=false, ExitApp, every COM
//! reference released — was DECLINED three times, at ~50 s, ~2.5 min and ~8 min
//! old: 0 documents, no dialog, census readable, only the main frame visible, an
//! empty auto-recover folder. The session had NEVER had a document open. Then, on
//! the SAME session: one scratch part created (`swx_new_document`), closed
//! (`swx_reset_workspace`), and rung (a) quit in 3.4 s. That reconciles the two
//! September observations — 09-08's "ExitApp declined at zero documents" was a
//! never-had-a-document session, 09-17's "not declined at zero documents" were
//! sessions that had held documents. So the rule is about session HISTORY, not
//! the current document count, and the quit ladder needs to know it.
//!
//! Recorded per session — (pid, creation time) — in `session-history.json` in the
//! data root: TRUE when the bridge itself created or opened a document in it, or
//! when a document count > 0 persists across two polls of the STARTED session
//! (never from a count read while starting — live 2026-10-01, pid 29108, such a
//! read recorded a session no one had opened a document in). ADVISORY since
//! 0.9.6: the quit ladder's priming no longer reads it. `None` (UNKNOWN) when
//! the bridge did not watch the session from its start: it attached to one it
//! did not launch, so a document may have come and gone unseen.
use serde_json::{json, Value};
fn path() -> std::path::PathBuf {
crate::scratch::root().join("session-history.json")
}
fn key(pid: u32, created: Option<u64>) -> String {
format!("{pid}:{}", created.map(|c| c.to_string()).unwrap_or_else(|| "?".into()))
}
fn load() -> serde_json::Map<String, Value> {
std::fs::read_to_string(path())
.ok()
.and_then(|t| serde_json::from_str::<Value>(&t).ok())
.and_then(|v| v.as_object().cloned())
.unwrap_or_default()
}
fn save(m: serde_json::Map<String, Value>) {
let mut m = m;
while m.len() > 20 {
let oldest = m
.iter()
.min_by_key(|(_, v)| v.get("atMs").and_then(|a| a.as_u64()).unwrap_or(0))
.map(|(k, _)| k.clone());
match oldest {
Some(o) => {
m.remove(&o);
}
None => break,
}
}
let _ = crate::launch::write_atomic(&path(), &Value::Object(m).to_string());
}
/// Record that this session has held a document BECAUSE THE BRIDGE ITSELF
/// created or opened one in it — the only single event that is proof.
pub fn mark(pid: u32, created: Option<u64>) {
set_true(pid, created, "the bridge itself created or opened a document in this session");
}
fn set_true(pid: u32, created: Option<u64>, basis: &str) {
let mut m = load();
let k = key(pid, created);
let mut entry = m.get(&k).cloned().unwrap_or_else(|| json!({}));
if entry.get("everHadDocument").and_then(|v| v.as_bool()) == Some(true) {
return;
}
if let Value::Object(e) = &mut entry {
e.insert("everHadDocument".into(), json!(true));
e.insert("basis".into(), json!(basis));
e.insert("atMs".into(), json!(crate::launchos::epoch_ms() as u64));
}
m.insert(k, entry);
save(m);
}
/// Two observations count as two polls only if they are this far apart.
const DISTINCT_POLL_MS: u64 = 1000;
/// WHAT A POLL SAW: a document count read on a session the bridge has VERIFIED
/// ready (callers never pass a count read while starting). Recorded with its
/// time and source (the last eight are kept). It sets `everHadDocument` only
/// when a count > 0 PERSISTS across two distinct polls with no zero between them
/// — live 2026-10-01 (pid 29108), a single count read near startup recorded a
/// session nobody had opened a document in.
pub fn observe(pid: u32, created: Option<u64>, count: u64, source: &str) {
let mut m = load();
let k = key(pid, created);
let now = crate::launchos::epoch_ms() as u64;
let mut entry = m.get(&k).cloned().unwrap_or_else(|| json!({}));
let mut obs: Vec<Value> =
entry.get("observations").and_then(|v| v.as_array()).cloned().unwrap_or_default();
obs.push(json!({"count": count, "atMs": now, "source": source}));
while obs.len() > 8 {
obs.remove(0);
}
// PERSISTED: an earlier observation with a count > 0, at least
// DISTINCT_POLL_MS older than this one, and no zero-count observation since.
let mut persisted = false;
if count > 0 {
for o in obs.iter().rev().skip(1) {
if o.get("count").and_then(|c| c.as_u64()).unwrap_or(0) == 0 {
break;
}
let at = o.get("atMs").and_then(|a| a.as_u64()).unwrap_or(now);
if now.saturating_sub(at) >= DISTINCT_POLL_MS {
persisted = true;
break;
}
}
}
if let Value::Object(e) = &mut entry {
e.insert("observations".into(), json!(obs));
if !e.contains_key("atMs") {
e.insert("atMs".into(), json!(now));
}
}
m.insert(k, entry);
save(m);
if persisted {
set_true(pid, created, "a document count > 0 on two distinct polls of the started session");
}
}
/// `Some(true)`: this session has held a document. `Some(false)`: NONE SEEN BY
/// THIS BRIDGE — it launched the session and no poll since has seen a document
/// (a non-zero `GetDocumentCount` at any readiness poll, or a verb reply showing
/// one, sets it true). `None`: unknown.
pub fn ever_had_document(pid: u32, created: Option<u64>) -> Option<bool> {
if load().get(&key(pid, created)).and_then(|v| v.get("everHadDocument")).and_then(|v| v.as_bool())
== Some(true)
{
return Some(true);
}
match crate::launch::attributed_solidworks() {
Some((p, c)) if p == pid && Some(c) == created => Some(false),
_ => None,
}
}
/// The verbs that bring a document into a session.
pub const ADDS_DOCUMENTS: &[&str] = &[
"swx_new_document",
"swx_open",
"swx_import",
"swx_add_component",
"swx_show_part",
"swx_show_assembly",
"swx_show_drawing",
];
/// After a verb: if its reply shows a document open in the running session,
/// record it. Asks the host which session that is only when there is something
/// to record.
pub fn note_reply(ctx: &crate::verbs::Ctx, command: &str, reply: &Value) {
if reply.get("success").and_then(|v| v.as_bool()) == Some(false) {
return;
}
let made_one = ADDS_DOCUMENTS.contains(&command);
let saw_one = ["documentCount", "count", "openDocuments"]
.iter()
.any(|k| reply.get(*k).and_then(|v| v.as_u64()).unwrap_or(0) > 0);
if !(made_one || saw_one) {
return;
}
let Ok(state) = ctx.call("startup_state", json!({}), 20) else { return };
let Some(pid) = state.get("processId").and_then(|v| v.as_u64()).map(|p| p as u32) else { return };
let created = crate::launchos::os()
.processes()
.ok()
.and_then(|ps| ps.iter().find(|p| p.pid == pid).and_then(|p| p.created_at))
.or_else(|| state.get("processCreatedAt").and_then(|v| v.as_u64()));
if made_one {
mark(pid, created);
} else if crate::readiness::known_ready(pid, created) {
// A COUNT IN A REPLY is a poll like any other: evidence only on a started
// session, and only once it persists.
let n = ["documentCount", "count", "openDocuments"]
.iter()
.filter_map(|k| reply.get(*k).and_then(|v| v.as_u64()))
.max()
.unwrap_or(0);
observe(pid, created, n, command);
}
}
/// THE SESSION'S HISTORY, for `swx_status` — so a caller can predict whether a
/// quit will need priming. `everHadDocument` is true, false or null, and `basis`
/// says which evidence decided it.
pub fn describe(pid: u32, created: Option<u64>) -> Value {
let ever = ever_had_document(pid, created);
let rec = load().get(&key(pid, created)).cloned().unwrap_or(Value::Null);
let recorded_basis = rec.get("basis").and_then(|v| v.as_str()).map(String::from);
let basis = match ever {
Some(true) => recorded_basis.as_deref().unwrap_or("a document was seen open in this session"),
Some(false) => "none seen by this bridge: it launched this session, it has not created or opened a \
document in it, and no document count > 0 has persisted across two polls of the \
started session — a document opened and closed between two polls would not be seen",
None => "the bridge did not watch this session from its start, so a document may have come and gone unseen",
};
json!({
"everHadDocument": ever,
"basis": basis,
"processId": pid,
"processCreatedAt": created,
// ADVISORY ONLY (0.9.6): no decision reads this — priming triggers on the
// measured decline itself.
"advisory": true,
"observations": rec.get("observations").cloned().unwrap_or_else(|| json!([])),
"note": "MEASURED 2026-10-01: a session that has never held a document quit without help at \
~25 s old but DECLINED ExitApp at 50 s, 130 s, 150 s and 8 min old; swx_stop primes \
an EMPTY session whose ExitApp was declined (userAuthorized, no blocking dialog) and \
asks once more — whatever this history says, which is advisory.",
})
}