main
Drew Owens 0.11.2 source 784acbf 5d ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898
//! LAUNCH RESILIENCE, end to end against the real compiled binary.
//!
//! Every test here drives a SIMULATED MACHINE (`SWX_LAUNCH_FAKE_DIR`) whose
//! behaviour is written down as a scenario — "route A starts a chain and stalls
//! at SecurityContext; route B reaches Run Begin and attaches" — and then
//! measures WHAT THE BRIDGE DID ABOUT IT on that machine: which processes it
//! ended, how many launcher invocations it made, what it left running. Not what
//! it returned.
//!
//! That distinction is the whole point. The pre-0.4 bridge returned
//! `stillLaunching:true` with a hint promising "call swx_start again, which
//! ATTACHES rather than launching a second copy" — and every one of those calls
//! fired the launcher again. The return value was right and the effect was
//! wrong, four times over, on somebody's real desktop.

mod common;

use common::{AbStub, Bridge, TempDir};
use serde_json::{json, Value};
use std::time::{Duration, Instant};

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

/// The pids `FakeOs` gives the Nth simulated launcher invocation.
fn chain_pids(n: u64) -> (u64, u64) {
    let base = 900_000 + n * 10;
    (base, base + 1)
}

/// A simulated machine. `routes` says what each launch route does; the
/// pre-existing processes are the ones that MUST still be there afterwards.
struct Machine {
    dir: TempDir,
}

impl Machine {
    fn new(tag: &str, routes: Value) -> Machine {
        let dir = TempDir::new(tag);
        std::fs::write(dir.join("routes.json"), routes.to_string()).unwrap();
        // The Platform's daemons and a chain the USER started a minute ago.
        // Nothing this bridge does may touch any of them, ever.
        std::fs::write(
            dir.join("preexisting.json"),
            json!([
                {"pid": 6076, "image": "3DEXPERIENCELauncher.exe", "ageSeconds": 30000},
                {"pid": 90552, "image": "3DEXPERIENCELauncherSysTray.exe", "ageSeconds": 30000},
                {"pid": 90553, "image": "3DEXPERIENCELauncherService.exe", "ageSeconds": 30000},
                {"pid": 70001, "image": "CATSTART.exe", "ageSeconds": 60},
                {"pid": 70002, "image": "SWXDesktopLauncher.exe", "ageSeconds": 60}
            ])
            .to_string(),
        )
        .unwrap();
        Machine { dir }
    }

    fn sldworks(self, state: Value) -> Machine {
        std::fs::write(self.dir.join("sldworks.json"), state.to_string()).unwrap();
        self
    }

    /// Also list SOLIDWORKS itself as already running.
    fn with_running_solidworks(self) -> Machine {
        let mut rows: Vec<Value> =
            serde_json::from_str(&std::fs::read_to_string(self.dir.join("preexisting.json")).unwrap())
                .unwrap();
        rows.push(json!({"pid": 88556, "image": "SLDWORKS.exe", "ageSeconds": 7200}));
        std::fs::write(self.dir.join("preexisting.json"), Value::Array(rows).to_string()).unwrap();
        self
    }

    fn lines(&self, file: &str) -> Vec<Value> {
        std::fs::read_to_string(self.dir.join(file))
            .unwrap_or_default()
            .lines()
            .filter_map(|l| serde_json::from_str(l).ok())
            .collect()
    }

    /// Every launcher invocation the bridge made, in order.
    fn invocations(&self) -> Vec<String> {
        self.lines("invocations.jsonl")
            .iter()
            .filter_map(|v| v.get("route").and_then(|r| r.as_str()).map(String::from))
            .collect()
    }

    /// Every process the bridge terminated, in order.
    fn terminated(&self) -> Vec<(u64, String)> {
        self.lines("terminated.jsonl")
            .iter()
            .filter_map(|v| {
                Some((
                    v.get("pid")?.as_u64()?,
                    v.get("image")?.as_str()?.to_string(),
                ))
            })
            .collect()
    }

    fn boot(&self, scratch: TempDir, extra: &[(&str, &str)]) -> Bridge {
        let lnk = format!("{}/SOLIDWORKS Design.lnk", self.dir.path());
        std::fs::write(&lnk, "not really a shortcut").unwrap();
        let mut env: Vec<(&str, &str)> = vec![
            ("SWX_SOLIDWORKS_SHORTCUT", Box::leak(lnk.into_boxed_str())),
            ("SWX_LAUNCH_FAKE_DIR", Box::leak(self.dir.path().into_boxed_str())),
            // Compressed budgets: the real ones are 20s / 120s / 240s, and a
            // suite that waited them out would never be run.
            ("SWX_LAUNCH_RUN_BEGIN_SECS", "2"),
            ("SWX_LAUNCH_SLDWORKS_SECS", "4"),
            ("SWX_LAUNCH_ATTACH_SECS", "8"),
            ("SWX_LAUNCH_POLL_MS", "100"),
            ("SWX_LAUNCH_ATTACH_POLL_MS", "150"),
            ("SWX_LAUNCH_INFLIGHT_SECS", "120"),
            ("SWX_LAUNCH_HELPER_SECS", "30"),
            ("SWX_LAUNCH_RETRY_SETTLE_MS", "400"),
            ("SWX_LAUNCH_DIALOG_GRACE_MS", "3000"),
        ];
        env.extend_from_slice(extra);
        Bridge::start_in(scratch, &env)
    }
}

/// Poll `swx_status` until the launch attempt finishes, or give up. Returns the
/// last status seen — a test asserts on the MACHINE, this only paces it.
fn wait_for_launch(b: &Bridge, secs: u64) -> Value {
    let deadline = Instant::now() + Duration::from_secs(secs);
    let mut last = json!({});
    loop {
        last = b.call("swx_status", json!({}));
        if last["launch"]["finished"] == true {
            return last;
        }
        if Instant::now() > deadline {
            return last;
        }
        std::thread::sleep(Duration::from_millis(150));
    }
}

#[test]
fn a_stalled_route_is_cleaned_up_and_the_next_route_takes_over() {
    // FAILURE MODE A, exactly as measured on 2026-09-04: the chain starts, the
    // launcher log stops at `SecurityContext:`, `Run Begin` never comes.
    let m = Machine::new(
        "fallback",
        // Both ATTRIBUTABLE routes: only a route that can say what it started
        // may have its chain cleaned up, so the fallback story is told with the
        // two that can. See `launch::AttributionRule`.
        json!({
            "shellExecute": {"chain": true},
            "powershell": {"chain": true, "runBeginAfterMs": 0, "helperAfterMs": 100,
                           "sldworksAfterMs": 200, "attachAfterMs": 400}
        }),
    );
    let b = m.boot(TempDir::new("scratch"), &[]);

    let r = b.call("swx_start", json!({"reason": "modelling a bracket for Drew", "waitSeconds": 0}));
    check!(b, "swx_start reports a launch in flight, not a failure", r["success"] == true && r["stillLaunching"] == true, s(&r));

    let st = wait_for_launch(&b, 25);
    check!(b, "swx_start reaches an attached SOLIDWORKS by falling back", st["launch"]["outcome"] == "attached", s(&st));

    // THE EFFECT, on the machine.
    check!(
        b,
        "exactly two launcher invocations: the stalled route, then the next one",
        m.invocations() == vec!["shellExecute".to_string(), "powershell".to_string()],
        format!("{:?}", m.invocations())
    );
    let (cat1, lnk1) = chain_pids(1);
    let killed = m.terminated();
    check!(
        b,
        "ONLY the stalled chain we started was ended — by pid, both of it, nothing else",
        killed.iter().map(|(p, _)| *p).collect::<Vec<_>>() == vec![cat1, lnk1],
        format!("terminated: {killed:?}")
    );
    check!(
        b,
        "...and it was ended as the images it really was",
        killed.iter().all(|(_, i)| i == "CATSTART.exe" || i == "SWXDesktopLauncher.exe"),
        format!("{killed:?}")
    );
    for guarded in [6076u64, 90552, 90553, 70001, 70002, 88556] {
        check!(
            b,
            "no daemon, no pre-existing chain and no SOLIDWORKS was ever terminated",
            !killed.iter().any(|(p, _)| *p == guarded),
            format!("pid {guarded} was terminated: {killed:?}")
        );
    }
    let (cat2, lnk2) = chain_pids(2);
    check!(
        b,
        "the WORKING route's chain was left alone",
        !killed.iter().any(|(p, _)| *p == cat2 || *p == lnk2),
        format!("{killed:?}")
    );

    // The stall is on the record, with what it cost.
    let tried = &st["launch"]["routesTried"];
    check!(b, "the stalled route is recorded", tried[0]["route"] == "shellExecute" && tried[0]["stalled"] == true, s(&st["launch"]));
    check!(
        b,
        "...and that the chain it ended was one the INVOKE identified, not one it recognised",
        tried[0]["attributed"] == true && tried[0]["cleanup"] == "cleaned",
        s(&st["launch"])
    );
    check!(
        b,
        "...naming the exact processes it ended",
        tried[0]["killed"][0]["pid"] == cat1 && tried[0]["killed"][1]["pid"] == lnk1,
        s(&st["launch"])
    );
    let ledger = b.call("swx_action_ledger", json!({"limit": 200}));
    check!(b, "the stall and the cleanup are in the human's ledger", s(&ledger).contains("solidworks_launch_stalled"), s(&ledger));
    check!(b, "...and so is Run Begin never arriving", s(&ledger).contains("never logged 'Run Begin'"), s(&ledger));
}

#[test]
fn the_route_that_worked_is_remembered_and_tried_first_next_time() {
    let scratch = TempDir::new("scratch");
    let m = Machine::new(
        "preferred",
        json!({
            "shellExecute": {"chain": true},
            "powershell": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 300}
        }),
    );
    {
        let b = m.boot(TempDir::borrowed(&scratch.0), &[]);
        b.call("swx_start", json!({"reason": "first launch of the day", "waitSeconds": 0}));
        let st = wait_for_launch(&b, 25);
        check!(b, "the working route is remembered on disk", st["launch"]["preferredRoute"] == "powershell", s(&st["launch"]));
    }
    // A DIFFERENT SERVER PROCESS, same scratch dir. The memory has to be the
    // FILE, not the process — a bridge is restarted far more often than a
    // desktop is.
    let state: Value = serde_json::from_str(
        &std::fs::read_to_string(scratch.join("launch-state.json")).unwrap(),
    )
    .unwrap();
    assert_eq!(state["preferredRoute"], "powershell", "{}", s(&state));

    // Every route still stalls except the remembered one, and the remembered
    // one is tried FIRST — so a second cold start costs one invocation, not two.
    let m2 = Machine::new(
        "preferred2",
        json!({"powershell": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 300}}),
    );
    std::fs::copy(scratch.join("launch-state.json"), m2.dir.join("seed.json")).unwrap();
    let scratch2 = TempDir::new("scratch2");
    std::fs::copy(scratch.join("launch-state.json"), scratch2.join("launch-state.json")).unwrap();
    let b2 = m2.boot(scratch2, &[]);
    b2.call("swx_start", json!({"reason": "second launch", "waitSeconds": 0}));
    let st2 = wait_for_launch(&b2, 25);
    check!(b2, "the second cold start attaches", st2["launch"]["outcome"] == "attached", s(&st2["launch"]));
    check!(
        b2,
        "...on the FIRST invocation, because the remembered route led the plan",
        m2.invocations() == vec!["powershell".to_string()],
        format!("{:?}", m2.invocations())
    );
    check!(b2, "...and nothing had to be cleaned up", m2.terminated().is_empty(), format!("{:?}", m2.terminated()));
}

#[test]
fn three_calls_during_a_launch_start_exactly_zero_extra_launchers() {
    // FAILURE MODE B. The old hint said calling again ATTACHES rather than
    // launching a second copy. It did not. Four launcher chains accumulated.
    let m = Machine::new(
        "inflight",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "helperAfterMs": 50,
                                "sldworksAfterMs": 150, "attachAfterMs": 600000}}),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_ATTACH_SECS", "120")]);

    let first = b.call("swx_start", json!({"reason": "starting SOLIDWORKS for Drew", "waitSeconds": 0}));
    check!(b, "the first call starts the launch", first["stillLaunching"] == true, s(&first));

    // Let the machine get past Run Begin so the calls land mid-flight.
    std::thread::sleep(Duration::from_millis(700));
    for n in 1..=3 {
        let again = b.call("swx_start", json!({"reason": "checking on it", "waitSeconds": 0}));
        check!(b, "a call during flight never fails", again["success"] == true, s(&again));
        check!(
            b,
            "...it reports the SAME attempt as still launching",
            again["stillLaunching"] == true && again["launchedNow"] == false,
            format!("call {n}: {}", s(&again))
        );
        check!(
            b,
            "...and it says, in words, that it launched nothing",
            again["_hint"].as_str().unwrap_or("").contains("NOTHING WAS LAUNCHED BY THIS CALL"),
            s(&again)
        );
        check!(
            b,
            "...carrying the live stage so the caller knows what it is waiting for",
            ["invoked", "launcherStarted", "runBegin", "helperSignIn", "sldworksUp", "attaching"]
                .contains(&again["stage"].as_str().unwrap_or("")),
            s(&again)
        );
    }
    // A call with NO reason must not be refused either — polling with swx_start
    // is what this bridge's own hint tells a caller to do.
    let bare = b.call("swx_start", json!({}));
    check!(b, "polling with swx_start needs no reason while a launch is in flight", bare["success"] == true && bare["stillLaunching"] == true, s(&bare));

    check!(
        b,
        "ONE launcher invocation, after five swx_start calls",
        m.invocations() == vec!["shellExecute".to_string()],
        format!("{:?}", m.invocations())
    );
    check!(b, "and nothing was terminated on the way", m.terminated().is_empty(), format!("{:?}", m.terminated()));
    // swx_status tells the same story, which is where a caller should be looking.
    let st = b.call("swx_status", json!({}));
    check!(b, "swx_status carries the live launch block", st["launch"]["inFlight"] == true && st["launch"]["route"] == "shellExecute", s(&st["launch"]));
}

#[test]
fn the_machine_stops_at_the_first_chain_it_cannot_prove_is_its_own() {
    // All four routes behave the way cmd/start did on 2026-09-04: they start a
    // launcher chain that never reaches Run Begin.
    //
    // The two ATTRIBUTABLE routes hand back the root they started, so their
    // chains are ended. `explorer` cannot say what it started — and it started
    // SOMETHING (a launcher log appeared) — so the machine stops there rather
    // than putting a fourth chain on the desktop beside one nobody can find.
    let m = Machine::new("exhaust", json!({}));
    let b = m.boot(
        TempDir::new("scratch"),
        &[("SWX_LAUNCH_RUN_BEGIN_SECS", "1"), ("SWX_LAUNCH_BACKOFF_SECS", "0")],
    );
    b.call("swx_start", json!({"reason": "trying to start SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 40);

    check!(b, "the attempt ends", st["launch"]["outcome"] == "exhausted", s(&st["launch"]));
    check!(
        b,
        "it stopped at the first route whose chain it could not prove was its own",
        m.invocations() == vec!["shellExecute", "powershell", "explorer"],
        format!("{:?}", m.invocations())
    );
    let tried = st["launch"]["routesTried"].as_array().cloned().unwrap_or_default();
    check!(
        b,
        "the two attributable routes ended the chains they started",
        tried[0]["attributed"] == true
            && tried[0]["cleanup"] == "cleaned"
            && tried[1]["attributed"] == true
            && tried[1]["cleanup"] == "cleaned",
        s(&st["launch"])
    );
    check!(
        b,
        "...and the unattributable one is recorded as exactly that, not as a clean recovery",
        tried[2]["attributed"] == false && tried[2]["cleanup"] == "notAttributable",
        s(&st["launch"])
    );
    check!(
        b,
        "...saying, in words, that a chain may remain which the bridge cannot identify",
        tried[2]["cleanupError"].as_str().unwrap_or("").contains("MAY still be running"),
        s(&st["launch"])
    );

    // THE EFFECT. Four processes ended — both attributable chains — and the
    // chain the bridge could not prove was its own was LEFT ALONE.
    let killed = m.terminated();
    check!(b, "two attributable chains, four processes", killed.len() == 4, format!("{killed:?}"));
    for ours in [900010u64, 900011, 900020, 900021] {
        check!(b, "each attributed chain was ended", killed.iter().any(|(p, _)| *p == ours), format!("{killed:?}"));
    }
    for unproven in [900030u64, 900031] {
        check!(
            b,
            "a chain the bridge could not prove was its own is NEVER terminated",
            !killed.iter().any(|(p, _)| *p == unproven),
            format!("{killed:?}")
        );
    }
    for guarded in [6076u64, 90552, 90553, 70001, 70002] {
        check!(b, "no daemon and no pre-existing chain was touched", !killed.iter().any(|(p, _)| *p == guarded), format!("{killed:?}"));
    }
    check!(
        b,
        "the advice is to ask the USER, which is the honest remaining move",
        st["launch"]["advice"].as_str().unwrap_or("").contains("ASK THE USER"),
        s(&st["launch"])
    );

    // And a fresh swx_start afterwards is allowed to try again — a finished
    // attempt is not a permanent lock.
    let again = b.call("swx_start", json!({"reason": "trying once more", "waitSeconds": 0}));
    check!(b, "a finished attempt does not block the next one", again["success"] == true, s(&again));
    let deadline = Instant::now() + Duration::from_secs(10);
    while m.invocations().len() <= 3 && Instant::now() < deadline {
        std::thread::sleep(Duration::from_millis(100));
    }
    check!(b, "...and it really did invoke again", m.invocations().len() > 3, format!("{:?}", m.invocations()));
    std::thread::sleep(Duration::from_millis(1500));
    check!(
        b,
        "a retry after a failure tries ONE route, not the whole plan again",
        m.invocations().len() == 4,
        format!("{:?}", m.invocations())
    );
}

#[test]
fn a_route_that_cannot_say_what_it_started_is_still_tried_when_it_started_nothing() {
    // The stop rule is about what a route LEFT BEHIND, not about whether it was
    // attributable. A route that started nothing at all leaves nothing behind,
    // so the machine may go on and try the ones that might actually work — the
    // two unattributable routes are kept precisely because they may be the ones
    // that launch SOLIDWORKS on this machine.
    let m = Machine::new(
        "nochain-continue",
        json!({"shellExecute": {"chain": false}, "powershell": {"chain": false},
               "explorer": {"chain": false},
               "cmdStart": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 300}}),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_RUN_BEGIN_SECS", "1")]);
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 40);

    check!(b, "the last route works and the launch attaches", st["launch"]["outcome"] == "attached", s(&st["launch"]));
    check!(
        b,
        "every route was tried, because none of the earlier ones left anything behind",
        m.invocations() == vec!["shellExecute", "powershell", "explorer", "cmdStart"],
        format!("{:?}", m.invocations())
    );
    check!(b, "and nothing was terminated anywhere", m.terminated().is_empty(), format!("{:?}", m.terminated()));
    check!(
        b,
        "a route that started nothing says so, rather than inventing a stall at SecurityContext",
        st["launch"]["routesTried"][0]["note"]
            .as_str()
            .unwrap_or("")
            .contains("NO launcher log at all"),
        s(&st["launch"])
    );
    // AND IT IS NOT MEMORISED. `cmdStart` cannot say what it started, so no
    // launcher log can be attributed to it — the `Run Begin` in the log that
    // appeared might have been written by a launch the USER started while we
    // watched. SOLIDWORKS is up and usable (that is what `attached` means and
    // it is proven by COM), but nothing proves THIS ROUTE did it, so the route
    // memory is left alone rather than taught something that may be false.
    check!(
        b,
        "an unattributable route is never learned as 'the one that works'",
        st["launch"]["preferredRoute"].is_null() && st["launch"]["runBeginSeen"] == false,
        s(&st["launch"])
    );
    check!(
        b,
        "...and the log it could not attribute is reported as exactly that",
        st["launch"]["unattributedLog"] == true,
        s(&st["launch"])
    );
}

#[test]
fn a_root_the_census_cannot_see_is_still_confirmed_by_its_children() {
    // `rootVisible:false` — the invoke hands back a root whose image this
    // bridge does not watch (a shim, a wrapper), so the census never shows it.
    // Its CHILDREN are there, and their ppid points at the handle-proven pid,
    // so the lineage is confirmed and the chain is cleaned up. Getting this
    // wrong reported a "clean recovery" with a real chain still running.
    let m = Machine::new(
        "rootinvisible",
        json!({"shellExecute": {"chain": true, "rootVisible": false}}),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_RUN_BEGIN_SECS", "1")]);
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 30);

    let tried = &st["launch"]["routesTried"][0];
    check!(b, "the lineage was confirmed through the invisible root", tried["rootConfirmed"] == true, s(&st["launch"]));
    check!(b, "...so the chain was cleaned, not reported clean", tried["cleanup"] == "cleaned", s(&st["launch"]));
    let killed = m.terminated();
    check!(
        b,
        "the child the root started WAS ended",
        killed.iter().any(|(p, _)| *p == 900011),
        format!("{killed:?}")
    );
    check!(
        b,
        "...and the root itself was not, because the census never showed it",
        !killed.iter().any(|(p, _)| *p == 900010),
        format!("{killed:?}")
    );
}

#[test]
fn each_route_carries_the_log_evidence_that_belongs_to_it() {
    // The gate's per-route table is its central measurement. Every field it
    // prints must come from the ROUTE, not from the attempt — the attempt's
    // copies are reset when the next route begins, so reading them per row
    // printed the last route's evidence against all of them.
    let m = Machine::new(
        "perroute",
        json!({
            "shellExecute": {"chain": false},
            "powershell": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 300}
        }),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_RUN_BEGIN_SECS", "1")]);
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 30);
    let tried = st["launch"]["routesTried"].as_array().cloned().unwrap_or_default();

    check!(b, "both routes are in the table", tried.len() == 2, s(&st["launch"]));
    check!(
        b,
        "the route that started nothing has no log and no Run Begin OF ITS OWN",
        tried[0]["launcherLog"].is_null() && tried[0]["runBeginSeen"] == false,
        s(&tried[0])
    );
    check!(
        b,
        "the route that worked has both, and says which root it was given",
        tried[1]["runBeginSeen"] == true
            && tried[1]["launcherLog"].is_string()
            && tried[1]["rootPid"].is_u64()
            && tried[1]["rootConfirmed"] == true,
        s(&tried[1])
    );
    check!(
        b,
        "the attach is recorded as an ordering hint that is explicitly NOT proof",
        st["launch"]["lastRouteBeforeAttach"]["route"] == "powershell"
            && st["launch"]["lastRouteBeforeAttach"]["proof"] == false,
        s(&st["launch"])
    );
}

#[test]
fn an_attributable_route_that_never_sees_its_own_chain_stops_the_machine() {
    // The invoke handed back a root and the census never showed it, nor
    // anything descending from it. That is not "there was nothing to kill" —
    // it is "I never found what I started", and another route would put a
    // second chain beside one nobody can account for.
    let m = Machine::new(
        "notconfirmed",
        // `attributable:false` alone models "no handle"; here the route DOES
        // report a root, but the simulated chain never appears in the census.
        // Route 1 starts nothing (so the machine reaches route 2), and route 2
        // reports a root whose chain the census never shows. Before the
        // per-route reset, `root_confirmed` carried over and `notConfirmed`
        // was unreachable after route 1.
        json!({"shellExecute": {"chain": false},
               "powershell": {"chain": true, "invisibleChain": true}}),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_RUN_BEGIN_SECS", "1")]);
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 30);

    let tried = &st["launch"]["routesTried"][1];
    check!(b, "the route is recorded as never confirmed", tried["cleanup"] == "notConfirmed", s(&st["launch"]));
    check!(b, "...as a FAILURE to account, not a clean recovery", tried["cleanupFailed"] == true, s(&st["launch"]));
    check!(b, "...and it says a chain may remain", tried["chainMayRemain"] == true, s(&st["launch"]));
    check!(
        b,
        "the machine stopped rather than starting another chain",
        m.invocations().len() == 2,
        format!("{:?}", m.invocations())
    );
    check!(b, "and nothing was terminated", m.terminated().is_empty(), format!("{:?}", m.terminated()));
}

#[test]
fn an_attributable_route_that_gets_no_handle_cleans_up_nothing_and_stops() {
    // THE SHAPE ShellExecuteExW IS MOST LIKELY TO PRODUCE on a .lnk: the shell
    // hands the link to an already-running process (DDE) and returns no handle,
    // so a route that CAN normally attribute does not, on this launch. It must
    // behave exactly like `explorer`: adopt nothing, kill nothing, and stop
    // once a launcher log shows something started.
    let m = Machine::new(
        "nohandle",
        json!({"shellExecute": {"chain": true, "attributable": false}}),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_RUN_BEGIN_SECS", "1")]);
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 30);

    check!(b, "nothing was attributed", st["launch"]["attributed"] == false, s(&st["launch"]));
    let tried = &st["launch"]["routesTried"][0];
    check!(b, "the route is recorded as unattributable", tried["cleanup"] == "notAttributable", s(&st["launch"]));
    check!(b, "...and says a chain may remain", tried["chainMayRemain"] == true, s(&st["launch"]));
    check!(
        b,
        "the machine stopped after ONE route, because a log says something started",
        m.invocations() == vec!["shellExecute".to_string()],
        format!("{:?}", m.invocations())
    );
    check!(b, "NOTHING was terminated", m.terminated().is_empty(), format!("{:?}", m.terminated()));
    let chain = m.lines("invocations.jsonl").len();
    check!(b, "one invocation only", chain == 1, format!("{chain}"));
}

#[test]
fn a_retry_after_a_failure_waits_instead_of_starting_more_chains() {
    let m = Machine::new("backoff", json!({}));
    let b = m.boot(
        TempDir::new("scratch"),
        &[("SWX_LAUNCH_RUN_BEGIN_SECS", "1"), ("SWX_LAUNCH_BACKOFF_SECS", "300")],
    );
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 40);
    check!(b, "precondition: the attempt failed", st["launch"]["outcome"] == "exhausted", s(&st["launch"]));
    let after_first = m.invocations().len();

    let r = b.call("swx_start", json!({"reason": "and again", "waitSeconds": 0}));
    check!(b, "the retry is refused with a branchable code", r["errorCode"] == "host_app_launch_backoff", s(&r));
    check!(b, "...saying how long", r["backoffSeconds"].as_u64().unwrap_or(0) > 0, s(&r));
    check!(
        b,
        "...and pointing at the human, which is the honest remaining move",
        r["_hint"].as_str().unwrap_or("").contains("ASK THE USER"),
        s(&r)
    );
    std::thread::sleep(Duration::from_millis(800));
    check!(
        b,
        "NOT ONE new launcher chain was started by the refused retry",
        m.invocations().len() == after_first,
        format!("{:?}", m.invocations())
    );
}

#[test]
fn solidworks_up_but_not_attaching_stops_the_machine_instead_of_launching_another() {
    // sldworks.exe IS on the user's desktop — probably at a 3DEXPERIENCE
    // sign-in only they can answer. That is NOT a stalled launcher: the chain
    // must not be killed for it, no further route may be tried (a second route
    // would put a SECOND SOLIDWORKS on their screen), and it must not be
    // reported as attached.
    let m = Machine::new(
        "upnotattached",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100}}),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_ATTACH_SECS", "3")]);
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 25);

    check!(
        b,
        "the outcome names what is true: up, and not attached",
        st["launch"]["outcome"] == "sldworksUpNotAttached",
        s(&st["launch"])
    );
    check!(b, "...and it is NEVER reported as attached", st["launch"]["stage"] != "attached", s(&st["launch"]));
    check!(
        b,
        "...pointing at the sign-in only the user can answer",
        st["launch"]["error"].as_str().unwrap_or("").contains("sign-in"),
        s(&st["launch"])
    );
    check!(b, "no second route was tried", m.invocations() == vec!["shellExecute".to_string()], format!("{:?}", m.invocations()));
    check!(b, "and the chain was NOT killed — SOLIDWORKS is coming up on their screen", m.terminated().is_empty(), format!("{:?}", m.terminated()));
    check!(
        b,
        "the route is not remembered as one that worked",
        st["launch"]["preferredRoute"].is_null(),
        s(&st["launch"])
    );
}

#[test]
fn the_crash_reporters_restart_button_is_clicked_once_and_nothing_else_is() {
    // FAILURE MODE C, 2026-09-03: sldworks crashed on first spawn, the crash
    // reporter appeared, and clicking "Restart SOLIDWORKS Design" launched it.
    // pid 900012 is the sldworks.exe the simulator spawns for invocation 1 —
    // the crash reporter must be ATTRIBUTED to the process we are launching,
    // not merely titled like one.
    let ab = AbStub::start(json!([
        {"hwnd": 111, "title": "SOLIDWORKS Design has stopped working", "className": "#32770", "pid": 900012, "rect": {"left": 0}},
        {"hwnd": 222, "title": "Save changes to Part1?", "className": "#32770", "pid": 900012, "rect": {"left": 0}},
        {"hwnd": 333, "title": "gallia - Google Chrome", "className": "Chrome_WidgetWin_1", "pid": 4242, "rect": {"left": 0}}
    ]));
    ab.set_response(
        "desktop_find_control",
        json!({"success": true, "found": true, "name": "Restart SOLIDWORKS Design", "role": "button", "invokable": true}),
    );
    ab.set_response("desktop_ui_click", json!({"success": true, "invoked": true, "name": "Restart SOLIDWORKS Design"}));

    let m = Machine::new(
        "crash",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 1200}}),
    );
    let b = m.boot(
        TempDir::new("scratch"),
        &[
            ("ADOM_DIRECT_API_URL", &ab.url),
            ("ADOM_BRIDGE_TOKEN", "test-token"),
            // SHIPPED OFF. The click is decided from the shape of ab's
            // desktop_find_control reply, and that shape has never been seen on
            // a real desktop — so the feature is armed explicitly, here and by
            // the live gate, and nowhere else.
            ("SWX_CRASH_RECOVERY", "on"),
        ],
    );
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS to model a bracket", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 25);
    check!(b, "the launch still completes", st["launch"]["outcome"] == "attached", s(&st["launch"]));

    let clicks = ab.calls_to("desktop_ui_click");
    check!(b, "the Restart button was clicked EXACTLY once, however many polls ran", clicks.len() == 1, format!("{clicks:?}"));
    let args = &clicks[0]["args"];
    check!(b, "...on the crash reporter's window", args["hwnd"] == 111, s(&clicks[0]));
    check!(b, "...targeting the button BY NAME, never a coordinate", args["contains"] == "Restart SOLIDWORKS" && args["role"] == "button", s(&clicks[0]));
    check!(
        b,
        "...with a reason a human can read in their Activity Log",
        args["reason"].as_str().unwrap_or("").contains("crashed"),
        s(&clicks[0])
    );
    check!(
        b,
        "the button was CONFIRMED to exist before it was clicked",
        !ab.calls_to("desktop_find_control").is_empty(),
        format!("{:?}", ab.calls())
    );
    // NOTHING ELSE was touched. The Save-changes dialog is the one that must
    // never be answered by a bridge, and it was on screen the whole time.
    check!(b, "no window was closed", ab.calls_to("desktop_ui_window").is_empty(), format!("{:?}", ab.calls()));
    check!(b, "no shell command was run", ab.calls_to("shell_execute").is_empty(), format!("{:?}", ab.calls()));
    check!(
        b,
        "the user's Save-changes dialog was never touched",
        !ab.calls().iter().any(|c| c.to_string().contains("222")),
        format!("{:?}", ab.calls())
    );
    let ledger = b.call("swx_action_ledger", json!({"limit": 200}));
    check!(b, "the click is on the record", s(&ledger).contains("solidworks_crash_reporter_restarted"), s(&ledger));
}

#[test]
fn a_window_that_merely_looks_like_a_crash_reporter_is_never_clicked() {
    // The gate is the BUTTON, not the title. ab says the control is not there,
    // so nothing may be clicked — a title is a guess and a click is an act.
    let ab = AbStub::start(json!([
        {"hwnd": 111, "title": "SOLIDWORKS Error Report", "className": "#32770", "pid": 900012, "rect": {"left": 0}}
    ]));
    ab.set_response("desktop_find_control", json!({"success": true, "found": false}));
    let m = Machine::new(
        "nocrash",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 1000}}),
    );
    let b = m.boot(
        TempDir::new("scratch"),
        &[
            ("ADOM_DIRECT_API_URL", &ab.url),
            ("ADOM_BRIDGE_TOKEN", "test-token"),
            ("SWX_CRASH_RECOVERY", "on"),
        ],
    );
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    wait_for_launch(&b, 25);
    check!(b, "no click was dispatched at all", ab.calls_to("desktop_ui_click").is_empty(), format!("{:?}", ab.calls()));
    check!(b, "...though the window WAS looked at", !ab.calls_to("desktop_find_control").is_empty(), format!("{:?}", ab.calls()));
}

#[test]
fn crash_recovery_is_off_unless_it_is_explicitly_armed() {
    // It ships DISABLED. The decision to click rests entirely on the shape of
    // ab's desktop_find_control reply, and no reply from that verb has ever
    // been observed on a real desktop — so until the live gate captures one,
    // the bridge reports the crash reporter and does nothing about it.
    let ab = AbStub::start(json!([
        {"hwnd": 111, "title": "SOLIDWORKS Design has stopped working", "className": "#32770", "pid": 900012, "rect": {"left": 0}}
    ]));
    ab.set_response(
        "desktop_find_control",
        json!({"success": true, "found": true, "name": "Restart SOLIDWORKS Design", "invokable": true}),
    );
    let m = Machine::new(
        "crashoff",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 1000}}),
    );
    let b = m.boot(
        TempDir::new("scratch"),
        &[("ADOM_DIRECT_API_URL", &ab.url), ("ADOM_BRIDGE_TOKEN", "test-token")],
    );
    b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 25);
    check!(b, "the launch is unaffected", st["launch"]["outcome"] == "attached", s(&st["launch"]));
    check!(
        b,
        "ab was never even asked about the window, let alone told to click it",
        ab.calls_to("desktop_find_control").is_empty() && ab.calls_to("desktop_ui_click").is_empty(),
        format!("{:?}", ab.calls())
    );
    check!(
        b,
        "...and the report says so, so a reader knows the feature is not armed",
        st["launch"]["crashRecovery"] == "off",
        s(&st["launch"])
    );
}

#[test]
fn a_hung_solidworks_is_reported_as_hung_and_a_second_one_is_never_launched() {
    // FAILURE MODE D. SOLIDWORKS is alive, the window is not answering, COM
    // times out. The old bridge said "not running, and this edition cannot be
    // started programmatically" — and on a shortcut machine it would have
    // launched a SECOND SOLIDWORKS onto the user's desktop.
    let m = Machine::new("hung", json!({}))
        .with_running_solidworks()
        .sldworks(json!({"responding": false, "hwnd": 4242, "privateMB": 2400, "handles": 9000}));
    let scratch = TempDir::new("scratch");
    let scratch_path = scratch.0.clone();
    let b = m.boot(scratch, &[]);
    // BOTH signals, from two independent causes: Windows says the window is not
    // answering (above), and a COM call this bridge made overran its budget.
    // Neither alone is a hang, and the bridge must not manufacture the second
    // one out of its own busy com host — see the adversary test.
    std::fs::write(scratch_path.join("mock-com-timeout"), "").unwrap();

    let r = b.call("swx_start", json!({"reason": "trying to use SOLIDWORKS"}));
    check!(b, "the bridge says it is HUNG, with a branchable code", r["errorCode"] == "host_app_hung", s(&r));
    check!(
        b,
        "...and says only the user can end it, and why",
        r["_hint"].as_str().unwrap_or("").contains("ONLY THE USER CAN END IT"),
        s(&r)
    );
    check!(b, "NOTHING was launched", m.invocations().is_empty(), format!("{:?}", m.invocations()));
    check!(b, "and nothing was killed", m.terminated().is_empty(), format!("{:?}", m.terminated()));
    check!(
        b,
        "the evidence is reported, not just the verdict",
        r["solidworksProcess"]["responding"] == false && r["solidworksProcess"]["processId"] == 88556,
        s(&r)
    );

    // swx_status tells the same story WITHOUT COM — which is the point, because
    // COM is what has stopped answering.
    let st = b.call("swx_status", json!({}));
    check!(b, "swx_status reports responding:false read from the OS, not from COM", st["solidworks"]["responding"] == false, s(&st["solidworks"]));
    check!(b, "...with the memory and handle counts a human needs", st["solidworks"]["privateMemoryMB"] == 2400 && st["solidworks"]["handles"] == 9000, s(&st["solidworks"]));
    check!(
        b,
        "...and resident memory beside the commit charge, so neither is read as 'memory'",
        st["solidworks"]["workingSetMB"].is_u64(),
        s(&st["solidworks"])
    );

    // TAKE THE TIMEOUT AWAY and the verdict must go with it: a window that is
    // not pumping messages, on its own, is a rebuild — not a hang.
    std::fs::remove_file(scratch_path.join("mock-com-timeout")).unwrap();
    let st2 = b.call("swx_status", json!({}));
    check!(
        b,
        "one signal alone is never a hang",
        st2["solidworks"]["hung"] != json!(true),
        s(&st2["solidworks"])
    );
}

#[test]
fn a_very_large_session_is_an_observation_not_a_verdict() {
    // 2026-09-03: 17.4 GB private, 52 documents, and BOTH stock templates
    // returned no document. That measurement is worth REPORTING — and it is not
    // a verdict. The 0.4.0 threshold (12 GB / 40 docs) called the same
    // machine's HEALTHY 13.1 GB / 33-document session out of room and told the
    // user to restart it, so memory is now advisory and the only sufficient
    // signal is SOLIDWORKS handing back no document (below).
    let m = Machine::new("exhausted", json!({}))
        .with_running_solidworks()
        .sldworks(json!({"responding": true, "hwnd": 4242, "privateMB": 17900, "handles": 21770}));
    let b = m.boot(TempDir::new("scratch"), &[]);

    let r = b.call("swx_start", json!({"reason": "trying to model"}));
    check!(
        b,
        "swx_start refuses to launch a second copy, and names what is ACTUALLY known",
        r["errorCode"] == "host_app_com_unreachable",
        s(&r)
    );
    check!(b, "nothing was launched", m.invocations().is_empty(), format!("{:?}", m.invocations()));

    let st = b.call("swx_status", json!({}));
    check!(
        b,
        "the memory figure is reported as an OBSERVATION",
        st["solidworks"]["memoryAdvisory"].as_str().unwrap_or("").contains("17900"),
        s(&st["solidworks"])
    );
    check!(
        b,
        "...explicitly not a verdict",
        st["solidworks"]["memoryAdvisory"].as_str().unwrap_or("").contains("not a verdict"),
        s(&st["solidworks"])
    );
    check!(
        b,
        "...and `exhausted` stays null, because nothing has proved it",
        st["solidworks"]["exhausted"].is_null(),
        s(&st["solidworks"])
    );
}

#[test]
fn a_new_document_that_comes_back_empty_is_exhaustion_not_a_template_fault() {
    let m = Machine::new(
        "newdoc",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0, "attachAfterMs": 0}}),
    );
    let b = m.boot(TempDir::new("scratch"), &[]);
    b.call("swx_start", json!({"reason": "modelling", "waitSeconds": 10}));
    let ok = b.call("swx_new_document", json!({"type": "part"}));
    check!(b, "a healthy session creates documents normally", ok["success"] == true, s(&ok));

    // Now SOLIDWORKS accepts the call and hands back nothing — the signature.
    std::fs::write(b.scratch.join("mock-newdoc-empty"), "").unwrap();
    let r = b.call("swx_new_document", json!({"type": "assembly"}));
    check!(b, "an empty NewDocument is reported as exhaustion", r["errorCode"] == "host_app_exhausted", s(&r));
    check!(b, "...quoting what SOLIDWORKS actually said", r["hostAppError"].as_str().unwrap_or("").contains("created no document"), s(&r));
    check!(b, "...and telling the caller not to loop on it", r["_hint"].as_str().unwrap_or("").contains("Do NOT retry"), s(&r));
}

#[test]
fn ownership_survives_an_unanswerable_probe_and_a_com_host_respawn() {
    // BUG #5, in both the shapes that were observed. No simulator needed: this
    // is about the SERVER's registry, not about launching.
    let scratch = TempDir::new("scratch");
    let scratch_path = scratch.0.clone();
    let b = Bridge::start_in(TempDir::borrowed(&scratch_path), &[]);
    b.call("swx_start", json!({}));
    let made = b.call("swx_new_document", json!({"type": "part"}));
    let title = made["created"]["title"].as_str().unwrap_or("Part1").to_string();
    check!(b, "the bridge created a document", made["success"] == true, s(&made));

    let write = b.call("swx_props_set", json!({"targetDocument": title, "properties": {"Owner": "bridge"}}));
    check!(b, "it may write to its own document", write["success"] == true, s(&write));

    // ...and the claim is ON DISK, not only in this process's memory.
    let registry: Value =
        serde_json::from_str(&std::fs::read_to_string(scratch_path.join("owned-docs.json")).unwrap()).unwrap();
    check!(b, "the ownership registry is persisted", s(&registry).contains(&title), s(&registry));

    // THE OBSERVED FAILURE: one probe SOLIDWORKS could not answer. The old code
    // read that as "no session, nothing open" and pruned the registry empty —
    // permanently disowning documents the bridge had created seconds earlier.
    std::fs::write(scratch_path.join("mock-fail-app-state"), "").unwrap();
    let blind = b.call("swx_props_set", json!({"targetDocument": title, "properties": {"Owner": "bridge"}}));
    check!(b, "an unanswerable probe fails HONESTLY", blind["success"] == false, s(&blind));
    check!(
        b,
        "...and never claims the document was not ours",
        !s(&blind).contains("did not create"),
        s(&blind)
    );
    std::fs::remove_file(scratch_path.join("mock-fail-app-state")).unwrap();

    let after = b.call("swx_props_set", json!({"targetDocument": title, "properties": {"Owner": "bridge"}}));
    check!(b, "OWNERSHIP SURVIVED the blind window", after["success"] == true, s(&after));

    // THE SECOND SHAPE: the com host is killed mid-build and respawns.
    let host_pid = b.call("swx_status", json!({}))["com"]["hostPid"].as_u64().unwrap();
    assert!(
        std::process::Command::new("kill")
            .args(["-9", &host_pid.to_string()])
            .status()
            .expect("kill the com host")
            .success(),
        "could not kill com host {host_pid}"
    );
    std::thread::sleep(Duration::from_millis(300));
    let st = b.call("swx_status", json!({}));
    check!(b, "the com host really was replaced", st["com"]["hostPid"].as_u64().unwrap_or(host_pid) != host_pid, s(&st["com"]));
    let survived = b.call("swx_props_set", json!({"targetDocument": title, "properties": {"Owner": "bridge"}}));
    check!(b, "OWNERSHIP SURVIVED the respawn", survived["success"] == true, s(&survived));

    // ...and a whole new SERVER reads the registry back off disk.
    drop(b);
    let b2 = Bridge::start_in(TempDir::borrowed(&scratch_path), &[]);
    let st2 = b2.call("swx_status", json!({}));
    check!(b2, "a restarted bridge restores the registry", b2.log().contains("ownership registry restored"), b2.log());
    check!(b2, "...and is otherwise healthy", st2["success"] == true, s(&st2));
}

#[test]
fn a_bridge_that_cannot_see_the_machine_still_launches_rather_than_refusing() {
    // No simulator, not Windows: the process census cannot be taken. UNKNOWN
    // must not become "SOLIDWORKS is running" (which would refuse every launch)
    // NOR a silent claim that it is not. The launch proceeds, and the report
    // says the census failed rather than inventing a census.
    let lnk = TempDir::new("lnk");
    let path = format!("{}/SOLIDWORKS Design.lnk", lnk.path());
    std::fs::write(&path, "x").unwrap();
    let b = Bridge::start_with(&[
        ("SWX_SOLIDWORKS_SHORTCUT", &path),
        ("SWX_LAUNCH_RUN_BEGIN_SECS", "1"),
        ("SWX_LAUNCH_POLL_MS", "100"),
    ]);
    let r = b.call("swx_start", json!({"reason": "starting SOLIDWORKS", "waitSeconds": 0}));
    check!(b, "the launch is attempted", r["success"] == true && r["stillLaunching"] == true, s(&r));
    let st = b.call("swx_status", json!({}));
    check!(
        b,
        "an unavailable census is reported as unavailable, never as 'not running'",
        st["solidworks"]["running"].is_null() || st["solidworks"]["censusError"].is_string(),
        s(&st["solidworks"])
    );
    check!(
        b,
        "...and responsiveness is UNKNOWN rather than a comfortable 'yes'",
        st["solidworks"]["responding"].is_null(),
        s(&st["solidworks"])
    );
}


#[test]
fn a_corrupt_registry_falls_back_to_the_previous_generation() {
    // `write_atomic` keeps one generation as `.bak`, and it is a strictly
    // better answer than owning nothing: it is a registry this bridge itself
    // wrote one write ago, so at worst it is missing the newest claim — while
    // owning nothing refuses every document the bridge created before the
    // restart, which IS bug #5.
    let scratch = TempDir::new("scratch");
    let dir = scratch.0.clone();
    {
        let b = Bridge::start_in(TempDir::borrowed(&dir), &[]);
        b.call("swx_start", json!({}));
        let a = b.call("swx_new_document", json!({"type": "part"}));
        check!(b, "a document is created and owned", a["success"] == true, s(&a));
        // A second write, so a .bak generation exists containing the first.
        let c = b.call("swx_new_document", json!({"type": "part"}));
        check!(b, "...and a second", c["success"] == true, s(&c));
    }
    check!(
        Bridge::start_in(TempDir::borrowed(&dir), &[]),
        "precondition: a backup generation exists",
        dir.join("owned-docs.bak").exists(),
        format!("{:?}", std::fs::read_dir(&dir).unwrap().count())
    );

    // A rewrite interrupted half way through.
    std::fs::write(dir.join("owned-docs.json"), r#"{"documents":[{"title":"Part1","sess"#).unwrap();
    let b2 = Bridge::start_in(TempDir::borrowed(&dir), &[]);
    let log = b2.log();
    check!(b2, "the corruption is reported, loudly", log.contains("UNREADABLE") || log.contains("could not be read"), log.clone());
    check!(
        b2,
        "...and the previous generation is used instead of owning nothing",
        log.contains("recovered from owned-docs.bak"),
        log
    );
}

#[test]
fn an_unknown_interference_count_reaches_the_caller_as_null_with_guidance() {
    // The shape has to be TESTED, not just produced: `count: null` on a
    // clearance report is the one null in this bridge that can reach a physical
    // part, and every caller's truthiness check reads it as zero.
    let b = Bridge::start();
    b.call("swx_start", json!({"reason": "checking clearances"}));
    let made = b.call("swx_new_document", json!({"type": "assembly"}));
    let title = made["created"]["title"].as_str().unwrap_or("Assem1").to_string();

    let ok = b.call("swx_interference", json!({"targetDocument": title}));
    check!(b, "a normal check reports a count and says it is known", ok["count"] == 1 && ok["countKnown"] == true, s(&ok));

    std::fs::write(b.scratch.join("mock-interference-count-unknown"), "").unwrap();
    let r = b.call("swx_interference", json!({"targetDocument": title}));
    check!(b, "an uncountable check answers null, never 0", r["count"].is_null() && r["countKnown"] == false, s(&r));
    check!(
        b,
        "...and the hint tells the caller not to use a truthiness check on it",
        r["_hint"].as_str().unwrap_or("").contains("never with a truthiness check")
            && r["_hint"].as_str().unwrap_or("").contains("countKnown"),
        s(&r)
    );
    check!(
        b,
        "...saying plainly that null is not a clear result",
        r["_hint"].as_str().unwrap_or("").contains("NOT a clear result"),
        s(&r)
    );

    // The same shape on the other two newly-nullable counts.
    std::fs::write(b.scratch.join("mock-doccount-unknown"), "").unwrap();
    let rec = b.call("swx_check_recovery", json!({}));
    check!(b, "an unknown open-document count is null, not 0", rec["com"]["openDocuments"].is_null(), s(&rec));

    std::fs::write(b.scratch.join("mock-component-count-unknown"), "").unwrap();
    let add = b.call("swx_add_component", json!({
        "targetDocument": title,
        "components": [{"file": "C:\\mock\\bracket.sldprt", "xMm": 0, "yMm": 0, "zMm": 0}]
    }));
    check!(
        b,
        "an uncountable assembly refuses the insert rather than risking a DOUBLE insert",
        add["success"] == false && add["errorCode"] == "component_count_failed",
        s(&add)
    );
    check!(
        b,
        "...and says why, in terms of the harm",
        add["error"].as_str().unwrap_or("").contains("TWICE"),
        s(&add)
    );
}


#[test]
fn a_not_responding_solidworks_that_is_burning_cpu_is_reported_as_busy() {
    // LIVE, 2026-09-08: 17.9 GB with an unsaved assembly, not-responding and a
    // COM timeout for ~5 minutes, ~70% of a core, memory creeping, NO dialog —
    // and it RECOVERED once Drew saved. The bridge said "only the user can end
    // it". `verdict` exists so a caller can tell "wait" from "it is gone".
    let m = Machine::new("busy", json!({}))
        .with_running_solidworks()
        .sldworks(json!({
            "responding": false, "hwnd": 4242, "privateMB": 17900, "handles": 21000,
            // Every metrics read advances the simulated CPU clock: work IS
            // happening, which is the whole point.
            "cpuSeconds": 1000.0, "cpuSecondsPerRead": 12.0
        }));
    let scratch = TempDir::new("scratch");
    let dir = scratch.0.clone();
    let b = m.boot(scratch, &[]);
    std::fs::write(dir.join("mock-com-timeout"), "").unwrap();

    // Two reads far enough apart: the verdict needs a sample, and one reading is
    // never enough to call a session dead.
    b.call("swx_status", json!({}));
    let st = b.call("swx_status", json!({}));
    let sw = &st["solidworks"];
    check!(b, "the window is not responding and a COM call timed out", sw["hung"] == true, s(sw));
    check!(b, "...but the verdict is BUSY, not dead", sw["verdict"] == "busy", s(sw));
    check!(
        b,
        "...and the advice is to WAIT, not to end the task",
        sw["verdictAdvice"].as_str().unwrap_or("").contains("WAIT")
            && !sw["verdictAdvice"].as_str().unwrap_or("").contains("ONLY THE USER CAN END IT"),
        s(sw)
    );
    check!(b, "...with the CPU it burned across the sample", sw["cpuActiveSeconds"].as_f64().unwrap_or(0.0) > 0.0, s(sw));
    check!(b, "...and the memory delta beside it", sw["memoryDeltaMB"].is_i64(), s(sw));
}

#[test]
fn one_reading_never_calls_a_session_dead() {
    // The guard that would have stopped the wrong call: with no previous sample
    // there is no CPU delta, so the verdict is UNKNOWN however bad it looks.
    let m = Machine::new("onesample", json!({}))
        .with_running_solidworks()
        .sldworks(json!({"responding": false, "hwnd": 4242, "privateMB": 17900, "cpuSecondsPerRead": 0.0}));
    let scratch = TempDir::new("scratch");
    let dir = scratch.0.clone();
    let b = m.boot(scratch, &[]);
    std::fs::write(dir.join("mock-com-timeout"), "").unwrap();
    let st = b.call("swx_status", json!({}));
    let sw = &st["solidworks"];
    check!(b, "a single reading is UNKNOWN, never dead", sw["verdict"] == "unknown", s(sw));
    check!(
        b,
        "...and it says to poll again rather than concluding",
        sw["verdictAdvice"].as_str().unwrap_or("").contains("Poll swx_status again"),
        s(sw)
    );
}

// ════════════════════════════════════════════════════════════════════════════
// LIVE, 2026-09-11 — A SIGN-IN WAIT IS NOT A STALL
// ════════════════════════════════════════════════════════════════════════════

/// Drew's machine, and the worst thing this bridge has done to date.
///
/// A cold launch stopped at the 3DEXPERIENCE ID sign-in — a native WebView2
/// window (`DSYSysLoginPanelWebView2Class`) owned by `SWXDesktopLauncher.exe` in
/// the bridge's OWN chain, with no controls UIA can even see. The
/// "sldworks.exe within 120s" deadline then fired while he was reading it, and
/// the machine killed its own chain — including the window he was about to type
/// into — escalated to the next route, killed that too, and finished
/// `exhausted`.
///
/// The launch was not stalled. It was waiting for a person, and a person is
/// slower than any budget worth setting.
#[test]
fn a_sign_in_window_pauses_every_deadline_instead_of_killing_the_chain() {
    // sldworks NEVER appears while the sign-in is up: on the old code the
    // 4-second budget here would fire and kill the chain.
    let m = Machine::new(
        "signin",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0}}),
    );
    // The sign-in window, owned by whichever of our launcher pids is asked.
    std::fs::write(
        m.dir.join("sign-in.json"),
        json!({"hwnd": 777001, "className": "DSYSysLoginPanelWebView2Class",
               "title": "Login | 3DEXPERIENCE ID | Dassault Systemes"})
            .to_string(),
    )
    .unwrap();
    let b = m.boot(TempDir::new("signin-scratch"), &[]);
    let r = b.call("swx_start", json!({"waitSeconds": 0, "reason": "the user asked for SOLIDWORKS"}));
    check!(b, "the launch is in flight", r["success"] == true || r["stillLaunching"] == true, s(&r));

    // Well past the sldworks budget (4s here, 120s live) with the window up.
    std::thread::sleep(std::time::Duration::from_secs(7));
    let st = b.call("swx_status", json!({}));
    let launch = &st["launch"];
    check!(
        b,
        "NOTHING was killed while the user was being asked to sign in",
        m.terminated().is_empty(),
        format!("{:?}", m.terminated())
    );
    check!(
        b,
        "...the machine did not escalate to another route",
        m.invocations() == vec!["shellExecute".to_string()],
        format!("{:?}", m.invocations())
    );
    check!(
        b,
        "...the stage SAYS it is waiting on a sign-in",
        launch["stage"] == "helperSignIn" || launch["signInSeen"] == true,
        s(launch)
    );
    check!(b, "...and the attempt is not finished", launch["finished"] != true, s(launch));
    // 0.9.12: SAID PLAINLY, with the window — "waitingOn: userSignIn".
    check!(
        b,
        "...swx_status says it is waiting on the USER's sign-in, naming the window",
        st["waitingOn"] == "userSignIn"
            && st["signInWindow"]["title"].as_str().unwrap_or("").contains("3DEXPERIENCE ID") && st["signInWindow"]["hwnd"].is_number(),
        s(&st)
    );

    // The user signs in: the window closes and SOLIDWORKS comes up.
    std::fs::remove_file(m.dir.join("sign-in.json")).unwrap();
    std::fs::write(
        m.dir.join("routes.json"),
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0,
                                "attachAfterMs": 0}})
            .to_string(),
    )
    .unwrap();
    let mut attached = false;
    for _ in 0..60 {
        std::thread::sleep(std::time::Duration::from_millis(250));
        let st = b.call("swx_status", json!({}));
        if st["launch"]["stage"] == "attached" || st["com"]["running"] == true {
            attached = true;
            break;
        }
    }
    let st = b.call("swx_status", json!({}));
    check!(b, "once signed in, the launch attaches", attached, s(&st["launch"]));
    check!(
        b,
        "...and the session is still recorded as OURS — attribution survives the wait",
        st["launch"]["attributed"] == true,
        s(&st["launch"])
    );
    check!(b, "...with nothing killed, start to finish", m.terminated().is_empty(),
           format!("{:?}", m.terminated()));
}

/// The other half: an unreadable window census must PAUSE too. Resuming a
/// deadline on a census we could not take is how the machine killed a window it
/// could not see.
#[test]
fn a_window_census_that_cannot_be_read_pauses_the_deadline_too() {
    let m = Machine::new(
        "signin-blind",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0}}),
    );
    std::fs::write(m.dir.join("window-census-fails"), "").unwrap();
    let b = m.boot(TempDir::new("signin-blind-scratch"), &[]);
    b.call("swx_start", json!({"waitSeconds": 0, "reason": "launching"}));
    std::thread::sleep(std::time::Duration::from_secs(7));
    check!(
        b,
        "a blind census does not license a kill",
        m.terminated().is_empty(),
        format!("{:?}", m.terminated())
    );
}

/// RE-ATTRIBUTION NEEDS LINEAGE, not just timing.
///
/// A session that comes up after the bridge gave up IS often the one it started
/// — that is the live failure 0.6.0 fixed. But "it started after our invoke and
/// we never saw another launcher chain" is timing plus the ABSENCE of an
/// observation, and absence is not evidence: a chain that started and finished
/// between two censuses was never seen at all. 0.6.1 requires a positive link —
/// a parent walk that reaches our own chain, or a launcher log a thread of our
/// chain wrote.
#[test]
fn a_session_with_no_link_to_our_chain_is_not_adopted_after_the_fact() {
    let m = Machine::new(
        "reattr-nolineage",
        // Every route fails to attach, so the attempt finishes un-attached.
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0},
               "powershell": {"chain": false},
               "explorer": {"chain": false},
               "cmdStart": {"chain": false}}),
    );
    let b = m.boot(TempDir::new("reattr-nolineage-scratch"), &[]);
    b.call("swx_start", json!({"waitSeconds": 0, "reason": "launching"}));
    // Let the attempt run itself out.
    let mut finished = false;
    for _ in 0..80 {
        std::thread::sleep(std::time::Duration::from_millis(250));
        if b.call("swx_status", json!({}))["launch"]["finished"] == true {
            finished = true;
            break;
        }
    }
    check!(b, "precondition: the attempt finished without attaching", finished, "never finished");

    // NOW SOLIDWORKS APPEARS — with no parent link to anything of ours.
    std::fs::write(
        m.dir.join("preexisting.json"),
        json!([{"pid": 99001, "image": "SLDWORKS.exe", "ageSeconds": 0}]).to_string(),
    )
    .unwrap();
    let st = b.call("swx_status", json!({}));
    check!(
        b,
        "a SOLIDWORKS with no proven link to our chain is NOT claimed as ours",
        st["launch"]["attributed"] != true && st["launch"]["outcome"] != "attachedAfterSignIn",
        s(&st["launch"])
    );
}

/// PASS 16, finding 2. A DEAD parent may be lineage — the launcher always exits
/// once SOLIDWORKS is up — but "a pid we once recorded" is not enough once that
/// process is gone: the NUMBER is free. A user's launcher that reuses it would
/// have its SOLIDWORKS record our dead pid as its parent, with nothing alive left
/// to contradict it, and "the child is younger than the parent" is vacuously true
/// of anything that started later.
///
/// So the child must have been created inside the window we actually WATCHED the
/// parent run, plus a grace for the poll interval.
#[test]
fn a_child_that_appeared_long_after_our_launcher_died_is_not_its_descendant() {
    let m = Machine::new(
        "lineage-window",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0}}),
    );
    let b = m.boot(TempDir::new("lineage-window-scratch"), &[]);
    b.call("swx_start", json!({"waitSeconds": 0, "reason": "launching"}));
    let mut finished = false;
    for _ in 0..80 {
        std::thread::sleep(std::time::Duration::from_millis(250));
        if b.call("swx_status", json!({}))["launch"]["finished"] == true {
            finished = true;
            break;
        }
    }
    check!(b, "precondition: the attempt finished", finished, "never finished");

    // A SOLIDWORKS that claims our launcher's pid as its parent but was created
    // an hour after we last saw that launcher alive: a recycled pid, not a child.
    let chain = b.call("swx_status", json!({}))["launch"]["chainPids"].clone();
    let launcher = chain
        .as_array()
        .and_then(|a| a.iter().find(|p| p["image"] == "SWXDesktopLauncher.exe"))
        .and_then(|p| p["pid"].as_u64())
        .unwrap_or(0);
    check!(b, "precondition: we recorded a launcher pid", launcher > 0, format!("{chain}"));
    std::fs::write(m.dir.join("sldworks-parent"), launcher.to_string()).unwrap();
    std::fs::write(
        m.dir.join("preexisting.json"),
        json!([{"pid": 99123, "image": "SLDWORKS.exe", "ageSeconds": -3600}]).to_string(),
    )
    .unwrap();

    let st = b.call("swx_status", json!({}));
    check!(
        b,
        "a process created long after that launcher died is not adopted as its child",
        st["launch"]["outcome"] != "attachedAfterSignIn",
        s(&st["launch"])
    );
}

/// PID REUSE, END TO END — through the whole bridge, with the simulator finally
/// able to pose it (`census-overrides.json` retires a pid and reissues it with a
/// new creation time).
///
/// HONEST LIMIT OF THIS TEST, because a test nobody can characterise is worse
/// than none: it asserts the OUTCOME (the bridge does not adopt that session),
/// and I could NOT establish which guard produces it. Disabling the `same_process`
/// check and the lifetime-window check — together, not just one — leaves it
/// passing, so something earlier in `reattribute_after_attach` is refusing and
/// this test does not pin the lineage rule. The rule itself is proved directly,
/// with a mutation check that does fail when it is removed, in
/// `launch::tests::a_child_created_after_we_last_saw_the_parent_alive_is_not_its_descendant`.
/// What this test genuinely covers is the WHOLE PATH: a census that retires and
/// reissues a pid does not end with somebody else's session recorded as ours.
#[test]
fn a_recycled_launcher_pid_does_not_make_someone_elses_solidworks_ours() {
    let m = Machine::new(
        "pid-reuse",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0}}),
    );
    let b = m.boot(TempDir::new("pid-reuse-scratch"), &[]);
    b.call("swx_start", json!({"waitSeconds": 0, "reason": "launching"}));
    let mut finished = false;
    for _ in 0..80 {
        std::thread::sleep(std::time::Duration::from_millis(250));
        if b.call("swx_status", json!({}))["launch"]["finished"] == true {
            finished = true;
            break;
        }
    }
    check!(b, "precondition: the attempt finished", finished, "never finished");
    let chain = b.call("swx_status", json!({}))["launch"]["chainPids"].clone();
    let launcher = chain
        .as_array()
        .and_then(|a| a.iter().find(|p| p["image"] == "SWXDesktopLauncher.exe"))
        .and_then(|p| p["pid"].as_u64())
        .unwrap_or(0);
    check!(b, "precondition: we recorded and watched a launcher", launcher > 0, format!("{chain}"));

    let before = b.call("swx_status", json!({}))["launch"]["outcome"].clone();

    // OUR launcher is retired and the number REISSUED to the user's, created now
    // — inside the grace window, so timing alone cannot tell them apart. Their
    // SOLIDWORKS, created now too, names that number as its parent.
    std::fs::write(
        m.dir.join("census-overrides.json"),
        json!([
            {"retire": launcher},
            {"pid": launcher, "image": "SWXDesktopLauncher.exe", "ageSeconds": 0},
            {"pid": 991234, "image": "SLDWORKS.exe", "ageSeconds": 0, "ppid": launcher}
        ])
        .to_string(),
    )
    .unwrap();
    // ...and COM becomes attachable, which is what makes re-attribution REACHABLE
    // at all: without an attach it returns before it ever consults lineage, and
    // this test would pass while proving nothing.
    std::fs::write(
        m.dir.join("routes.json"),
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0,
                                "attachAfterMs": 0}})
            .to_string(),
    )
    .unwrap();
    // The user signs in and SOLIDWORKS comes up; the next call attaches to it —
    // which is the real sequence, and the only thing that makes re-attribution
    // REACHABLE. Without an attach it returns before consulting lineage at all
    // and this test would pass while proving nothing.
    let mut attached = false;
    for _ in 0..40 {
        b.call("swx_start", json!({"waitSeconds": 0, "reason": "attaching to the signed-in session"}));
        std::thread::sleep(std::time::Duration::from_millis(250));
        if b.call("swx_status", json!({}))["com"]["running"] == true {
            attached = true;
            break;
        }
    }
    check!(b, "precondition: COM attached, so lineage is the guard under test", attached, "never");

    let st = b.call("swx_status", json!({}));
    check!(
        b,
        "a SOLIDWORKS whose parent merely REUSED our launcher's pid is not adopted",
        st["launch"]["outcome"] != "attachedAfterSignIn",
        format!("was {before} / now {}", s(&st["launch"]))
    );
}

/// RE-ATTRIBUTION IS ONLY POSSIBLE FOR AN ATTRIBUTED ROUTE, end to end.
///
/// `explorer` and `cmdStart` cannot say what they started, so nothing of theirs
/// is ever recorded as our chain and there is no identity to walk a parent back
/// to. A session that comes up after one of them may well BE ours — and this
/// bridge still will not claim it, because it cannot prove it.
///
/// The RULE is pinned deterministically in
/// `launch::tests::an_unattributable_route_has_no_identities_to_walk_back_to`;
/// this one covers the path through the running bridge. Same honest limit as the
/// test above: it asserts the outcome, not which guard produced it.
#[test]
fn an_unattributable_route_can_never_re_attribute_a_session() {
    let m = Machine::new(
        "reattr-unattributable",
        // shellExecute reports no root at all here; explorer runs and stalls.
        json!({"shellExecute": {"chain": false}, "powershell": {"chain": false},
               "explorer": {"chain": true, "runBeginAfterMs": 0},
               "cmdStart": {"chain": false}}),
    );
    let b = m.boot(TempDir::new("reattr-unattributable-scratch"), &[]);
    b.call("swx_start", json!({"waitSeconds": 0, "reason": "launching"}));
    let mut finished = false;
    for _ in 0..100 {
        std::thread::sleep(std::time::Duration::from_millis(250));
        if b.call("swx_status", json!({}))["launch"]["finished"] == true {
            finished = true;
            break;
        }
    }
    check!(b, "precondition: the attempt finished", finished, "never finished");

    // A SOLIDWORKS appears, descended from the explorer route's own launcher —
    // which really may be ours. The bridge cannot PROVE it, so it does not say it.
    let st0 = b.call("swx_status", json!({}));
    check!(
        b,
        "precondition: no attribution root was recorded for the route that ran",
        st0["launch"]["attribution"].is_null() || st0["launch"]["attributed"] != true,
        s(&st0["launch"])
    );
    std::fs::write(
        m.dir.join("preexisting.json"),
        json!([{"pid": 99321, "image": "SLDWORKS.exe", "ageSeconds": 0}]).to_string(),
    )
    .unwrap();
    // COM attaches — so re-attribution is REACHED and refuses on the rule, rather
    // than never being asked.
    std::fs::write(
        m.dir.join("routes.json"),
        json!({"explorer": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0,
                            "attachAfterMs": 0}})
            .to_string(),
    )
    .unwrap();
    let mut attached = false;
    for _ in 0..40 {
        b.call("swx_start", json!({"waitSeconds": 0, "reason": "attaching to the session"}));
        std::thread::sleep(std::time::Duration::from_millis(250));
        if b.call("swx_status", json!({}))["com"]["running"] == true {
            attached = true;
            break;
        }
    }
    check!(b, "precondition: COM attached, so the rule is what refuses", attached, "never");

    let st = b.call("swx_status", json!({}));
    check!(
        b,
        "an unattributable route never re-attributes a session, however plausible it looks",
        st["launch"]["outcome"] != "attachedAfterSignIn" && st["launch"]["attributed"] != true,
        s(&st["launch"])
    );
}

/// THE POSITIVE CASE'S MIRROR. Same scenario, one thing changed: our launcher is
/// retired and its pid REISSUED to a different process before COM attaches. The
/// session must NOT be adopted, and the report must name which clause refused —
/// so the next person diagnosing this reads one field instead of the source.
///
/// Mutation-checked: removing the lineage rule makes this fail.
#[test]
fn a_reissued_launcher_pid_is_refused_and_the_report_names_the_clause() {
    let m = Machine::new(
        "reissue-named",
        // The attach lands AFTER the attempt has given up — which is the whole
        // sign-in shape, and the only state in which re-attribution is even
        // consulted.
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0,
                                "attachAfterMs": 6000}}),
    );
    std::fs::write(m.dir.join("preexisting.json"), json!([]).to_string()).unwrap();
    let b = m.boot(TempDir::new("reissue-named-scratch"), &[("SWX_LAUNCH_ATTACH_SECS", "2")]);
    b.call("swx_start", json!({"waitSeconds": 0, "reason": "launching"}));

    // Let the chain be recorded and watched.
    let mut launcher = 0u64;
    for _ in 0..60 {
        std::thread::sleep(std::time::Duration::from_millis(200));
        let st = b.call("swx_status", json!({}));
        if let Some(a) = st["launch"]["chainPids"].as_array() {
            if let Some(p) = a.iter().find(|p| p["image"] == "SWXDesktopLauncher.exe") {
                launcher = p["pid"].as_u64().unwrap_or(0);
                if st["launch"]["finished"] == true {
                    break;
                }
            }
        }
    }
    check!(b, "precondition: our launcher was recorded and watched", launcher > 0, "none");

    // ...then that pid is REISSUED to a different process, and a SOLIDWORKS
    // claiming it as its parent appears. Both facts are exactly what a recycled
    // pid looks like from outside.
    std::fs::write(
        m.dir.join("census-overrides.json"),
        json!([
            {"retire": launcher},
            {"pid": launcher, "image": "SWXDesktopLauncher.exe", "ageSeconds": 0},
            {"pid": 991234, "image": "SLDWORKS.exe", "ageSeconds": 0, "ppid": launcher}
        ])
        .to_string(),
    )
    .unwrap();

    let mut st = json!({});
    for _ in 0..40 {
        std::thread::sleep(std::time::Duration::from_millis(250));
        st = b.call("swx_status", json!({}));
        if st["com"]["attached"] == true {
            break;
        }
    }
    check!(b, "precondition: COM attached, so the lineage walk runs", st["com"]["attached"] == true, s(&st["com"]));
    check!(
        b,
        "the session is NOT adopted on a reissued pid",
        st["launch"]["outcome"] != "attachedAfterSignIn",
        s(&st["launch"])
    );
    // TWO LAYERS, since 0.6.7: the report carries the COMPOSITE reason (no
    // candidate could be proved), and the ledger carries the per-candidate
    // clause — because "the last one stands" hid which process failed which test.
    let why = st["launch"]["reattributionRefusedBecause"].as_str().unwrap_or("").to_string();
    check!(
        b,
        "...the report names the composite reason",
        why == "no_candidate_descends" || why == "attached_pid_not_ours",
        format!("reattributionRefusedBecause={why:?} / {}", s(&st["launch"]))
    );
    let ledger = s(&b.call("swx_action_ledger", json!({"limit": 80})));
    check!(
        b,
        "...and the ledger names the clause the REISSUED pid failed on",
        ledger.contains("alive_but_different_process") || ledger.contains("child_outside_window"),
        ledger.chars().rev().take(900).collect::<String>().chars().rev().collect::<String>()
    );
}

/// CONSENT-AFFECTING, from pass 19. Re-attribution must claim ONLY the process
/// COM is attached to.
///
/// 0.6.6 used the attached pid to ORDER the candidates and took the first that
/// descended — so with two SOLIDWORKS running it could prove lineage for OUR
/// launcher's child while COM was attached to a DIFFERENT process, and then
/// label the session `attributed:true`. Everything downstream reads that label:
/// the quit gate's bridge-launched proof, and a quit ladder that builds its
/// Identity from the COM pid. The bridge would have been willing to END a session
/// nothing had proved was ours.
///
/// Staged here so the attached process is NOT ours and a non-attached one IS:
/// the route's own SOLIDWORKS is re-parented to a stranger, and a second one is
/// given our launcher as its parent.
#[test]
fn re_attribution_claims_only_the_process_com_is_attached_to() {
    let m = Machine::new(
        "attached-only",
        json!({"shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 0,
                                "attachAfterMs": 6000}}),
    );
    std::fs::write(m.dir.join("preexisting.json"), json!([]).to_string()).unwrap();
    let b = m.boot(TempDir::new("attached-only-scratch"), &[("SWX_LAUNCH_ATTACH_SECS", "2")]);
    b.call("swx_start", json!({"waitSeconds": 0, "reason": "launching"}));

    let mut launcher = 0u64;
    let mut sw_pid = 0u64;
    for _ in 0..60 {
        std::thread::sleep(std::time::Duration::from_millis(200));
        let st = b.call("swx_status", json!({}));
        if let Some(a) = st["launch"]["chainPids"].as_array() {
            if let Some(p) = a.iter().find(|p| p["image"] == "SWXDesktopLauncher.exe") {
                launcher = p["pid"].as_u64().unwrap_or(0);
            }
        }
        if let Some(p) = st["solidworks"]["processId"].as_u64() {
            sw_pid = p;
        }
        if st["launch"]["finished"] == true && launcher > 0 && sw_pid > 0 {
            break;
        }
    }
    check!(b, "precondition: chain and SOLIDWORKS observed", launcher > 0 && sw_pid > 0,
           format!("launcher={launcher} sw={sw_pid}"));

    // The ATTACHED process is re-parented to a stranger; a SECOND SOLIDWORKS,
    // which COM is NOT attached to, descends from our launcher — created at the
    // moment we last SAW that launcher alive, so it is genuinely inside the
    // lineage window and the ONLY thing that can refuse it is the pid-equality
    // rule under test.
    let last_seen = b.call("swx_status", json!({}))["launch"]["chainLastSeen"]
        .as_array()
        .and_then(|rows| {
            rows.iter()
                .find(|r| r[0].as_u64() == Some(launcher))
                .and_then(|r| r[2].as_u64())
        })
        .unwrap_or(0);
    check!(b, "precondition: we know when the launcher was last seen", last_seen > 0, "none");
    // ABSOLUTE, not an age: the census computes "now" when it is read, so a
    // relative age drifts by however long the test takes to get there — and the
    // window is one census interval wide.
    std::fs::write(
        m.dir.join("census-overrides.json"),
        json!([
            {"pid": sw_pid, "image": "SLDWORKS.exe", "ageSeconds": 0, "ppid": 4242},
            {"pid": 900777, "image": "SLDWORKS.exe", "createdAt": last_seen, "ppid": launcher}
        ])
        .to_string(),
    )
    .unwrap();

    let mut st = json!({});
    for _ in 0..40 {
        std::thread::sleep(std::time::Duration::from_millis(250));
        st = b.call("swx_status", json!({}));
        if st["com"]["attached"] == true {
            break;
        }
    }
    check!(b, "precondition: COM attached", st["com"]["attached"] == true, s(&st["com"]));
    check!(
        b,
        "precondition: the attached process is NOT the one that descends from our chain",
        st["com"]["processId"].as_u64() == Some(sw_pid),
        s(&st["com"])
    );
    // NOTE on `attributed`: it stays TRUE here, and correctly — this attempt DID
    // launch a chain and attribute its root. What must not happen is the extra
    // claim that the session COM is now talking to is that launch's product.
    check!(
        b,
        "the session is NOT re-claimed, because the process COM answers for is not ours",
        st["launch"]["outcome"] != "attachedAfterSignIn",
        s(&st["launch"])
    );
    check!(
        b,
        "...and no claim is recorded about which SOLIDWORKS this attempt produced",
        st["launch"]["attributedSolidworks"].is_null(),
        s(&st["launch"])
    );
    check!(
        b,
        "...and the refusal NAMES that clause",
        st["launch"]["reattributionRefusedBecause"] == "attached_pid_not_ours",
        format!("{}", st["launch"]["reattributionRefusedBecause"])
    );
}

/// MEASURED 2026-10-12 (hosted 0.9.27): with SOLIDWORKS NOT running, `launch`
/// still said stage "attached" and "SOLIDWORKS is up and COM-attached. Carry
/// on." about the launch of 2026-10-02 — its process ten days gone. A record
/// that outlived every process it names is ENDED.
#[test]
fn a_launch_record_that_outlived_its_processes_is_ended_not_attached() {
    let m = Machine::new("launch-stale-record", json!({}));
    // pid 32224 has been REUSED by an unrelated process created just now: the
    // same number, another process (identity is pid + creation time).
    let mut rows: Vec<Value> = serde_json::from_str(&std::fs::read_to_string(m.dir.join("preexisting.json")).unwrap()).unwrap();
    rows.push(json!({"pid": 32224, "image": "SWXDesktopUpdate.exe", "ageSeconds": 5}));
    std::fs::write(m.dir.join("preexisting.json"), Value::Array(rows).to_string()).unwrap();
    let scratch = TempDir::new("launch-stale-record-scratch");
    std::fs::write(
        scratch.join("launch-state.json"),
        json!({"attempt": {
            "id": 7, "startedAt": 1790953690u64, "invokedAt": 1790953690u64, "route": "shellExecute",
            "stage": "attached", "finished": true, "outcome": "attached",
            "attribution": {"pid": 32224, "createdAt": 1790953692u64, "source": "shellExecuteHandle"},
            "attributedSolidworks": {"pid": 41000, "createdAt": 1790953720u64},
            "chainPids": [{"pid": 32224, "image": "CATSTART.exe", "createdAt": 1790953692u64}]
        }}).to_string(),
    )
    .unwrap();
    let b = m.boot(TempDir::borrowed(&scratch.0), &[]);
    let st = b.call("swx_status", json!({}));
    let l = &st["launch"];
    check!(
        b,
        "stage ended (not attached), finished, endedWhy names the gone pids, the old stage kept as recordedStage",
        l["stage"] == "ended" && l["finished"] == true && l["recordedStage"] == "attached"
            && l["endedWhy"].as_str().unwrap_or("").contains("32224"),
        s(l)
    );
    check!(
        b,
        "the advice never says carry on while nothing it names runs",
        !l["advice"].as_str().unwrap_or("").to_lowercase().contains("carry on") && l["advice"].as_str().unwrap_or("").contains("OVER"),
        s(l)
    );
}

// ── 0.11.2: THE FALSE STALL OF 2026-10-15 ───────────────────────────────────
//
// From the laptop's ledger (attempt 24, route platformShortcut): Run Begin at
// 14:49:04 and the helper sign-in with it; at 14:51:11 the supervisor called
// the route STALLED (no sldworks.exe within the budget), killed CATSTART and
// invoked the shortcut AGAIN; at 14:51:17 sldworks.exe came up — the FIRST
// invoke's — and the second invoke reached it as an "open" request: a File ▸
// Open dialog that blocked every quit for the rest of the day.

/// The File ▸ Open as measured, owned by the simulated main frame, its frame disabled.
fn open_dialog() -> Value {
    json!({"hwnd": 205698, "className": "#32770", "title": "Open ", "visible": true, "owner": 6622700,
           "ownerEnabled": false, "style": 0x96CC_02C4u64, "exStyle": 0x10101u64, "rect": [0, 0, 853, 533]})
}

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

#[test]
fn a_slow_helper_sign_in_is_not_a_stall_and_nothing_is_invoked_again() {
    // The incident scaled to the suite's budgets (sldworks 4 s): the helper
    // sign-in from +0.1 s, sldworks.exe at +5.5 s — past the sldworks budget,
    // as 2 min 13 s was past 120 s — and attach at +6.5 s. A re-invoke would
    // put up the Open dialog.
    let m = Machine::new(
        "helper-slow",
        json!({
            "shellExecute": {"chain": true, "runBeginAfterMs": 0, "helperAfterMs": 100, "sldworksAfterMs": 5500, "attachAfterMs": 6500},
            "powershell": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 300, "dialogOnInvoke": [open_dialog()]}
        }),
    );
    let b = m.boot(TempDir::new("scratch"), &[]);
    b.call("swx_start", json!({"reason": "modelling for Drew", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 30);
    check!(b, "the launch ATTACHES to the first invoke's SOLIDWORKS", st["launch"]["outcome"] == "attached", s(&st["launch"]));
    check!(b, "ONE invocation: the shortcut is never invoked again", m.invocations() == vec!["shellExecute".to_string()], format!("{:?}", m.invocations()));
    check!(b, "nothing was killed: a chain in its helper sign-in is not stalled", m.terminated().is_empty(), format!("{:?}", m.terminated()));
    check!(
        b,
        "no stall on the record, and no dialog on the screen",
        !ledger_actions(&b).iter().any(|e| e["action"] == "solidworks_launch_stalled")
            && !std::fs::read_to_string(m.dir.join("windows.json")).unwrap_or_default().contains("205698"),
        s(&json!(ledger_actions(&b)))
    );
}

#[test]
fn a_solidworks_that_comes_up_after_a_stall_cleanup_is_waited_for_never_re_invoked_over() {
    // No helper log, so the sldworks budget (4 s) does run out — but the
    // launcher had already spawned sldworks.exe, which comes up at +4.3 s
    // although its chain was killed.
    let m = Machine::new(
        "settle",
        json!({
            "shellExecute": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 4300, "sldworksSurvivesKill": true, "attachAfterMs": 5000},
            "powershell": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 300, "dialogOnInvoke": [open_dialog()]}
        }),
    );
    let b = m.boot(TempDir::new("scratch"), &[("SWX_LAUNCH_RETRY_SETTLE_MS", "2500")]);
    b.call("swx_start", json!({"reason": "modelling for Drew", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 30);
    check!(b, "the next route is NEVER invoked over a SOLIDWORKS this launch started", m.invocations() == vec!["shellExecute".to_string()], format!("{:?}", m.invocations()));
    check!(
        b,
        "...the retry is declined on the record, naming the SOLIDWORKS",
        ledger_actions(&b).iter().any(|e| e["action"] == "launch_retry_declined" && e["detail"]["why"].as_str().unwrap_or("").contains("already running")),
        s(&json!(ledger_actions(&b)))
    );
    check!(b, "...and the launch attaches to it", st["launch"]["outcome"] == "attached", s(&st["launch"]));
}

#[test]
fn a_file_dialog_a_retry_raised_is_attributed_to_it_and_cancelled_by_the_launch() {
    // A genuine stall (no Run Begin, no SOLIDWORKS) → a legitimate retry,
    // whose invoke puts up the Open dialog anyway. It is the launch's own: the
    // supervisor attributes it to `launch.retry` and cancels it.
    let m = Machine::new(
        "retry-dialog",
        json!({
            "shellExecute": {"chain": true},
            "powershell": {"chain": true, "runBeginAfterMs": 0, "sldworksAfterMs": 100, "attachAfterMs": 300, "dialogOnInvoke": [open_dialog()]}
        }),
    );
    std::fs::write(m.dir.join("file-dialogs.json"), json!({"205698": {"standard": true, "fileName": ""}}).to_string()).unwrap();
    std::fs::write(m.dir.join("last-input-secs"), "3600").unwrap();
    let b = m.boot(TempDir::new("scratch"), &[]);
    b.call("swx_start", json!({"reason": "modelling for Drew", "waitSeconds": 0}));
    let st = wait_for_launch(&b, 30);
    check!(b, "the retry attaches", st["launch"]["outcome"] == "attached" && m.invocations().len() == 2, s(&st["launch"]));
    let deadline = Instant::now() + Duration::from_secs(8);
    let mut cancelled = None;
    while Instant::now() < deadline && cancelled.is_none() {
        cancelled = ledger_actions(&b).into_iter().find(|e| e["action"] == "dialog_cancelled");
        std::thread::sleep(Duration::from_millis(200));
    }
    let c = cancelled.unwrap_or(Value::Null);
    check!(
        b,
        "the dialog is attributed to launch.retry and CANCELLED by the launch, ledgered",
        c["detail"]["raisedDuring"] == "launch.retry" && c["detail"]["ok"] == true && c["detail"]["hwnd"] == 205698,
        s(&json!(ledger_actions(&b)))
    );
    check!(b, "...the window is gone", !std::fs::read_to_string(m.dir.join("windows.json")).unwrap_or_default().contains("205698"), "");
}