main
Drew Owens 0.11.3 source 7364e19 5d ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598
//! End-to-end verb suite against the REAL binary in mock mode.
//!
//! This is the port of `tests/test_verbs.py`, plus the gates the Rust port owes
//! the brief: verb coverage measured from calls actually made, response-shape
//! invariants on every call (in the harness), numbered error paths, and effects
//! asserted on disk rather than "the response said it worked".
//!
//! It runs as ONE test function on purpose: the verbs share a stateful mock
//! application (open documents, active doc), so their ORDER is part of what is
//! under test — and one server boot keeps the suite fast.

mod common;

use common::{manifest, manifest_verbs, Bridge, TempDir};
use serde_json::{json, Value};

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

#[test]
fn every_verb_over_http_against_the_real_binary() {
    // A MACHINE THIS PROCESS CAN LOOK AT. The safe-close sweep refuses to close
    // anything while the window census is unreadable — a dialog nobody can see is
    // the one that matters — so a walk that ends in a real close needs a session
    // the bridge can actually see. Without it this test would exercise the REFUSAL
    // and silently stop covering the close.
    let machine = TempDir::new("e2e-machine");
    std::fs::write(machine.join("windows.json"), "[]").unwrap();
    let b = Bridge::start_with(&[("SWX_LAUNCH_FAKE_DIR", &machine.path())]);

    // ── health endpoints ────────────────────────────────────────────────────
    let (status_code, health) = b.get("/status");
    check!(b, "GET /status is 200", status_code == 200, s(&health));
    check!(b, "health status ok", health["status"] == "ok", s(&health));
    check!(b, "health mock flag", health["mock"] == true, s(&health));
    check!(b, "health led", health["led"] == "yellow", s(&health));
    check!(
        b,
        "health summary + tooltip are present for the status chip",
        health["summary"].is_string() && health["tooltip"].is_string(),
        s(&health)
    );
    check!(
        b,
        "health version matches the manifest",
        health["bridgeVersion"] == manifest()["version"],
        format!("{} vs {}", health["bridgeVersion"], manifest()["version"])
    );
    let (_, alias) = b.get("/health");
    check!(b, "/health mirrors /status", alias["status"] == "ok", s(&alias));
    let (missing, _) = b.get("/nope");
    check!(b, "unknown path is 404", missing == 404, missing.to_string());

    // ── malformed input: a clean 400, never a 500 ───────────────────────────
    let (code, body) = b.post_raw("{not json");
    check!(b, "malformed body is 400", code == 400, format!("{code} {body}"));
    check!(b, "malformed body answers JSON", body.contains("Invalid JSON"), body.clone());

    // ── core ────────────────────────────────────────────────────────────────
    let r = b.call("swx_describe", json!({}));
    let described: Vec<String> = r["verbs"]
        .as_array()
        .expect("describe verbs[]")
        .iter()
        .map(|v| v["verb"].as_str().unwrap().to_string())
        .collect();
    check!(b, "describe lists the whole v0.3 surface", described.len() >= 60, s(&r));
    check!(b, "describe advertises the modeling ops", r["scriptOps"].as_array().unwrap().contains(&json!("extrude")), s(&r));
    check!(
        b,
        "describe carries the LIVE-VERIFIED export format matrix",
        r["exportFormats"]["provenModelFormats"].as_array().unwrap().contains(&json!("glb"))
            && r["exportFormats"]["blockedFormats"].as_array().unwrap().contains(&json!("wrl")),
        s(&r)
    );
    check!(b, "describe keyword", r["keyword"] == "swx", s(&r));
    check!(
        b,
        "describe carries a risk per verb",
        r["verbs"].as_array().unwrap().iter().all(|v| v["risk"].is_string()),
        s(&r)
    );

    let r = b.call("swx_readiness", json!({}));
    check!(b, "readiness ready (mock)", r["ready"] == true, s(&r));

    let r = b.call("swx_status", json!({}));
    check!(b, "status success", r["success"] == true, s(&r));
    check!(b, "status reports the com host pid", r["com"]["hostPid"].is_u64(), s(&r));
    check!(b, "status etiquette", r["windowEtiquette"] == "background", s(&r));

    let r = b.call("swx_progress", json!({}));
    check!(b, "progress idle", r["active"] == json!([]), s(&r));

    let r = b.call("swx_nonsense", json!({}));
    check!(
        b,
        "unknown verb is hinted with the valid list",
        r["_hint"].as_str().unwrap_or("").contains("Valid swx commands"),
        s(&r)
    );
    check!(b, "unknown verb invites a bug report", r["_reportIssues"].is_string(), s(&r));

    // ── app lifecycle ───────────────────────────────────────────────────────
    let r = b.call("swx_docs", json!({}));
    check!(b, "docs before start errors", r["success"] == false, s(&r));
    check!(b, "a failure carries a hint", r["_hint"].is_string(), s(&r));

    let r = b.call("swx_start", json!({}));
    check!(b, "start", r["success"] == true && r["started"] == true, s(&r));
    check!(b, "start progress is terminal", r["progress"]["percent"] == 100, s(&r));
    check!(b, "start progress reports elapsed", r["progress"]["elapsedSec"].is_number(), s(&r));
    check!(b, "start etiquette", r["windowEtiquette"] == "background", s(&r));

    // ── documents ───────────────────────────────────────────────────────────
    let r = b.call("swx_open", json!({"path": "C:\\mock\\gearbox.sldasm"}));
    check!(b, "open assembly", r["success"] == true && r["opened"]["type"] == "assembly", s(&r));

    let r = b.call("swx_open", json!({"path": "C:\\mock\\readme.txt"}));
    check!(b, "open rejects a non-SOLIDWORKS file", r["success"] == false, s(&r));

    let r = b.call("swx_open", json!({}));
    check!(b, "open without a path is rejected", r["success"] == false, s(&r));

    let r = b.call("swx_docs", json!({}));
    check!(b, "docs lists the open documents", !r["docs"].as_array().unwrap().is_empty(), s(&r));
    check!(b, "docs active is the assembly", r["active"]["type"] == "assembly", s(&r));

    // ── properties ──────────────────────────────────────────────────────────
    // props_set MODIFIES the document — it leaves it dirty, so the user's own
    // Ctrl+S would commit bridge-authored data to their file. Gated like every
    // other write; "in memory until a gated save" ignored the ungatable
    // persist route, which is the user.
    let r = b.call("swx_props_set", json!({"properties": {"PartNo": "ASM-9", "Rev": "B"}}));
    check!(
        b,
        "swx_props_set refuses to modify a document the bridge did not create",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    // On a document the bridge made, it is the normal case.
    b.call("swx_new_document", json!({"type": "part"}));
    let r = b.call("swx_props_set", json!({"properties": {"PartNo": "ASM-9", "Rev": "B"}}));
    check!(b, "props_set", r["success"] == true && r["set"]["Rev"] == 1, s(&r));

    let r = b.call("swx_props_get", json!({}));
    check!(b, "props_get roundtrip", r["properties"]["Rev"]["resolved"] == "B", s(&r));
    b.call("swx_close_doc", json!({"save": false}));
    b.call("swx_activate_document", json!({"name": "gearbox.sldasm"}));

    let r = b.call("swx_props_set", json!({"properties": {}}));
    check!(b, "props_set with no properties is rejected", r["success"] == false, s(&r));

    // swx_save is the PERSIST step, so it is gated on a document the bridge did
    // not create — swx_props_set is not, because nothing it does reaches the
    // user's file until this verb runs.
    let r = b.call("swx_save", json!({}));
    check!(b, "swx_save refuses to persist into the user's own document", r["errorCode"] == "user_writes_disabled", s(&r));
    check!(b, "...and reports the posture it is in", r["userWrites"] == "disabled", s(&r));
    // Confirm + reason are NOT enough on their own any more: the process-level
    // opt-in is the part an AI cannot grant itself.
    let r = b.call("swx_save", json!({"allowUserWrites": true, "confirm": true, "reason": "the user asked"}));
    check!(
        b,
        "swx_save: arguments alone cannot unlock a user write",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );

    // ── BOM (and its CSV, on disk) ──────────────────────────────────────────
    let r = b.call("swx_bom", json!({"format": "csv"}));
    check!(b, "bom rows", r["rowCount"] == 3, s(&r));
    check!(
        b,
        "bom quantities aggregate",
        r["rows"].as_array().unwrap().iter().any(|row| row["quantity"] == 8),
        s(&r)
    );
    check!(
        b,
        "bom rows are sorted by name",
        r["rows"][0]["name"] == "bracket" && r["rows"][2]["name"] == "shaft",
        s(&r)
    );
    let csv = r["csv"].as_str().unwrap_or("").to_string();
    check!(b, "bom csv content", csv.contains("m4-screw"), csv.clone());
    check!(b, "bom csv property columns", csv.contains("BRK-100"), csv.clone());

    let csv_path = r["csvPath"].as_str().unwrap_or("").to_string();
    check!(b, "bom csv file written", std::path::Path::new(&csv_path).is_file(), csv_path.clone());
    check!(
        b,
        "bom csv landed in the bridge's own scratch dir",
        csv_path.starts_with(&b.scratch.path()),
        format!("{csv_path} not under {}", b.scratch.path())
    );
    // ...and it really is CSV, with the union of property names as columns.
    let on_disk = std::fs::read_to_string(&csv_path).expect("read csv");
    let lines: Vec<&str> = on_disk.lines().collect();
    check!(b, "csv has a header + 3 rows", lines.len() == 4, on_disk.clone());
    check!(
        b,
        "csv header carries both property columns",
        lines[0] == "item,name,configuration,quantity,file,Material,PartNo",
        lines[0].to_string()
    );
    check!(
        b,
        "csv rows have one cell per header column",
        lines.iter().all(|l| l.split(',').count() == 7),
        on_disk.clone()
    );

    let r = b.call("swx_bom", json!({"path": "C:\\mock\\gearbox.sldasm", "topLevelOnly": true}));
    check!(b, "bom topLevelOnly is echoed back", r["topLevelOnly"] == true, s(&r));

    b.call("swx_open", json!({"path": "C:\\mock\\bracket.sldprt"}));
    let r = b.call("swx_bom", json!({}));
    check!(b, "bom rejects a part", r["success"] == false, s(&r));

    // ── the self-test (0.10.0): read level changes nothing ───────────────────
    let docs_before = b.call("swx_docs", json!({}))["count"].clone();
    let r = b.call("swx_selftest", json!({}));
    check!(
        b,
        "swx_selftest (read) reports one row per check, with the version facts, and changes nothing",
        r["success"] == true && r["level"] == "read" && r["results"].as_array().map(|a| a.len() >= 4).unwrap_or(false)
            && r["solidworks"]["versionSupport"].is_object() && b.call("swx_docs", json!({}))["count"] == docs_before,
        s(&r)
    );

    // ── analysis ────────────────────────────────────────────────────────────
    let r = b.call("swx_mass_properties", json!({}));
    check!(
        b,
        "mass properties",
        r["success"] == true && r["massKg"].as_f64().unwrap_or(0.0) > 0.0,
        s(&r)
    );

    let r = b.call("swx_interference", json!({"path": "C:\\mock\\gearbox.sldasm"}));
    check!(b, "interference", r["count"] == 1, s(&r));

    let r = b.call("swx_interference", json!({"path": "C:\\mock\\bracket.sldprt"}));
    check!(b, "interference rejects a part", r["success"] == false, s(&r));

    // rebuild_check calls ForceRebuild3 — it re-solves features and dirties the
    // document, which this bridge's own com_eval hazard list already named as
    // "rebuilds the user's model".
    let r = b.call("swx_rebuild_check", json!({}));
    check!(
        b,
        "swx_rebuild_check refuses to rebuild a document the bridge did not create",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    b.call("swx_new_document", json!({"type": "part"}));
    let r = b.call("swx_rebuild_check", json!({}));
    check!(b, "rebuild check", r["errorCount"] == 0, s(&r));
    b.call("swx_close_doc", json!({"save": false}));
    b.call("swx_activate_document", json!({"name": "bracket.sldprt"}));

    // ── export + Pack and Go: bytes on disk, not claims ─────────────────────
    let tmp = TempDir::new("out");
    let out = tmp.join("bracket.step");
    let r = b.call("swx_export", json!({"format": "step", "out": out.to_string_lossy()}));
    check!(b, "export step", r["success"] == true && out.is_file(), s(&r));
    let bytes = std::fs::read(&out).expect("read export");
    check!(b, "export wrote real bytes", !bytes.is_empty(), format!("{} bytes", bytes.len()));
    check!(
        b,
        "export byte count is reported honestly",
        r["bytes"].as_u64() == Some(bytes.len() as u64),
        s(&r)
    );

    let r = b.call("swx_export", json!({"format": "wat"}));
    check!(b, "export rejects an unsupported format", r["success"] == false, s(&r));

    // A relay caller must not aim `out` at a relative / traversal path — that
    // would resolve against the bridge's cwd (an escape off the desktop).
    let r = b.call("swx_export", json!({"format": "step", "out": "../../victim.txt"}));
    check!(
        b,
        "export refuses a relative traversal out",
        r["errorCode"] == "unsafe_path",
        s(&r)
    );
    let r = b.call("swx_bom", json!({"path": "C:\\mock\\gearbox.sldasm", "format": "csv", "out": "escape.csv"}));
    check!(b, "bom csv refuses a relative out", r["errorCode"] == "unsafe_path", s(&r));

    // No `out`: the file must land in the bridge's own pruned scratch dir.
    let r = b.call("swx_export", json!({"format": "iges", "path": "C:\\mock\\bracket.sldprt"}));
    let auto = r["exported"].as_str().unwrap_or("").to_string();
    check!(b, "export without out succeeds", r["success"] == true, s(&r));
    check!(
        b,
        "export without out lands in the scratch dir with the right extension",
        auto.starts_with(&b.scratch.path()) && auto.ends_with(".igs"),
        auto.clone()
    );
    check!(b, "auto-named export exists", std::path::Path::new(&auto).is_file(), auto.clone());

    // Pack and Go copies the document AND its whole reference tree — a bulk
    // extraction of the user's design, not one export — so it needs to be aimed
    // at a document the bridge created. (The server used to skip the ownership
    // question entirely for an empty destination while the real com host
    // refused, so this verb was dead on a real machine and green here.)
    let png_dir = tmp.join("packandgo");
    let r = b.call(
        "swx_pack_and_go",
        json!({"path": "C:\\mock\\gearbox.sldasm", "out": png_dir.to_string_lossy()}),
    );
    check!(
        b,
        "swx_pack_and_go refuses to collect a document the bridge did not create",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    check!(
        b,
        "...and left no directory behind after the refusal",
        !png_dir.exists(),
        png_dir.display().to_string()
    );
    b.call("swx_new_document", json!({"type": "assembly"}));
    let r = b.call("swx_pack_and_go", json!({"out": png_dir.to_string_lossy()}));
    check!(b, "pack and go", r["success"] == true, s(&r));
    let files = r["files"].as_array().cloned().unwrap_or_default();
    check!(b, "pack and go lists files", !files.is_empty(), s(&r));
    check!(
        b,
        "pack and go files exist on disk",
        files.iter().all(|f| std::path::Path::new(f.as_str().unwrap_or("")).is_file()),
        s(&r)
    );

    let r = b.call("swx_pack_and_go", json!({}));
    check!(b, "pack and go without out is rejected", r["success"] == false, s(&r));

    // ── find_files ──────────────────────────────────────────────────────────
    let fixtures = TempDir::new("find");
    for name in ["a.sldprt", "b.sldasm", "~$b.sldasm", "c.txt"] {
        std::fs::write(fixtures.join(name), b"x").expect("fixture");
    }
    let root = fixtures.path();
    let r = b.call("swx_find_files", json!({"roots": [root]}));
    check!(b, "find_files finds 2 (and skips the ~$ lock file)", r["count"] == 2, s(&r));
    check!(b, "find_files reports the roots it used", r["roots"][0] == root, s(&r));

    let r = b.call("swx_find_files", json!({"roots": [root], "types": ["assembly"]}));
    check!(
        b,
        "find_files type filter",
        r["count"] == 1 && r["files"][0]["type"] == "assembly",
        s(&r)
    );

    let r = b.call("swx_find_files", json!({"roots": [root], "query": "a.sld"}));
    check!(b, "find_files query filter", r["count"] == 1, s(&r));

    let r = b.call("swx_find_files", json!({"roots": [root], "limit": 1}));
    check!(b, "find_files limit truncates honestly", r["count"] == 1 && r["truncated"] == true, s(&r));


    // ══ v0.3: the Fusion-parity surface ═════════════════════════════════════
    // State on entry: gearbox.sldasm and bracket.sldprt are open; bracket is
    // active. Order matters — these verbs share the mock's stateful app.

    let r = b.call("swx_get_app_state", json!({}));
    check!(b, "app_state running", r["running"] == true, s(&r));
    check!(b, "app_state lists the open documents", r["documents"].as_array().unwrap().len() >= 2, s(&r));
    check!(b, "app_state names the active document", r["activeDocument"].is_string(), s(&r));
    check!(b, "app_state reports the workspace (the active doc's type)", r["workspace"].is_string() && r["workspace"] != "none", s(&r));

    b.call("swx_activate_document", json!({"name": "bracket.sldprt"}));
    let r = b.call("swx_document_info", json!({}));
    check!(b, "document_info names the active doc", r["name"] == "bracket.sldprt", s(&r));
    check!(b, "document_info reports it as saved (it has a path)", r["isSaved"] == true, s(&r));
    check!(b, "document_info lists configurations", r["configurations"][0] == "Default", s(&r));

    // ── create: the verb Drew asked for ─────────────────────────────────────
    let r = b.call("swx_new_document", json!({"type": "part"}));
    check!(b, "new_document creates a part", r["success"] == true && r["created"]["type"] == "part", s(&r));
    let scratch_title = r["created"]["title"].as_str().unwrap_or("").to_string();
    check!(
        b,
        "new_document names it from SOLIDWORKS' own Part<n>, and gives it a FILE",
        scratch_title.starts_with("Part") && scratch_title.ends_with(".SLDPRT"),
        scratch_title.clone()
    );
    check!(
        b,
        "...so it has an identity that is not just a title (0.6.0)",
        r["documentIdentity"]["identity"] == "path"
            && r["created"]["path"].as_str().unwrap_or("").contains("scratch"),
        s(&r)
    );
    // 0.6.0: the old claim here was "a brand-new document has NO path until it is
    // saved". That was true, and it was the defect — three pathless documents
    // sharing one title were addressable by nothing. `keepUnsaved:true` is where
    // that state now lives, and it is reported rather than silent.
    let bare = b.call("swx_new_document", json!({"type": "part", "keepUnsaved": true}));
    check!(
        b,
        "keepUnsaved:true still makes a pathless document...",
        bare["created"]["path"] == "" && bare["documentIdentity"]["identity"] == "titleOnly",
        s(&bare)
    );
    check!(
        b,
        "...and SAYS that its title is the only name it has",
        bare["documentIdentity"]["warning"].as_str().unwrap_or("").contains("ambiguous_target"),
        s(&bare)
    );
    check!(b, "new_document reports the template it used", r["template"].is_string(), s(&r));

    let r = b.call("swx_new_document", json!({"type": "sandwich"}));
    check!(b, "new_document rejects an unknown type", r["success"] == false, s(&r));

    // The bridge WROTE DOWN that it created that document — which is what lets
    // swx_reset_workspace clean up after itself without touching user documents.
    let r = b.call("swx_action_ledger", json!({}));
    check!(
        b,
        "the action ledger recorded the document the bridge created",
        r["actions"].as_array().unwrap().iter().any(|a| a["action"] == "document_created"
            && a["detail"]["title"] == "Part1"),
        s(&r)
    );
    check!(b, "ledger entries are timestamped", r["actions"][0]["at"].as_u64().unwrap_or(0) > 0, s(&r));

    let r = b.call("swx_design_info", json!({}));
    check!(b, "design_info on the empty scratch part has no bodies", r["bodies"] == 0, s(&r));

    // ── macros: the verb whose gate cannot be loosened ──────────────────────
    // Full coverage lives in `running_a_macro_is_arbitrary_code_and_is_gated_as_such`;
    // this is the sweep's assertion that the DEFAULT posture refuses, which is
    // the property that must hold on every bridge that has not been explicitly
    // opted in.
    let r = b.call("swx_run_macro", json!({"path": "C:\\anything.swp"}));
    check!(
        b,
        "swx_run_macro refuses in the default posture — a macro is arbitrary code",
        r["success"] == false,
        s(&r)
    );

    // ── the modeling DSL ────────────────────────────────────────────────────
    let r = b.call("swx_run_script", json!({"script": "import adsk; do_stuff()"}));
    check!(b, "run_script refuses a string of code", r["errorCode"] == "bad_script", s(&r));
    check!(b, "a refused script teaches the grammar", r["ops"].as_array().unwrap().contains(&json!("sketch_rect")), s(&r));
    check!(b, "a refused script shows a worked example", r["example"]["script"].is_array(), s(&r));

    let r = b.call("swx_run_script", json!({"script": [{"op": "extrude", "depthMm": 5}]}));
    check!(b, "run_script refuses an extrude with no sketch", r["errorCode"] == "bad_script", s(&r));
    check!(
        b,
        "the refusal names the step that cannot work",
        r["error"].as_str().unwrap_or("").contains("no sketch to consume"),
        s(&r)
    );

    let built = TempDir::new("built");
    let part_path = built.join("bracket-built.sldprt");
    let r = b.call("swx_run_script", json!({"script": [
        {"op": "sketch_rect", "plane": "Front Plane", "widthMm": 50, "heightMm": 30},
        {"op": "extrude", "depthMm": 20},
        {"op": "set_material", "name": "6061 Alloy"},
        {"op": "set_prop", "name": "PartNo", "value": "BRK-100"},
        {"op": "rebuild"},
        {"op": "zoom_fit"}
    ]}));
    check!(b, "run_script builds", r["success"] == true && r["stepCount"] == 6, s(&r));
    check!(b, "run_script reports each step", r["steps"][1]["op"] == "extrude", s(&r));
    check!(b, "run_script converts mm at the boundary", r["steps"][0]["result"]["widthMm"] == 50.0, s(&r));

    // Verify the GEOMETRY, not the step list.
    let r = b.call("swx_inspect_bodies", json!({}));
    check!(b, "inspect_bodies sees the solid", r["bodyCount"] == 1, s(&r));
    check!(b, "inspect_bodies reports millimetres", r["units"] == "mm", s(&r));
    check!(b, "inspect_bodies reports the size that was asked for", r["bodies"][0]["sizeMm"]["x"] == 50.0, s(&r));
    check!(b, "inspect_bodies reports a volume", r["bodies"][0]["volumeMm3"].as_f64().unwrap_or(0.0) > 0.0, s(&r));

    let r = b.call("swx_inspect_bodies", json!({"path": "C:\\mock\\gearbox.sldasm"}));
    check!(b, "inspect_bodies rejects an assembly", r["success"] == false, s(&r));

    // ── assembly components: the verb the BOM needs ─────────────────────────
    // Round-trip proof that swx_add_component -> swx_bom is a real chain: build
    // a part FILE, make an assembly, insert the file twice, and read the
    // quantity back out of the BOM.
    let asmdir = TempDir::new("asm");
    let comp_a = asmdir.join("rail.sldprt");
    let comp_b = asmdir.join("screw.sldprt");
    // Everything this block opens is closed again at the end, and the document
    // that was active when it started is put back — the checks after it target
    // the active document.
    let was_active = b.call("swx_docs", json!({}))["active"]["title"].as_str().unwrap_or("").to_string();
    let mut opened: Vec<String> = Vec::new();
    for (path, no) in [(&comp_a, "R1"), (&comp_b, "F-10x3")] {
        let made = b.call("swx_run_script", json!({"script": [
            {"op": "new_part"},
            {"op": "sketch_rect", "widthMm": 44.45, "heightMm": 38.1},
            {"op": "extrude", "depthMm": 100},
            {"op": "set_prop", "name": "PartNo", "value": no},
            {"op": "save_as", "path": path.to_string_lossy()}
        ]}));
        if let Some(t) = made["created"]["created"]["title"].as_str() {
            opened.push(t.to_string());
        }
    }
    let asm = b.call("swx_new_document", json!({"type": "assembly"}));
    let asm_title = asm["created"]["title"].as_str().unwrap_or("Assem1").to_string();

    let r = b.call("swx_add_component", json!({"targetDocument": asm_title}));
    check!(
        b,
        "swx_add_component refuses a request with no component file",
        r["success"] == false && r["error"].as_str().unwrap_or("").contains("filePath"),
        s(&r)
    );
    let r = b.call("swx_add_component", json!({
        "targetDocument": asm_title,
        "components": [{"filePath": "RELATIVE.sldprt"}]
    }));
    check!(
        b,
        "swx_add_component refuses a relative component path",
        r["success"] == false && r["error"].as_str().unwrap_or("").contains("ABSOLUTE"),
        s(&r)
    );

    let r = b.call("swx_add_component", json!({
        "targetDocument": asm_title,
        "components": [
            {"filePath": comp_a.to_string_lossy(), "xMm": 0, "yMm": 0, "zMm": 0},
            {"filePath": comp_b.to_string_lossy(), "xMm": 100, "yMm": 0, "zMm": 25.4},
            {"filePath": comp_b.to_string_lossy(), "xMm": 200, "yMm": 0, "zMm": 25.4, "rotZDeg": 90},
            {"filePath": asmdir.join("missing.sldprt").to_string_lossy()}
        ]
    }));
    check!(b, "swx_add_component inserts a batch in one call", r["insertedCount"] == 3, s(&r));
    check!(b, "swx_add_component reports the COM call that worked", r["method"].is_string(), s(&r));
    check!(
        b,
        "swx_add_component reports the one that could not go in, and why",
        r["failedCount"] == 1
            && r["failed"][0]["error"].as_str().unwrap_or("").contains("not found"),
        s(&r)
    );
    check!(b, "swx_add_component echoes the position in millimetres", r["inserted"][1]["positionMm"][2] == 25.4, s(&r));
    check!(
        b,
        "swx_add_component orients a component that cannot go in axis-aligned",
        r["rotationsRequested"] == 1 && r["placedCount"] == 3 && r["inserted"][2]["rotationDeg"][2] == 90.0,
        s(&r)
    );
    check!(b, "swx_add_component reports the assembly's component count", r["componentCount"] == 3, s(&r));

    // THE POINT OF THE VERB: a BOM built from what was inserted.
    let r = b.call("swx_bom", json!({"targetDocument": asm_title}));
    check!(b, "swx_bom sees the inserted components", r["rowCount"] == 2, s(&r));
    let screw = r["rows"]
        .as_array()
        .and_then(|rows| rows.iter().find(|row| row["name"] == "screw"))
        .cloned()
        .unwrap_or(json!({}));
    check!(b, "swx_bom aggregates repeated instances into a quantity", screw["quantity"] == 2, s(&screw));
    check!(
        b,
        "swx_bom carries the components' custom properties",
        screw["properties"]["PartNo"]["value"] == "F-10x3",
        s(&screw)
    );

    let r = b.call("swx_add_component", json!({
        "path": "C:\\mock\\bracket.sldprt",
        "components": [{"filePath": comp_a.to_string_lossy()}]
    }));
    check!(
        b,
        "swx_add_component refuses a document the bridge did not create",
        r["success"] == false && r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    b.call("swx_close_doc", json!({"name": asm_title, "save": false}));
    for t in &opened {
        b.call("swx_close_doc", json!({"name": t, "save": false}));
    }
    let r = b.call("swx_activate_document", json!({"name": was_active.clone()}));
    check!(
        b,
        "the component block leaves the bench as it found it",
        r["activeDocument"]["title"] == json!(was_active.clone()),
        s(&r)
    );

    let r = b.call("swx_design_info", json!({}));
    check!(b, "design_info now sees the body", r["bodies"] == 1, s(&r));
    check!(b, "design_info reports the material that was set", r["material"]["name"] == "6061 Alloy", s(&r));

    // ── parameters ──────────────────────────────────────────────────────────
    let r = b.call("swx_get_parameters", json!({}));
    check!(
        b,
        "get_parameters finds the extrusion's named dimension",
        r["parameters"].as_array().unwrap().iter().any(|p| p["name"] == "D1@Boss-Extrude1"),
        s(&r)
    );
    check!(
        b,
        "get_parameters gives both SI and mm",
        r["parameters"].as_array().unwrap().iter().any(|p| p["unit"] == "m" && p["valueMm"].is_number()),
        s(&r)
    );

    let r = b.call("swx_set_parameter", json!({"name": "D1@Boss-Extrude1", "valueMm": 25}));
    check!(b, "set_parameter drives a dimension in mm", r["success"] == true && r["valueMm"] == 25.0, s(&r));
    check!(b, "set_parameter converts mm to SI metres", r["value"] == 0.025, s(&r));
    check!(b, "set_parameter shows what it changed FROM", r["before"] == 0.02, s(&r));

    let r = b.call("swx_set_parameter", json!({"name": "D1@Nope"}));
    check!(b, "set_parameter without a value is rejected", r["success"] == false, s(&r));
    let r = b.call("swx_set_parameter", json!({"name": "D1@Nope", "valueMm": 5}));
    check!(b, "set_parameter on an unknown dimension is rejected", r["success"] == false, s(&r));

    // ── save_as: the scratch document reaches disk ──────────────────────────
    let r = b.call("swx_save_as", json!({"outputPath": "relative.sldprt"}));
    check!(b, "save_as refuses a relative path", r["errorCode"] == "unsafe_path", s(&r));

    let r = b.call("swx_save_as", json!({"outputPath": part_path.to_string_lossy()}));
    check!(b, "save_as writes the file", r["success"] == true && part_path.is_file(), s(&r));
    check!(
        b,
        "save_as (not copy) retitles the open document",
        r["doc"]["title"].as_str().unwrap_or("").eq_ignore_ascii_case("bracket-built.sldprt"),
        s(&r)
    );
    check!(b, "save_as reports the byte count", r["bytes"].as_u64().unwrap_or(0) > 0, s(&r));

    // ── the per-format export aliases (fusion_export_* parity) ──────────────
    // The mock refuses exactly the formats a live SOLIDWORKS refuses for a PART
    // (swFileSaveError_e 256), so this loop tests both outcomes.
    for (verb, ext) in [
        ("swx_export_step", "step"), ("swx_export_iges", "igs"), ("swx_export_stl", "stl"),
        ("swx_export_3mf", "3mf"), ("swx_export_glb", "glb"), ("swx_export_sat", "sat"),
        ("swx_export_parasolid", "x_t"), ("swx_export_pdf", "pdf"),
    ] {
        let out = built.join(&format!("alias.{ext}"));
        let r = b.call(verb, json!({"outputPath": out.to_string_lossy()}));
        check!(b, &format!("{verb} writes {ext}"), r["success"] == true && out.is_file(), s(&r));
        check!(
            b,
            &format!("{verb} echoes the LIVE-VERIFIED format matrix"),
            r["formats"]["provenModelFormats"].is_array(),
            s(&r)
        );
        check!(
            b,
            &format!("{verb} did NOT rename the open document (Silent|Copy)"),
            r["documentRenamed"] == false,
            s(&r)
        );
        check!(b, &format!("{verb} reports a clean save code"), r["saveErrorCode"] == 0, s(&r));
    }
    // DXF and DWG are DRAWING formats: refused for a part, with the reason.
    for (verb, ext) in [("swx_export_dxf", "dxf"), ("swx_export_dwg", "dwg")] {
        let out = built.join(&format!("drawingonly.{ext}"));
        let r = b.call(verb, json!({"outputPath": out.to_string_lossy()}));
        check!(
            b,
            &format!("{verb} is refused for a PART, as SOLIDWORKS refuses it live"),
            r["success"] == false && r["error"].as_str().unwrap_or("").contains("256"),
            s(&r)
        );
    }

    // THE guard that shipped broken: it checked the `format` ARGUMENT, but
    // SaveAs3 keys off the DESTINATION EXTENSION — so an alias with a hard-coded
    // format could name a .wrl output and sail straight past it, into the call
    // that hung SOLIDWORKS for 110 seconds. Test the guard the way it BREAKS.
    let wrl = built.join("bypass.wrl");
    for (verb, args) in [
        ("swx_export_step", json!({"outputPath": wrl.to_string_lossy()})),
        ("swx_export_glb", json!({"outputPath": wrl.to_string_lossy()})),
        ("swx_export", json!({"format": "step", "outputPath": wrl.to_string_lossy()})),
        ("swx_export", json!({"format": "step", "out": wrl.to_string_lossy()})),
        ("swx_save_as", json!({"outputPath": wrl.to_string_lossy()})),
    ] {
        let r = b.call(verb, args.clone());
        check!(
            b,
            &format!("{verb} refuses a .wrl DESTINATION whatever the format argument says"),
            r["errorCode"] == "format_blocked",
            s(&r)
        );
    }
    check!(b, "and nothing was written for any of them", !wrl.exists(), wrl.display().to_string());
    // The DSL is the third road to SaveAs3, and it must meet the same rule.
    let r = b.call("swx_run_script", json!({"script": [{"op": "save_as", "path": wrl.to_string_lossy()}]}));
    check!(b, "the modelling DSL refuses a .wrl destination too", r["errorCode"] == "bad_script", s(&r));
    let r = b.call("swx_run_script", json!({"script": [{"op": "save_as", "path": "RELATIVE-BYPASS.sldprt"}]}));
    check!(b, "...and a relative DSL save_as, which used to write into the bridge cwd", r["errorCode"] == "bad_script", s(&r));
    check!(
        b,
        "the relative DSL save_as really wrote nothing",
        !std::path::Path::new("RELATIVE-BYPASS.sldprt").exists(),
        "RELATIVE-BYPASS.sldprt exists in the bridge cwd"
    );

    // ── import ──────────────────────────────────────────────────────────────
    let step_in = built.join("alias.step");
    let r = b.call("swx_import", json!({"filePath": step_in.to_string_lossy()}));
    check!(b, "import brings a neutral file in as a new document", r["success"] == true, s(&r));
    // An imported document reports its CONVERSION TEMP path — what the real
    // backend's GetPathName returns — and is never a saved user file. The mock
    // used to report "" here, which meant `is_import_temp` (the proof the whole
    // drain rests on) was never exercised against a realistic value.
    check!(
        b,
        "the imported document reports the conversion temp path a real one would",
        swx_bridge::comhost::host::is_import_temp(r["imported"]["path"].as_str().unwrap_or("")),
        s(&r)
    );
    // Import reports the net document count it added, and says so — one open
    // unsaved doc, like new_document (WORKSTREAM A: the leak was callers
    // importing without ever closing). See the import_lifecycle suite for the
    // enumeration cap and the drain verb in depth.
    check!(b, "import asserts exactly one new document", r["documentsOpened"] == 1 && r["netCountOk"] == true, s(&r));
    check!(b, "...and its hint says it stays open until closed", r["_hint"].as_str().unwrap_or("").contains("stays open"), s(&r));
    let temps = b.call("swx_close_import_temps", json!({"reason": "drain import temps left by this suite"}));
    check!(b, "swx_close_import_temps runs in the default posture with just a reason", temps["success"] == true, s(&temps));
    check!(b, "...and reports how many it closed and whether it finished", temps["closed"].is_u64() && temps["done"] == true, s(&temps));
    let temps_gate = b.call("swx_close_import_temps", json!({}));
    check!(b, "...and needs a reason (it closes documents on the user's desktop)", temps_gate["errorCode"] == "reason_required", s(&temps_gate));
    let r = b.call("swx_import", json!({}));
    check!(b, "import without a filePath is rejected", r["success"] == false, s(&r));

    // ...and an imported document is OURS on both sides, so the bridge can
    // clean it up. Live run 3 left an orphan because the host never registered
    // it: `cmd_import` has three success paths and only one of them did.
    // A DISTINCT stem: SOLIDWORKS titles an imported document `<stem>.SLDPRT`,
    // so re-importing a file already imported manufactures a title collision.
    let step_src = built.join("ownership-probe.step");
    b.call("swx_export_step", json!({"outputPath": step_src.to_string_lossy()}));
    let imported = b.call("swx_import", json!({"filePath": step_src.to_string_lossy()}));
    let it = imported["imported"]["title"].as_str().unwrap_or("").to_string();
    check!(b, "swx_import registered the document it created", imported["success"] == true, s(&imported));
    let r = b.call("swx_close_doc", json!({"name": it.clone(), "save": false}));
    check!(
        b,
        "the bridge can close a document it imported",
        r["success"] == true,
        s(&r)
    );

    // ── activate + the show family ──────────────────────────────────────────
    let r = b.call("swx_activate_document", json!({"name": "gearbox.sldasm"}));
    check!(b, "activate_document", r["success"] == true && r["activeDocument"]["type"] == "assembly", s(&r));
    let r = b.call("swx_activate_document", json!({}));
    check!(b, "activate_document without a name is rejected", r["success"] == false, s(&r));
    let r = b.call("swx_activate_document", json!({"name": "nothing-open.sldprt"}));
    check!(b, "activate_document on a closed document is rejected", r["success"] == false, s(&r));

    let r = b.call("swx_show_assembly", json!({}));
    check!(b, "show_assembly activates and fits", r["success"] == true && r["zoomedToFit"] == true, s(&r));
    check!(b, "show_assembly reports the view", r["view"] == "assembly", s(&r));
    let r = b.call("swx_show_part", json!({}));
    check!(b, "show_part refuses when the active document is an assembly", r["errorCode"] == "wrong_document_type", s(&r));
    let r = b.call("swx_show_drawing", json!({"path": "C:\\mock\\gearbox.sldasm"}));
    check!(b, "show_drawing refuses a .sldasm by extension, before opening it", r["errorCode"] == "wrong_document_type", s(&r));
    let r = b.call("swx_show_part", json!({"path": "C:\\mock\\newly-shown.sldprt"}));
    check!(b, "show_part opens a document it was handed and shows it", r["success"] == true && r["view"] == "part", s(&r));

    // ── windows & dialogs: ab is unreachable from the harness, so these must
    //    degrade honestly rather than throw ──────────────────────────────────
    let r = b.call("swx_window_info", json!({}));
    check!(b, "window_info degrades honestly when ab is unreachable", r["success"] == true && r["abError"].is_string(), s(&r));
    // NOT an empty array. "ab could not be asked" and "SOLIDWORKS has no
    // windows" are different facts, and an empty list reads as the second — in
    // the live run it did exactly that, and three failures looked like bridge
    // bugs when the bridge had simply been started by hand.
    check!(b, "...reporting the window list as UNKNOWN, not empty", r["windows"].is_null(), s(&r));
    check!(b, "...and saying ab is unavailable", r["abAvailable"] == false, s(&r));
    let st = b.call("swx_status", json!({}));
    check!(b, "swx_status says up front whether ab is reachable", st["abAvailable"] == false, s(&st));

    let r = b.call("swx_dismiss_blocking_dialogs", json!({}));
    check!(b, "dismiss_blocking_dialogs reports rather than acting", r["success"] == true, s(&r));
    let r = b.call("swx_dismiss_blocking_dialogs", json!({"close": true}));
    check!(b, "closing dialogs needs a reason", r["errorCode"] == "reason_required", s(&r));
    let r = b.call("swx_dismiss_blocking_dialogs", json!({"close": true, "reason": "an export sheet my own probe raised"}));
    check!(b, "closing dialogs needs confirmation too", r["errorCode"] == "confirm_required", s(&r));

    let r = b.call("swx_close_window", json!({}));
    check!(b, "close_window needs an hwnd", r["success"] == false, s(&r));
    let r = b.call("swx_close_window", json!({"hwnd": 4242}));
    check!(b, "close_window needs a reason", r["errorCode"] == "reason_required", s(&r));
    let r = b.call("swx_close_window", json!({"hwnd": 4242, "reason": "clearing my own dialog"}));
    check!(b, "close_window needs confirmation", r["errorCode"] == "confirm_required", s(&r));
    let r = b.call("swx_close_window", json!({"hwnd": 4242, "reason": "clearing my own dialog", "confirm": true}));
    check!(b, "close_window reports ab being unreachable instead of claiming success", r["success"] == false, s(&r));

    // ab is deliberately unreachable in this harness, so the recovery pane —
    // which is a WINDOW, not a COM fact — cannot be looked for. The honest
    // answer is UNKNOWN. This assertion used to require `false`, which is the
    // most misleading possible answer to "did the last session end badly?".
    let r = b.call("swx_check_recovery", json!({}));
    check!(
        b,
        "check_recovery says UNKNOWN when the desktop cannot be enumerated, never 'no'",
        r["recoveryPending"].is_null() && r["recoveryKnown"] == false && r["abError"].is_string(),
        s(&r)
    );

    let r = b.call("swx_set_driving_badge", json!({}));
    check!(b, "the driving badge defaults ON", r["showDrivingBadge"] == true, s(&r));
    let r = b.call("swx_set_driving_badge", json!({"enabled": false}));
    check!(b, "the driving badge can be turned off", r["showDrivingBadge"] == false, s(&r));
    let r = b.call("swx_set_driving_badge", json!({}));
    check!(b, "the driving badge setting is STICKY", r["showDrivingBadge"] == false, s(&r));

    // ── preferences: written, then READ BACK ────────────────────────────────
    let r = b.call("swx_get_preferences", json!({}));
    check!(b, "get_preferences lists what can be round-tripped", r["current"]["lengthUnitRaw"]["id"] == 53, s(&r));
    // A preference is a change to a DOCUMENT, so it faces the same rule. On the
    // user's document it is refused; on the bridge's own it goes through.
    let r = b.call("swx_set_preference", json!({"name": "lengthUnitRaw", "value": 3}));
    check!(
        b,
        "swx_set_preference refuses to touch a document the bridge did not create",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    let ours = part_path.to_string_lossy().to_string();
    let r = b.call("swx_set_preference", json!({"name": "lengthUnitRaw", "value": 3, "path": ours.clone()}));
    check!(b, "set_preference verifies by reading the value back", r["verified"] == true && r["value"] == 3, s(&r));
    let r = b.call("swx_get_preferences", json!({"path": ours.clone()}));
    check!(b, "the preference really changed", r["current"]["lengthUnitRaw"]["value"] == 3, s(&r));
    let r = b.call("swx_set_preference", json!({"name": "theme", "value": 1, "path": ours.clone()}));
    check!(b, "set_preference refuses a preference it cannot round-trip", r["success"] == false, s(&r));
    let r = b.call("swx_set_preference", json!({}));
    check!(b, "set_preference without a name is rejected", r["success"] == false, s(&r));

    // ── cloud: the honest refusal ───────────────────────────────────────────
    let r = b.call("swx_cloud_status", json!({}));
    check!(b, "cloud_status says plainly that there is no cloud route", r["supported"] == false, s(&r));
    check!(b, "cloud_status carries the probe that proves it", r["comApiExposesCloud"] == false, s(&r));
    check!(b, "cloud_status has a branchable code", r["errorCode"] == "cloud_not_available", s(&r));

    // ── measured timings ────────────────────────────────────────────────────
    let r = b.call("swx_verb_times", json!({}));
    check!(
        b,
        "verb_times reports what this machine measured",
        r["stages"]["swx_run_script"]["count"].as_u64().unwrap_or(0) >= 1,
        s(&r)
    );
    check!(b, "verb_times gives p50 and p90", r["stages"]["swx_run_script"]["p90"].is_number(), s(&r));

    // ── the reference diagnostic (0.10.6) ───────────────────────────────────
    let docs_before = b.call("swx_docs", json!({}))["docs"].as_array().map(|a| a.len());
    let r = b.call("swx_com_respawn", json!({"reason": "release every COM reference the bridge holds"}));
    check!(
        b,
        "swx_com_respawn replaces the bridge's own com host and leaves SOLIDWORKS's documents alone",
        r["respawned"] == true && r["solidworksTouched"] == false
            && b.call("swx_docs", json!({}))["docs"].as_array().map(|a| a.len()) == docs_before,
        s(&r)
    );

    // ── OWNERSHIP: the bridge must not change documents it did not create ───
    // The suite has a user-owned document open (gearbox.sldasm, opened by this
    // test, never created by the bridge). Every mutating verb must refuse it.
    let r = b.call("swx_activate_document", json!({"name": "gearbox.sldasm"}));
    check!(b, "activate the user's own document for the ownership tests", r["success"] == true, s(&r));

    let before = b.call("swx_design_info", json!({"path": "C:\\mock\\gearbox.sldasm"}));
    let bodies_before = before["bodies"].clone();
    check!(b, "the user's document has a known body count before we try", bodies_before.is_number(), s(&before));

    let r = b.call("swx_run_script", json!({"script": [
        {"op": "sketch_rect", "widthMm": 10, "heightMm": 10},
        {"op": "extrude", "depthMm": 5}
    ]}));
    check!(
        b,
        "run_script REFUSES to build geometry into a document the bridge did not create",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    check!(b, "...and names what it would have touched", r["targetDocument"] == "gearbox.sldasm", s(&r));
    check!(
        b,
        "...and lists the documents that ARE fair game",
        r["bridgeDocuments"].is_array(),
        s(&r)
    );
    let after = b.call("swx_design_info", json!({"path": "C:\\mock\\gearbox.sldasm"}));
    check!(
        b,
        "the user's document was not touched — no body appeared in it",
        after["bodies"] == bodies_before,
        format!("{} -> {}", bodies_before, after["bodies"])
    );

    let r = b.call("swx_run_script", json!({
        "script": [{"op": "rebuild"}],
        "allowUserWrites": true,
        "confirm": true,
        "reason": "the user asked me to rebuild their gearbox"
    }));
    check!(
        b,
        "swx_run_script: even a fully-argued request is refused while user writes are off",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );

    let r = b.call("swx_set_parameter", json!({"name": "D1@Boss-Extrude1", "valueMm": 9}));
    check!(b, "set_parameter refuses a document the bridge did not create", r["errorCode"] == "user_writes_disabled", s(&r));

    let r = b.call("swx_save_as", json!({"outputPath": built.join("stolen.sldasm").to_string_lossy()}));
    check!(
        b,
        "save_as refuses to RENAME a document the bridge did not create",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    let r = b.call("swx_save_as", json!({"outputPath": built.join("copy.sldasm").to_string_lossy(), "copy": true}));
    check!(b, "...but copy:true is not a rename, so it is allowed", r["success"] == true, s(&r));

    // Closing someone else's document at all — dirty or clean — is a change to
    // their session, and needs the process-level opt-in.
    let r = b.call("swx_close_doc", json!({}));
    check!(
        b,
        "close_doc refuses to close a document the bridge did not create",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "...and the user's document is still open",
        docs["docs"].as_array().unwrap().iter().any(|d| d["title"] == "gearbox.sldasm"),
        s(&docs)
    );

    // close_window must not become a general window killer. With ab
    // unreachable the refusal stands, and it now says WHICH refusal it is:
    // "the desktop could not be listed" is a different fact from "this window
    // is not SOLIDWORKS'", and a caller told the second goes looking for the
    // wrong problem.
    let r = b.call("swx_close_window", json!({"hwnd": 999999, "reason": "tidy up", "confirm": true}));
    check!(
        b,
        "close_window refuses an hwnd it cannot attribute to SOLIDWORKS",
        r["success"] == false
            && (r["errorCode"] == "window_not_attributed"
                || r["errorCode"] == "window_list_unavailable"),
        s(&r)
    );
    check!(
        b,
        "...and with ab unreachable it says so, rather than blaming the window",
        r["errorCode"] == "window_list_unavailable" && r["abError"].is_string(),
        s(&r)
    );

    // ── targetDocument must be REAL: authorize X, act on X ──────────────────
    // The defect this replaces: the gate resolved ownership from
    // `targetDocument`, but only run_script forwarded it — every other verb sent
    // `path` (usually null), so the com host fell back to ActiveDoc. With a user
    // part active, `swx_save_as {targetDocument:"Part1"}` renamed and relocated
    // the USER's document. The refusal even handed the caller the value to use.
    let r = b.call("swx_activate_document", json!({"name": "gearbox.sldasm"}));
    check!(b, "swx_activate_document puts the user's document in front", r["success"] == true, s(&r));

    let refusal = b.call("swx_save_as", json!({"outputPath": built.join("stolen2.sldasm").to_string_lossy()}));
    check!(b, "swx_save_as refuses the user's document", refusal["errorCode"] == "user_writes_disabled", s(&refusal));
    let offered = refusal["bridgeDocuments"].as_array().cloned().unwrap_or_default();
    check!(b, "the refusal offers the bridge's own documents", !offered.is_empty(), s(&refusal));
    check!(
        b,
        "...each identified by PATH, not by a title that may not be unique",
        offered.iter().any(|d| d.get("path").map(|p| p.is_string()).unwrap_or(false)),
        s(&refusal)
    );

    // Retry using the PATH the refusal handed over. It must act on THAT
    // document, and the user's must survive with its title AND path unchanged.
    let saved = offered
        .iter()
        .find(|d| d.get("path").map(|p| p.is_string()).unwrap_or(false))
        .cloned()
        .unwrap_or(Value::Null);
    let ours_path = saved["path"].as_str().unwrap_or("").to_string();
    let retry_out = built.join("retargeted.sldprt");
    let r = b.call("swx_save_as", json!({
        "outputPath": retry_out.to_string_lossy(),
        "path": ours_path.clone()
    }));
    check!(b, "swx_save_as retried by path succeeds", r["success"] == true, s(&r));
    check!(
        b,
        "...and it acted on THAT document, not the active one",
        r["doc"]["title"].as_str().unwrap_or("") != "gearbox.sldasm",
        s(&r)
    );
    // IDENTITY, not open-ness: same title AND same path.
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "the user's document survived with its title AND path identical",
        docs["docs"].as_array().unwrap().iter().any(|d| d["title"] == "gearbox.sldasm"
            && d["path"] == "C:\\mock\\gearbox.sldasm"),
        s(&docs)
    );

    // Naming a document two ways, with two different answers, is refused.
    let r = b.call("swx_save_as", json!({
        "outputPath": built.join("amb.sldprt").to_string_lossy(),
        "targetDocument": "gearbox.sldasm",
        "path": "C:\\mock\\newly-shown.sldprt"
    }));
    check!(b, "swx_save_as refuses an ambiguous target", r["errorCode"] == "ambiguous_target", s(&r));
    let r = b.call("swx_set_parameter", json!({"name": "D1@X", "valueMm": 1, "targetDocument": "NotOpen.sldprt"}));
    check!(b, "swx_set_parameter refuses a targetDocument that is not open", r["errorCode"] == "document_not_open", s(&r));

    // ── ownership is scoped to a SOLIDWORKS session, and pruned ─────────────
    let before = b.call("swx_reset_workspace", json!({"titles": ["nothing"]}));
    check!(b, "swx_reset_workspace reports what it believes it owns", before["trackedScratchDocuments"].is_array(), s(&before));

    // ── reset_workspace closes ONLY what the bridge made and never saved ────
    let r = b.call("swx_new_document", json!({"type": "assembly"}));
    let sweepable = r["created"]["title"].as_str().unwrap_or("").to_string();
    check!(
        b,
        "a second scratch document for the sweep, named the way SOLIDWORKS names one",
        sweepable.starts_with("Assem") && !sweepable.starts_with("Assembly"),
        sweepable.clone()
    );
    // The sweep list lives in MEMORY and holds only what this process created.
    let r = b.call("swx_reset_workspace", json!({"titles": ["nothing-by-this-name"]}));
    check!(b, "reset_workspace with an explicit titles[] closes nothing else", r["closed"] == json!([]), s(&r));
    let r = b.call("swx_reset_workspace", json!({}));
    check!(b, "reset_workspace closed the scratch document", r["closed"].as_array().unwrap().contains(&json!(sweepable)), s(&r));
    check!(
        b,
        "reset_workspace left the user's own documents alone",
        r["skipped"].as_array().unwrap().iter().any(|x| x["title"] == "gearbox.sldasm"
            && x["why"].as_str().unwrap_or("").contains("not created by this bridge")),
        s(&r)
    );
    check!(
        b,
        "a scratch document that HAS been saved is skipped too",
        r["skipped"].as_array().unwrap().iter().any(|x| x["why"].as_str().unwrap_or("").contains("has been saved")),
        s(&r)
    );
    check!(
        b,
        "our claim on a scratch document SURVIVED its save_as rename",
        r["trackedScratchDocuments"].as_array().unwrap().iter()
            .any(|t| t.as_str().unwrap_or("").eq_ignore_ascii_case("retargeted.sldprt")),
        s(&r)
    );
    check!(
        b,
        "the sweep list is reported, so a caller can see what the bridge thinks it owns",
        r["trackedScratchDocuments"].is_array(),
        s(&r)
    );

    // ── kill: gated twice, and never actually run here ──────────────────────
    // Make a BRIDGE-OWNED document dirty, so the unsaved-work refusal is a real
    // branch. (The bridge can no longer dirty the user's documents at all.)
    b.call("swx_new_document", json!({"type": "part"}));
    let d = b.call("swx_props_set", json!({"properties": {"Scratch": "1"}}));
    check!(b, "the kill fixture is dirty", d["doc"]["dirty"] == true, s(&d));
    let r = b.call("swx_kill", json!({}));
    check!(b, "kill needs a reason", r["errorCode"] == "reason_required", s(&r));
    let r = b.call("swx_kill", json!({"reason": "SOLIDWORKS is wedged on a modal nobody can answer"}));
    check!(b, "kill needs confirmation too", r["errorCode"] == "confirm_required", s(&r));
    // swx_kill ENDS THE USER'S SESSION through ab, so neither veto was ever in
    // its path and its own gates were both self-grantable. Choke point now.
    let r = b.call("swx_kill", json!({"reason": "wedged", "confirm": true}));
    check!(b, "swx_kill needs the process-level opt-in", r["errorCode"] == "user_writes_disabled", s(&r));

    // ── close_all_documents: confirm-gated, and it spares unsaved work ──────
    let r = b.call("swx_close_all_documents", json!({}));
    check!(b, "close_all_documents needs confirmation", r["errorCode"] == "confirm_required", s(&r));
    let r = b.call("swx_close_all_documents", json!({"confirm": true, "closeUnsaved": true}));
    check!(
        b,
        "swx_close_all_documents refuses to discard everything without a reason",
        r["errorCode"] == "reason_required",
        s(&r)
    );
    // Closing the user's SESSION is a destructive state change in its own right,
    // so it needs the process-level opt-in even with confirm and a reason.
    let r = b.call("swx_close_all_documents", json!({
        "confirm": true, "closeUnsaved": true, "reason": "clearing the bench"
    }));
    check!(
        b,
        "swx_close_all_documents needs the process-level opt-in to close the user's session",
        r["success"] == false,
        s(&r)
    );
    // With a reason: OUR scratch documents are discarded, the user's dirty ones
    // are not — one flag must not throw away everything they have open.
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "nothing was closed: the user's documents are all still open",
        docs["docs"].as_array().unwrap().len() >= 2,
        s(&docs)
    );
    check!(
        b,
        "swx_close_all_documents refused without the process-level opt-in",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );

    // Put the suite's own fixture back for the teardown section below.
    b.call("swx_open", json!({"path": "C:\\mock\\bracket.sldprt"}));

    // ── escape hatch, state, screenshot ─────────────────────────────────────
    let r = b.call("swx_com_eval", json!({"expr": "$sw.RevisionNumber()"}));
    check!(b, "com_eval is gated on reason", r["errorCode"] == "reason_required", s(&r));

    let r = b.call("swx_com_eval", json!({"expr": "$sw.RevisionNumber()", "reason": "test"}));
    check!(b, "com_eval with a reason runs", r["success"] == true, s(&r));
    // The mock now runs the SAME grammar the real backend uses, so this proves
    // the parser end to end: the chain is reflected back.
    check!(b, "com_eval reflects the parsed chain", r["chain"][0] == "RevisionNumber", s(&r));

    let r = b.call("swx_com_eval", json!({"reason": "test"}));
    check!(b, "com_eval without an expr is rejected", r["success"] == false, s(&r));

    // A garbage expression is now REJECTED over the wire (not cheerfully echoed),
    // because the mock parses it too — the grammar is genuinely exercised.
    let r = b.call("swx_com_eval", json!({"expr": "Remove-Item C:\\", "reason": "test"}));
    check!(b, "com_eval rejects a non-expression", r["success"] == false, s(&r));

    let r = b.call("swx_state", json!({}));
    check!(b, "state", r["success"] == true && !r["openDocs"].is_null(), s(&r));
    check!(b, "state etiquette", r["windowEtiquette"] == "background", s(&r));
    // ab is unreachable here, so the census is UNKNOWN — and `blockingDialogs`
    // must say so rather than hand back an empty array, which a caller reads as
    // "nothing is in the way" right before it drives a SOLIDWORKS that may be
    // sitting on a modal.
    check!(
        b,
        "state carries a dialog census",
        r["blockingDialogs"].is_array() || r["blockingDialogs"].is_null(),
        s(&r)
    );
    // 0.11.1: the census is NATIVE (the process's own windows), so ab being
    // unreachable no longer leaves it unknown; where the native census cannot be
    // read and ab is the fallback, an unreachable ab is still UNKNOWN.
    check!(
        b,
        "...native and known, or (ab fallback, ab unreachable) UNKNOWN — never an empty 'nothing in the way' it could not see",
        (r["dialogCensusSource"] == "native" && r["blockingDialogsKnown"] == true && r["blockingDialogs"].is_array())
            || (r["blockingDialogs"].is_null() && r["blockingDialogsKnown"] == false && r["blockingDialogsError"].is_string()),
        s(&r)
    );
    check!(b, "state carries this machine's measured timings", r["timings"].is_object(), s(&r));
    check!(b, "state names the active document", r["activeDocument"].is_string(), s(&r));
    let r = b.call("swx_state", json!({"screenshot": false}));
    check!(b, "state can skip the ab callbacks", r["screenshot"].is_null(), s(&r));

    // ab is not reachable from the test harness: the verb must report that
    // cleanly instead of throwing.
    let r = b.call("swx_screenshot", json!({}));
    check!(
        b,
        "screenshot reports ab being unreachable instead of blowing up",
        r["success"] == false && r["ab"]["error"].is_string(),
        s(&r)
    );

    // ── caller identity reaches the log ─────────────────────────────────────
    b.call_with_headers(
        "swx_status",
        json!({"caller": {"aiThread": "harness-thread", "containerName": "test"}}),
        &[("X-Adom-Caller-Thread".into(), "header-thread".into())],
    );
    check!(
        b,
        "the caller is logged, one line per verb",
        b.log().contains("caller=\"harness-thread\""),
        b.log()
    );

    // ── the safe-close family (Drew's standing authorization, 2026-09-11) ───
    let rec = b.call("swx_recover_list", json!({}));
    check!(b, "recover_list answers before anything has been preserved", rec["success"] == true, s(&rec));
    check!(b, "...with a recovery root", rec["recoveryRoot"].is_string(), s(&rec));
    // The user-presence guard's own reading (0.9.9): a simulated SOLIDWORKS is on
    // nobody's screen, and the reply says what it measured.
    // Unattended sign-in (0.9.13): with no launch waiting at a sign-in window,
    // it types nothing anywhere and says so.
    // Rendering (0.9.18): a small PNG of the current view, size read back.
    let rr = b.call("swx_render_image", json!({"width": 32, "height": 24, "reason": "coverage"}));
    check!(b, "render_image writes a PNG of the asked size", rr["success"] == true && rr["width"] == 32 && rr["height"] == 24, s(&rr));
    let si = b.call("swx_sign_in", json!({"reason": "coverage"}));
    check!(b, "sign_in with nothing waiting: sign_in_not_waiting", si["errorCode"] == "sign_in_not_waiting", s(&si));
    let pres = b.call("swx_user_presence", json!({}));
    check!(
        b,
        "user_presence answers, with its evidence",
        pres["success"] == true && pres["present"] == false && pres["evidence"]["basis"].is_string(),
        s(&pres)
    );

    // ── teardown verbs ──────────────────────────────────────────────────────
    // The bridge closes its OWN documents freely; the user's need the opt-in
    // (covered above), so the teardown closes one of ours.
    let mine = b.call("swx_new_document", json!({"type": "part"}));
    let mine_title = mine["created"]["title"].as_str().unwrap_or("").to_string();
    let r = b.call("swx_close_doc", json!({"name": mine_title}));
    check!(b, "close doc", r["success"] == true, s(&r));

    // Quitting with unsaved work would strand SOLIDWORKS on a save dialog that
    // nobody is there to answer, so it refuses until the caller says so.
    b.call("swx_new_document", json!({"type": "part"}));
    let d = b.call("swx_props_set", json!({"properties": {"Unsaved": "yes"}}));
    check!(b, "the exit fixture really is dirty", d["doc"]["dirty"] == true, s(&d));
    let r = b.call("swx_stop", json!({}));
    // v2 gates on the OPEN-document count FIRST, and that refusal is the
    // stronger one: v1 gated on UNSAVED, so five of Drew's CLEAN documents with
    // unsavedDocuments:0 would have sailed past the guard. `force` waives the
    // unsaved question and never this one.
    check!(
        b,
        "stop refuses while the user's documents are open",
        r["errorCode"] == "open_documents_present",
        s(&r)
    );
    check!(b, "...and says force does not waive it", r["_hint"].as_str().unwrap_or("").contains("force` does not"), s(&r));
    // Quitting ends the user's SOLIDWORKS session — on a Connected edition the
    // bridge cannot start it again — so it needs the process-level opt-in too.
    // Checked on an EMPTY session, because the open-document refusal above
    // would otherwise answer first and this consent gate would go unproven.
    let no_optin = quittable_machine("verb-stop-off", r#"{"a":"exited"}"#);
    let off = Bridge::start_with(&[
        ("SWX_LAUNCH_FAKE_DIR", &no_optin.path()),
        ("SWX_QUIT_SETTLE_MS", "80"),
    ]);
    off.call("swx_start", json!({}));
    let r = off.call("swx_stop", json!({"force": true}));
    check!(off, "stop needs the process-level opt-in", r["errorCode"] == "user_writes_disabled", s(&r));
    let optin = quittable_machine("verb-stop-on", r#"{"a":"exited"}"#);
    let on = Bridge::start_with(&[
        ("SWX_ALLOW_USER_WRITES", "1"),
        ("SWX_LAUNCH_FAKE_DIR", &optin.path()),
        ("SWX_QUIT_SETTLE_MS", "80"),
    ]);
    on.call("swx_start", json!({}));
    let r = on.call("swx_stop", json!({
        "force": true, "allowUserWrites": true, "confirm": true, "reason": "the user asked me to close SOLIDWORKS"
    }));
    check!(on, "stop with force", r["success"] == true && r["stopped"] == true, s(&r));
    check!(
        on,
        "stop VERIFIES the app is gone rather than trusting ExitApp's return",
        r["stillRunning"] == false,
        s(&r)
    );

    // THE SAFE CLOSE, on this same session — it is teardown, and it is the verb
    // Drew's standing authorization exists for: no opt-in, no confirmation, just
    // a reason, and every document written to disk before it closes.
    let swept = b.call(
        "swx_close_all_safely",
        json!({"reason": "the user asked me to close SOLIDWORKS"}),
    );
    check!(
        b,
        "close_all_safely preserves and closes in the DEFAULT posture",
        swept["success"] == true && swept["done"] == true,
        s(&swept)
    );
    check!(
        b,
        "...and every document it closed was on disk first",
        swept["recovered"]
            .as_array()
            .map(|a| a.iter().all(|d| d["preserved"] == true))
            .unwrap_or(false),
        s(&swept)
    );
    let empty = b.call("swx_docs", json!({}));
    check!(b, "...leaving the session empty", empty["count"] == 0, s(&empty));

    // uninstall removes ONLY the bridge's own exports subtree — never the cache
    // root ab owns (which, on a real machine, holds the running exe).
    let exports = std::path::Path::new(&b.scratch.path()).join("exports");
    check!(
        b,
        "the exports dir exists before uninstall (the bom csv wrote there)",
        exports.is_dir(),
        exports.display().to_string()
    );
    let recovery = std::path::Path::new(&b.scratch.path()).join("recovery");
    let rescues_before: Vec<std::path::PathBuf> = std::fs::read_dir(&recovery)
        .map(|d| d.flatten().map(|e| e.path()).collect())
        .unwrap_or_default();
    check!(
        b,
        "precondition: the sweep above left a recovery folder for uninstall to leave alone",
        !rescues_before.is_empty(),
        recovery.display().to_string()
    );
    let r = b.call("swx_uninstall", json!({"cascade": true}));
    check!(b, "uninstall", r["success"] == true, s(&r));
    check!(b, "uninstall echoes the cascade flag", r["cascade"] == true, s(&r));
    // THE RESCUES SURVIVE UNINSTALL. A recovery file can be the only copy of
    // work the user had not saved; ab calls this verb on app uninstall, ungated.
    check!(
        b,
        "uninstall PRESERVES every recovery folder, and says so",
        rescues_before.iter().all(|p| p.exists()) && r["recoveryPreserved"] == true,
        s(&r)
    );
    // LAST: it ends the session, so nothing may follow it that needs one.
    let down = b.call("swx_shutdown", json!({"reason": "the user asked me to close SOLIDWORKS"}));
    check!(
        b,
        "swx_shutdown closes what is open and quits — one verb, no opt-in, only a reason",
        down["success"] == true,
        s(&down)
    );
    check!(
        b,
        "uninstall removed the exports subtree",
        !exports.exists(),
        s(&r)
    );
    check!(
        b,
        "uninstall did NOT delete the cache root (ab owns it)",
        std::path::Path::new(&b.scratch.path()).exists(),
        b.scratch.path()
    );
    for name in ["timings.json", "settings.json"] {
        let f = std::path::Path::new(&b.scratch.path()).join(name);
        check!(
            b,
            &format!("uninstall removed the bridge's own {name}"),
            !f.exists(),
            f.display().to_string()
        );
    }
    // The AUDIT LOG survives on purpose. swx_uninstall takes no gate — ab calls
    // it on app uninstall — so deleting the ledger here would let a caller erase
    // the record of what it did by asking the bridge to tidy up.
    let ledger = std::path::Path::new(&b.scratch.path()).join("ledger.jsonl");
    check!(
        b,
        "uninstall PRESERVES swx_action_ledger's log",
        ledger.exists(),
        ledger.display().to_string()
    );
    let final_uninstall = b.call("swx_uninstall", json!({}));
    check!(b, "...and says so", final_uninstall["ledgerPreserved"] == true, s(&final_uninstall));
    let again = b.call("swx_uninstall", json!({}));
    check!(b, "uninstall is idempotent", again["success"] == true, s(&again));

    // ── the coverage gate ───────────────────────────────────────────────────
    // Measured from the calls this suite actually made. A verb added to
    // bridge.json (or to swx_describe) without a test turns this red.
    let covered = b.covered();
    let asserted = b.asserted();
    let manifest = manifest_verbs();
    let described: std::collections::BTreeSet<String> = described.into_iter().collect();

    let untested: Vec<&String> = manifest.difference(&covered).collect();
    check!(
        b,
        "every verb in bridge.json is exercised by this suite",
        untested.is_empty(),
        format!("untested verbs: {untested:?}")
    );

    // ...and CALLING a verb is not testing it. Every shipped verb must have at
    // least one assertion made against its response, or a verb could ship with a
    // one-line POST that proves nothing and still turn the gate green.
    let unasserted: Vec<&String> = manifest.difference(&asserted).collect();
    check!(
        b,
        "every verb in bridge.json is ASSERTED on, not merely called",
        unasserted.is_empty(),
        format!("called but never asserted: {unasserted:?}")
    );

    let undeclared: Vec<&String> = described.difference(&manifest).collect();
    check!(
        b,
        "swx_describe declares no verb missing from bridge.json",
        undeclared.is_empty(),
        format!("in describe but not bridge.json: {undeclared:?}")
    );

    let unimplemented: Vec<&String> = manifest.difference(&described).collect();
    check!(
        b,
        "bridge.json declares no verb missing from swx_describe",
        unimplemented.is_empty(),
        format!("in bridge.json but not describe: {unimplemented:?}")
    );

    // The bridge's log must be one line per verb, not a stream of chatter.
    let verb_lines = b.log().lines().filter(|l| l.starts_with("[swx] swx_")).count();
    check!(
        b,
        "exactly one log line per verb call — no per-item chatter",
        verb_lines == b.call_count(),
        format!("{verb_lines} log lines for {} calls", b.call_count())
    );
}

#[test]
fn a_handler_panic_becomes_json_and_the_worker_keeps_serving() {
    // SWX_TEST_PANIC makes the named verb panic (debug builds only). The HTTP
    // worker must catch it, answer success:false + _reportIssues, and stay up —
    // not drop the connection or die after WORKERS panics.
    let b = Bridge::start_with(&[("SWX_TEST_PANIC", "swx_progress")]);
    let r = b.call("swx_progress", json!({}));
    check!(b, "a panicking verb still answers success:false", r["success"] == false, r.to_string());
    check!(b, "the panic answer invites a bug report", r["_reportIssues"].is_string(), r.to_string());
    // Hit it several more times — if the worker had died, we'd eventually stall.
    for _ in 0..6 {
        let _ = b.call("swx_progress", json!({}));
    }
    // ...and a DIFFERENT verb still works, proving the process is healthy.
    let ok = b.call("swx_status", json!({}));
    check!(b, "the bridge still serves other verbs after a panic", ok["success"] == true, ok.to_string());
}

#[test]
fn oversized_and_malformed_bodies_are_rejected_cleanly() {
    let b = Bridge::start();
    // 400 with a hint, not a 500.
    let (code, body) = b.post_raw("{ broken");
    check!(b, "malformed body → 400", code == 400, format!("{code} {body}"));
    check!(b, "malformed 400 carries a hint", body.contains("_hint"), body.clone());
    check!(b, "malformed 400 invites a report", body.contains("_reportIssues"), body.clone());
    // Over the 8MB cap → 413.
    let huge = format!("{{\"command\":\"swx_status\",\"args\":{{\"x\":\"{}\"}}}}", "a".repeat(9 * 1024 * 1024));
    let (code, body) = b.post_raw(&huge);
    check!(b, "oversized body → 413", code == 413, format!("{code} {}", &body[..body.len().min(120)]));
}

#[test]
fn a_second_instance_refuses_the_port_instead_of_fighting_for_it() {
    let b = Bridge::start();
    let out = std::process::Command::new(common::BIN)
        .arg("--port")
        .arg(b.port.to_string())
        .env("SWX_MOCK", "1")
        .env("ADOM_BIND_HOST", "127.0.0.1")
        .output()
        .expect("run second instance");
    let text = String::from_utf8_lossy(&out.stdout).to_string();
    assert!(out.status.success(), "a duplicate instance must exit 0, got {:?}", out.status);
    assert!(text.contains("already in use"), "expected a single-instance notice, got: {text}");
    // ...and the original is still serving.
    let (code, health) = b.get("/status");
    assert_eq!(code, 200, "{health}");
}

#[test]
fn an_edition_that_cannot_be_launched_says_so_instead_of_trying() {
    // THE branch that matters on the machine this bridge runs on, and the one
    // that was previously unreachable from any test on any platform: swx_start
    // short-circuited in mock mode, and the real check needed a Windows box with
    // SOLIDWORKS installed. A guard nothing can execute is not a guard.
    //
    // SWX_TEST_NO_LAUNCH makes `may_launch` answer no, exactly as a Connected
    // (or unrecognised) install does. What must happen then is a branchable
    // refusal that tells the human what to do — NOT a COM launch, which on a
    // Connected edition puts a modal on the user's screen and leaves a dead
    // process behind.
    let b = Bridge::start_with(&[("SWX_TEST_NO_LAUNCH", "1")]);
    let r = b.call("swx_start", json!({}));
    check!(b, "start refuses when the edition cannot be launched", r["success"] == false, s(&r));
    check!(b, "...with a branchable code", r["errorCode"] == "host_app_launch_blocked", s(&r));
    let hint = r["_hint"].as_str().unwrap_or("");
    check!(b, "...naming the 3DEXPERIENCE Platform as the way in", hint.contains("3DEXPERIENCE Platform"), hint.to_string());
    check!(
        b,
        "...and telling the AI NOT to launch sldworks.exe itself",
        hint.contains("Do not try to launch sldworks.exe by hand"),
        hint.to_string()
    );
    // Nothing was started: the COM host still reports the app as down.
    let st = b.call("swx_status", json!({}));
    check!(b, "nothing was launched", st["com"]["running"] == false, s(&st));

    // ...and once SOLIDWORKS is up by other means, ATTACH still works — which is
    // the whole point: the bridge is fully functional on an edition it cannot
    // start, it just cannot start it.
    let b2 = Bridge::start();
    b2.call("swx_start", json!({}));
    let b3 = Bridge::start_with(&[("SWX_TEST_NO_LAUNCH", "1")]);
    let r = b3.call("swx_readiness", json!({}));
    check!(b3, "readiness still answers on a non-launchable edition", r["ready"] == true, s(&r));
}

#[test]
fn a_rename_during_export_is_reported_not_swallowed() {
    // Report-bug #2: v0.2 exported with swSaveAsOptions_Silent alone, which
    // RENAMES the open document — the user's bracket.sldprt silently became
    // bracket.step in memory. The fix is Silent|Copy, and this is the test that
    // the fix is actually LOAD-BEARING rather than decorative: with the mock
    // injected to rename anyway, the verb must notice and say so, instead of
    // reporting a clean export over a document that just lost its identity.
    let b = Bridge::start_with(&[("SWX_MOCK_RENAME_ON_EXPORT", "1")]);
    b.call("swx_start", json!({}));
    b.call("swx_open", json!({"path": "C:\\mock\\bracket.sldprt"}));
    let tmp = TempDir::new("rename");
    let out = tmp.join("bracket.step");
    let r = b.call("swx_export_step", json!({"outputPath": out.to_string_lossy()}));
    check!(b, "the export itself succeeded", r["success"] == true, s(&r));
    check!(
        b,
        "a document rename during export is REPORTED, never swallowed",
        r["documentRenamed"] == true,
        s(&r)
    );
    // ...and with the fix in place (no injection) it must be false, or the flag
    // would be meaningless.
    let clean = Bridge::start();
    clean.call("swx_start", json!({}));
    clean.call("swx_open", json!({"path": "C:\\mock\\bracket.sldprt"}));
    let r = clean.call("swx_export_step", json!({"outputPath": tmp.join("clean.step").to_string_lossy()}));
    check!(clean, "Silent|Copy leaves the document's identity alone", r["documentRenamed"] == false, s(&r));
    check!(clean, "...and the title is genuinely unchanged", r["doc"]["title"] == "bracket.sldprt", s(&r));
}

/// A fake-OS directory in which the quit ladder can actually MEASURE a quit:
/// the mock publishes its session pid there and `FakeOs` synthesises the
/// SOLIDWORKS process, so `swx_stop`'s "the pid and its creation time are gone"
/// test has something to observe. Without one the census is unavailable and the
/// ladder correctly refuses (`stop_preconditions_unknown`) — see tests/quit.rs.
fn quittable_machine(tag: &str, script: &str) -> TempDir {
    let d = TempDir::new(tag);
    std::fs::write(d.join("quit-script.json"), script).unwrap();
    d
}

#[test]
fn ownership_does_not_survive_a_solidworks_restart_or_a_close() {
    // Registry entries were keyed on TITLE alone and forgotten only by
    // close_doc/reset_workspace. SOLIDWORKS restarts its Part numbering every
    // session, so a remembered "Part1" would match a fresh "Part1" the USER
    // made — and the bridge would then build geometry into their document
    // ungated. It also never forgot a document closed in the SOLIDWORKS UI, by
    // a crash, or by CloseAllDocuments.
    // Started WITH the opt-in: this test has to stop and restart SOLIDWORKS to
    // create a second session, and quitting the user's session is gated.
    let machine = quittable_machine("own-quit", r#"{"a":"exited"}"#);
    let b = Bridge::start_with(&[
        ("SWX_ALLOW_USER_WRITES", "1"),
        ("SWX_LAUNCH_FAKE_DIR", &machine.path()),
        ("SWX_QUIT_SETTLE_MS", "80"),
    ]);
    b.call("swx_start", json!({}));
    let r = b.call("swx_new_document", json!({"type": "part"}));
    let title = r["created"]["title"].as_str().unwrap_or("").to_string();
    check!(b, "swx_new_document made a scratch part", title.starts_with("Part"), title.clone());

    // While it is ours, a mutating verb goes through without confirmation.
    let r = b.call("swx_run_script", json!({"script": [
        {"op": "sketch_rect", "widthMm": 10, "heightMm": 10},
        {"op": "extrude", "depthMm": 2}
    ]}));
    check!(b, "swx_run_script builds into the bridge's own document", r["success"] == true, s(&r));

    // Close everything the way SOLIDWORKS itself would — not through
    // swx_close_doc. Closing the user's session needs the process-level opt-in,
    // so this bridge is started with it to exercise the path.
    let r = b.call("swx_close_all_documents", json!({
        "confirm": true, "allowUserWrites": true, "reason": "clearing the bench for the test"
    }));
    check!(b, "swx_close_all_documents runs with the opt-in", r["success"] == true, s(&r));
    let r = b.call("swx_reset_workspace", json!({}));
    check!(
        b,
        "the registry no longer claims a document that is not open",
        r["trackedScratchDocuments"] == json!([]),
        s(&r)
    );

    // A document the bridge did not create is refused even when it is the only
    // thing open.
    b.call("swx_open", json!({"path": "C:\\users\\theirs.sldprt"}));
    let r = b.call("swx_run_script", json!({"script": [
        {"op": "sketch_rect", "widthMm": 10, "heightMm": 10},
        {"op": "extrude", "depthMm": 2}
    ]}));
    check!(
        b,
        "swx_run_script refuses a document the bridge did not create",
        r["errorCode"] == "not_bridge_document",
        s(&r)
    );

    // ── and NOTHING carries over a SOLIDWORKS restart ───────────────────────
    // This is the case that made title-only ownership dangerous: SOLIDWORKS
    // restarts its Part numbering every session, so a remembered "Part1" would
    // match a fresh "Part1" the USER made after the restart.
    let r = b.call("swx_new_document", json!({"type": "part"}));
    let again = r["created"]["title"].as_str().unwrap_or("").to_string();
    check!(b, "swx_new_document gives us a scratch document again", !again.is_empty(), again.clone());
    let r = b.call("swx_reset_workspace", json!({"titles": ["nothing"]}));
    check!(b, "which the bridge tracks", r["trackedScratchDocuments"].as_array().unwrap().contains(&json!(again)), s(&r));

    // v2 QUITS ONLY A SESSION WITH NO DOCUMENTS OPEN, and `force` does not waive
    // that (v1 gated on the UNSAVED count, which is how five of Drew's clean
    // documents could have been quit out from under him). So the sweep comes
    // first — which is also what a caller would have to do.
    b.call("swx_reset_workspace", json!({"force": true, "allowUserWrites": true, "confirm": true, "reason": "clearing before the restart"}));
    b.call("swx_close_all_documents", json!({
        "confirm": true, "allowUserWrites": true, "closeUnsaved": true,
        "reason": "the test needs an empty session before quitting"
    }));
    let stopped = b.call("swx_stop", json!({"force": true, "allowUserWrites": true, "confirm": true, "reason": "test needs a second session"}));
    check!(b, "with no documents open, the quit succeeds", stopped["stopped"] == true, s(&stopped));
    b.call("swx_start", json!({}));
    // `keepUnsaved:true` so the document really is untitled-only: the HAZARD this
    // test is about is SOLIDWORKS reusing `Part1` across sessions, and from 0.6.0
    // a bridge-created document is given a unique file at birth precisely so that
    // hazard cannot reach it. The hazard is still real for a document that opts
    // out, and the ownership scoping still has to hold for it.
    let r = b.call("swx_new_document", json!({"type": "part", "keepUnsaved": true}));
    let after_restart = r["created"]["title"].as_str().unwrap_or("").to_string();
    check!(
        b,
        "a new SOLIDWORKS session REUSES the title Part1, exactly as the real one does",
        after_restart == "Part1",
        format!("{after_restart} {}", s(&r))
    );
    let r = b.call("swx_reset_workspace", json!({"titles": ["nothing"]}));
    let tracked = r["trackedScratchDocuments"].as_array().cloned().unwrap_or_default();
    check!(
        b,
        "swx_reset_workspace tracks ONLY the new session's document, not the old one with the same title",
        tracked.len() == 1 && tracked[0] == json!("Part1"),
        s(&r)
    );
}

#[test]
fn two_open_documents_sharing_a_title_cannot_be_confused() {
    // THE round-3 hole, and the reason "ownership by title" was never sound.
    // `C:\users\thing.sldprt` and `C:\bridge\thing.sldprt` are both titled
    // `thing.sldprt`; having two such documents open is ordinary. Ownership was
    // (title, session) and GetOpenDocumentByName returns whichever it finds
    // first, so `swx_save_as {targetDocument:"thing.sldprt"}` passed the gate
    // against the BRIDGE's copy and renamed and relocated the USER's — with no
    // confirm and no reason. The refusal even handed the AI the title to retry
    // with.
    let b = Bridge::start();
    b.call("swx_start", json!({}));
    // Hermetic directories: the overwrite guard is real, so a leftover file from
    // a previous run would (correctly) refuse the setup.
    let theirs = TempDir::new("theirs");
    let ours = TempDir::new("ours");
    // NOTE the extension case: a non-copy save_as reports the path back with an
    // UPPERCASED extension, so the user's document has to be opened the same way
    // for the titles to genuinely collide — which is the situation under test.
    let their_path = theirs.join("thing.SLDPRT").to_string_lossy().to_string();
    let our_path = ours.join("thing.sldprt").to_string_lossy().to_string();

    // The user's document, with unsaved work in it.
    b.call("swx_open", json!({"path": their_path.clone()}));
    // NOTE: the bridge can no longer make their document dirty at all —
    // swx_props_set is gated now — which is itself the improvement. What this
    // test proves is that a colliding title cannot make a write land on it.
    // The bridge's own document, saved under the SAME title in another folder.
    b.call("swx_new_document", json!({"type": "part"}));
    let mine = b.call("swx_save_as", json!({"outputPath": our_path.clone()}));
    check!(b, "the bridge has its own same-titled document", mine["success"] == true, s(&mine));

    let docs = b.call("swx_docs", json!({}));
    let same_titled = docs["docs"]
        .as_array()
        .unwrap()
        .iter()
        .filter(|d| d["title"].as_str().unwrap_or("").eq_ignore_ascii_case("thing.sldprt"))
        .count();
    check!(b, "two open documents really do share the title", same_titled == 2, s(&docs));

    // (a) save_as by that title must REFUSE, not pick one.
    let r = b.call("swx_save_as", json!({
        "targetDocument": "thing.SLDPRT",
        "outputPath": ours.join("renamed.sldprt").to_string_lossy()
    }));
    check!(b, "swx_save_as refuses an ambiguous title", r["errorCode"] == "ambiguous_target", s(&r));
    check!(
        b,
        "...and lists the candidates with their paths, so the caller can disambiguate",
        r["candidates"].as_array().map(|c| c.len()) == Some(2),
        s(&r)
    );

    // The user's document must be IDENTICAL — same title AND same path. "Still
    // open" is not the assertion: in the bug it WAS still open, under a new name
    // at a new path inside the bridge's folder.
    let docs = b.call("swx_docs", json!({}));
    let user_doc = docs["docs"]
        .as_array()
        .unwrap()
        .iter()
        .find(|d| d["path"] == json!(their_path.clone()))
        .cloned();
    check!(b, "the user's document has its EXACT title and path", user_doc.is_some(), s(&docs));
    check!(
        b,
        "...and is unmoved: the path is exactly the one it was opened from",
        user_doc.as_ref().map(|d| d["path"] == json!(their_path.clone())).unwrap_or(false),
        s(&docs)
    );

    // (b) close_doc by that title must refuse too — it was the one destructive
    // verb that never resolved a target at all.
    let r = b.call("swx_close_doc", json!({"name": "thing.SLDPRT", "save": false}));
    check!(b, "swx_close_doc refuses an ambiguous title", r["errorCode"] == "ambiguous_target", s(&r));
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "...and closed nothing: BOTH documents are still open",
        docs["docs"].as_array().unwrap().iter().filter(|d| d["title"].as_str().unwrap_or("").eq_ignore_ascii_case("thing.sldprt")).count() == 2,
        s(&docs)
    );

    // Naming the user's copy unambiguously by PATH still protects their work.
    let r = b.call("swx_close_doc", json!({"path": their_path.clone(), "save": false}));
    check!(
        b,
        "swx_close_doc refuses to close a document the bridge did not create",
        r["success"] == false,
        s(&r)
    );

    // (c) the bridge's OWN copy, named by path, is fair game and closes cleanly.
    let r = b.call("swx_close_doc", json!({"path": our_path.clone(), "save": false}));
    check!(b, "the bridge's own same-titled document closes without ceremony", r["success"] == true, s(&r));
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "and the user's document is STILL exactly where it was",
        docs["docs"].as_array().unwrap().iter().any(|d| d["path"] == json!(their_path.clone())
            && d["title"].as_str().unwrap_or("").eq_ignore_ascii_case("thing.sldprt")),
        s(&docs)
    );
}

#[test]
fn writes_are_deny_by_default_and_the_opt_in_is_not_self_grantable() {
    // THE design change, after five rounds in which every Critical was the
    // bridge writing to something the user owns through a route whose guard had
    // been forgotten. Writing is now refused unless BOTH the document is ours
    // AND the destination is new; the exception needs a process-level opt-in an
    // AI cannot give itself.
    let off = Bridge::start();
    off.call("swx_start", json!({}));
    let st = off.call("swx_status", json!({}));
    check!(off, "swx_status reports the write posture", st["userWrites"] == "disabled", s(&st));
    let d = off.call("swx_describe", json!({}));
    check!(off, "swx_describe states the write policy", d["writePolicy"].as_str().unwrap_or("").contains("DENY BY DEFAULT"), s(&d));

    let tmp = TempDir::new("deny");
    off.call("swx_open", json!({"path": "C:\\users\\theirs.sldprt"}));

    // Every route that reaches the user's document is refused, by ONE code.
    for (verb, args) in [
        ("swx_save", json!({})),
        ("swx_close_doc", json!({"save": true})),
        ("swx_set_parameter", json!({"name": "D1@Boss-Extrude1", "valueMm": 5})),
        ("swx_set_preference", json!({"name": "lengthUnitRaw", "value": 1})),
        ("swx_run_script", json!({"script": [{"op": "rebuild"}]})),
        ("swx_save_as", json!({"outputPath": tmp.join("x.sldprt").to_string_lossy()})),
    ] {
        let r = off.call(verb, args);
        check!(
            off,
            &format!("{verb} is denied by default on the user's document"),
            r["errorCode"] == "user_writes_disabled",
            s(&r)
        );
        check!(off, &format!("{verb} names the opt-in it would need"), r["requires"]["env"] == "SWX_ALLOW_USER_WRITES=1", s(&r));
    }

    // ...and an existing destination is refused even for OUR OWN document —
    // ownership of the source says nothing about the file being clobbered.
    off.call("swx_new_document", json!({"type": "part"}));
    let occupied = tmp.join("already.step");
    std::fs::write(&occupied, b"the user's existing export").expect("fixture");
    for (verb, args) in [
        ("swx_export", json!({"format": "step", "outputPath": occupied.to_string_lossy()})),
        ("swx_save_as", json!({"outputPath": occupied.to_string_lossy()})),
        ("swx_run_script", json!({"script": [{"op": "save_as", "path": occupied.to_string_lossy()}]})),
    ] {
        let r = off.call(verb, args);
        check!(
            off,
            &format!("{verb} refuses to overwrite an existing file"),
            r["errorCode"] == "destination_exists",
            s(&r)
        );
    }
    check!(
        off,
        "and the existing file was NOT touched",
        std::fs::read(&occupied).unwrap() == b"the user's existing export",
        "bytes changed"
    );
    // A NEW destination needs no permission at all — the safe subset works.
    let fresh = tmp.join("fresh.step");
    let r = off.call("swx_export", json!({"format": "step", "outputPath": fresh.to_string_lossy()}));
    check!(off, "exporting to a NEW path needs no permission", r["success"] == true && fresh.is_file(), s(&r));

    // ── the enabled posture ─────────────────────────────────────────────────
    let on = Bridge::start_with(&[("SWX_ALLOW_USER_WRITES", "1")]);
    on.call("swx_start", json!({}));
    let st = on.call("swx_status", json!({}));
    check!(on, "the enabled posture is reported too", st["userWrites"] == "enabled", s(&st));
    on.call("swx_open", json!({"path": "C:\\users\\theirs.sldprt"}));

    // Even enabled, the call must ASK — the env is permission to ask, not a
    // blanket grant.
    let r = on.call("swx_save", json!({}));
    check!(on, "with the env on, a call that does not ask is still refused", r["errorCode"] == "not_bridge_document", s(&r));
    let r = on.call("swx_save", json!({"confirm": true, "reason": "x"}));
    check!(on, "...and confirm+reason without allowUserWrites is not asking", r["errorCode"] == "not_bridge_document", s(&r));

    let r = on.call("swx_save", json!({
        "allowUserWrites": true, "confirm": true,
        "reason": "the user asked me to save their part"
    }));
    check!(on, "all three, with the env on, goes through", r["success"] == true, s(&r));
    let led = on.call("swx_action_ledger", json!({"limit": 10}));
    check!(
        on,
        "and every granted exception is recorded with the caller's reason",
        led["actions"].as_array().unwrap().iter().any(|a| a["action"] == "user_write_authorized"
            && a["detail"]["reason"] == "the user asked me to save their part"),
        s(&led)
    );
}

#[test]
fn the_com_host_refuses_a_write_the_server_would_have_allowed() {
    // Rounds 3 and 5 both turned on the server-authorizes / host-acts split: a
    // server-side check is a CLAIM, and the host acted on it. The host now keeps
    // its own record of the documents it created and reads the opt-in from the
    // environment it inherited, so it can veto independently.
    //
    // Driven over the RAW stdio protocol, bypassing the server entirely — which
    // is precisely the attack the split allowed.
    use std::io::Write;
    // ISOLATED scratch: the com host PERSISTS its created-document record, so a
    // test sharing the developer's real scratch root inherits whatever ran
    // before it and passes or fails by accident.
    let scratch = TempDir::new("hostveto");
    let mut child = std::process::Command::new(common::BIN)
        .arg("--com-host")
        .env("SWX_MOCK", "1")
        .env("SWX_SCRATCH_DIR", scratch.path())
        .stdin(std::process::Stdio::piped())
        .stdout(std::process::Stdio::piped())
        .spawn()
        .expect("spawn com host");
    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = std::io::BufReader::new(child.stdout.take().unwrap());
    fn read(stdout: &mut std::io::BufReader<std::process::ChildStdout>) -> Value {
        loop {
            let mut line = String::new();
            std::io::BufRead::read_line(stdout, &mut line).expect("read");
            let v: Value = serde_json::from_str(line.trim()).unwrap_or(Value::Null);
            if v.get("event").is_none() && !v.is_null() {
                return v;
            }
        }
    }
    {
        // consume the `ready` event
        let mut line = String::new();
        std::io::BufRead::read_line(&mut stdout, &mut line).expect("ready");
    }
    writeln!(stdin, r#"{{"id":1,"cmd":"start","args":{{"launch":true}}}}"#).unwrap();
    let _ = read(&mut stdout);
    writeln!(stdin, r#"{{"id":2,"cmd":"open","args":{{"path":"C:\\users\\theirs.sldprt","launch":true}}}}"#).unwrap();
    let _ = read(&mut stdout);

    // The server would have refused this; here we forge the authorization the
    // server alone would have granted. The host must still say no, because the
    // document is not one IT created and the environment opt-in is absent.
    writeln!(
        stdin,
        r#"{{"id":3,"cmd":"save","args":{{"path":"C:\\users\\theirs.sldprt","allowUserWrites":true}}}}"#
    )
    .unwrap();
    let r = read(&mut stdout);
    assert_eq!(r["ok"], false, "the com host must veto independently: {r}");
    let err = r["error"].as_str().unwrap_or("");
    assert!(err.contains("com host refuses"), "{err}");
    assert!(
        r["detail"].as_str().unwrap_or("").contains("OWN check"),
        "the refusal must say it is the host's own decision: {r}"
    );

    // A document the HOST itself created is fine, with no forged flag at all.
    writeln!(stdin, r#"{{"id":4,"cmd":"new_document","args":{{"type":"part"}}}}"#).unwrap();
    let made = read(&mut stdout);
    assert_eq!(made["ok"], true, "{made}");
    let title = made["result"]["created"]["title"].as_str().unwrap().to_string();
    writeln!(stdin, r#"{{"id":5,"cmd":"save","args":{{"docName":"{title}"}}}}"#).unwrap();
    let r = read(&mut stdout);
    assert_eq!(r["ok"], true, "the host's own document saves without ceremony: {r}");

    writeln!(stdin, r#"{{"id":0,"cmd":"__exit__"}}"#).unwrap();
    let _ = child.wait();
}

#[test]
fn every_write_route_is_covered_by_the_choke_point() {
    // Round 6: `authorize` was wired into 7 verbs and three others wrote around
    // it. One test per route, so a route that loses its guard fails HERE rather
    // than in the next review.
    let b = Bridge::start();
    b.call("swx_start", json!({}));
    b.call("swx_open", json!({"path": "C:\\users\\gearbox.sldasm"}));
    let tmp = TempDir::new("routes");

    // C1: the BOM CSV is written by the SERVER with std::fs::write, so neither
    // the com host's veto nor safe_out stood between it and any file on disk.
    let victim = tmp.join("quarterly-report.csv");
    std::fs::write(&victim, b"THE USER'S QUARTERLY REPORT").expect("fixture");
    let r = b.call("swx_bom", json!({"format": "csv", "out": victim.to_string_lossy()}));
    check!(b, "swx_bom refuses to overwrite an existing file", r["errorCode"] == "destination_exists", s(&r));
    check!(
        b,
        "...and the user's file is byte-for-byte unchanged",
        std::fs::read(&victim).unwrap() == b"THE USER'S QUARTERLY REPORT",
        "the CSV overwrote it"
    );
    // A fresh destination is the normal case and needs no permission.
    let fresh = tmp.join("bom.csv");
    let r = b.call("swx_bom", json!({"format": "csv", "out": fresh.to_string_lossy()}));
    check!(b, "swx_bom writes to a new path", r["success"] == true && fresh.is_file(), s(&r));

    // C2: props_set leaves the document DIRTY, so the user's own Ctrl+S commits
    // bridge-authored data. "In memory until a gated save" ignored the persist
    // route that cannot be gated: the user.
    let r = b.call("swx_props_set", json!({"properties": {"Injected": "yes"}}));
    check!(b, "swx_props_set refuses to modify the user's document", r["errorCode"] == "user_writes_disabled", s(&r));
    let after = b.call("swx_document_info", json!({}));
    check!(b, "...and left it clean, so SOLIDWORKS will not prompt to save", after["dirty"] == false, s(&after));

    // C3: rebuild_check calls ForceRebuild3 — which this bridge's own com_eval
    // hazard list refuses as "rebuilds the user's model".
    let r = b.call("swx_rebuild_check", json!({}));
    check!(b, "swx_rebuild_check refuses to rebuild the user's document", r["errorCode"] == "user_writes_disabled", s(&r));

    // M4: the server asked "is the directory non-empty?" while the host asked
    // `exists()`, so a bridge-owned assembly into an existing EMPTY directory
    // was granted by one and refused by the other — fail-closed, but the verb
    // was dead for its most natural case and the two guards were answering
    // different questions.
    let empty_dir = tmp.join("already-there");
    std::fs::create_dir_all(&empty_dir).expect("fixture");
    b.call("swx_new_document", json!({"type": "assembly"}));
    let r = b.call("swx_pack_and_go", json!({"out": empty_dir.to_string_lossy()}));
    check!(
        b,
        "swx_pack_and_go: server and host agree that an EXISTING destination is refused",
        r["errorCode"] == "destination_exists",
        s(&r)
    );
    b.call("swx_close_doc", json!({"save": false}));

    // M1: pack_and_go must not leave a directory behind after refusing.
    let png = tmp.join("packandgo-refused");
    let r = b.call("swx_pack_and_go", json!({"out": png.to_string_lossy()}));
    check!(b, "swx_pack_and_go refuses the user's document", r["errorCode"] == "user_writes_disabled", s(&r));
    check!(b, "...and created no directory", !png.exists(), png.display().to_string());
}

#[test]
fn the_host_authorizes_every_mutating_command_not_a_remembered_list() {
    // H1: the host's veto covered 7 commands. A forged `save` was vetoed while a
    // forged `run_script` — the whole modelling DSL — sketched and extruded into
    // the user's open document. The wrapper is now on the DISPATCH LOOP and
    // keyed off a READ-ONLY list, so a command nobody classified is refused.
    use std::io::Write;
    let scratch = TempDir::new("hostdispatch");
    let mut child = std::process::Command::new(common::BIN)
        .arg("--com-host")
        .env("SWX_MOCK", "1")
        .env("SWX_SCRATCH_DIR", scratch.path())
        .env_remove("SWX_ALLOW_USER_WRITES")
        .stdin(std::process::Stdio::piped())
        .stdout(std::process::Stdio::piped())
        .spawn()
        .expect("spawn com host");
    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = std::io::BufReader::new(child.stdout.take().unwrap());
    fn read(stdout: &mut std::io::BufReader<std::process::ChildStdout>) -> Value {
        loop {
            let mut line = String::new();
            std::io::BufRead::read_line(stdout, &mut line).expect("read");
            let v: Value = serde_json::from_str(line.trim()).unwrap_or(Value::Null);
            if v.get("event").is_none() && !v.is_null() {
                return v;
            }
        }
    }
    {
        let mut line = String::new();
        std::io::BufRead::read_line(&mut stdout, &mut line).expect("ready");
    }
    writeln!(stdin, r#"{{"id":1,"cmd":"start","args":{{"launch":true}}}}"#).unwrap();
    let _ = read(&mut stdout);
    writeln!(stdin, r#"{{"id":2,"cmd":"open","args":{{"path":"C:\\users\\theirs.sldprt","launch":true}}}}"#).unwrap();
    let _ = read(&mut stdout);

    // THE forged request that used to work: a DSL script with no targetDocument,
    // which the host resolved to the user's ActiveDoc and ran.
    writeln!(
        stdin,
        r#"{{"id":3,"cmd":"run_script","args":{{"allowUserWrites":true,"script":[{{"op":"sketch_rect","widthMm":10,"heightMm":10}},{{"op":"extrude","depthMm":2}}]}}}}"#
    )
    .unwrap();
    let r = read(&mut stdout);
    assert_eq!(r["ok"], false, "a forged run_script must be vetoed by the host: {r}");

    // ...and the user's document is untouched.
    writeln!(stdin, r#"{{"id":4,"cmd":"inspect_bodies","args":{{"path":"C:\\users\\theirs.sldprt"}}}}"#).unwrap();
    let bodies = read(&mut stdout);
    assert_eq!(bodies["result"]["bodyCount"], 1, "no body was added: {bodies}");

    // Every other command that used to be missing from the veto.
    for (cmd, args) in [
        ("props_set", r#"{"allowUserWrites":true,"properties":{"x":"1"}}"#),
        ("rebuild_check", r#"{"allowUserWrites":true}"#),
        ("close_doc", r#"{"allowUserWrites":true,"save":false}"#),
        ("close_all_documents", r#"{"allowUserWrites":true}"#),
        ("stop", r#"{"allowUserWrites":true}"#),
    ] {
        writeln!(stdin, r#"{{"id":9,"cmd":"{cmd}","args":{args}}}"#).unwrap();
        let r = read(&mut stdout);
        assert_eq!(r["ok"], false, "forged {cmd} must be vetoed: {r}");
        assert!(
            r["error"].as_str().unwrap_or("").contains("com host refuses"),
            "{cmd}: the refusal must come from the HOST: {r}"
        );
    }

    // H2: `eval` can reach ANY COM member and had no host-side guard at all.
    writeln!(
        stdin,
        r#"{{"id":20,"cmd":"eval","args":{{"allowUserWrites":true,"expr":"$doc.SaveAs3(\"C:\\x.step\",0,1)"}}}}"#
    )
    .unwrap();
    let r = read(&mut stdout);
    assert_eq!(r["ok"], false, "the host must re-check the read allowlist: {r}");
    assert!(r["error"].as_str().unwrap_or("").contains("refuses to evaluate"), "{r}");
    // A read still goes through.
    writeln!(stdin, r#"{{"id":21,"cmd":"eval","args":{{"expr":"$sw.RevisionNumber()"}}}}"#).unwrap();
    let r = read(&mut stdout);
    assert_eq!(r["ok"], true, "reads are what the escape hatch is for: {r}");

    writeln!(stdin, r#"{{"id":0,"cmd":"__exit__"}}"#).unwrap();
    let _ = child.wait();
}

#[test]
fn the_ab_delegated_verbs_end_the_session_and_are_gated_like_the_com_ones() {
    // Round 7: the half of the bridge that never speaks to the com host. Two
    // verbs end the user's SOLIDWORKS session through ab, so NEITHER of the two
    // vetoes was ever in their path, and their own gates (confirm + reason) are
    // both things a caller writes for itself.
    let off = Bridge::start();
    off.call("swx_start", json!({}));

    // C1: force-kill was dispatchable in the DEFAULT posture.
    let r = off.call("swx_kill", json!({"reason": "wedged", "confirm": true, "force": true}));
    check!(off, "swx_kill is denied by default", r["errorCode"] == "user_writes_disabled", s(&r));
    let led = off.call("swx_action_ledger", json!({"limit": 20}));
    check!(
        off,
        "...and nothing was dispatched: no kill in the ledger",
        !led["actions"].as_array().unwrap().iter().any(|a| a["action"] == "solidworks_killed"),
        s(&led)
    );

    // With the opt-in ON, an unsaved BRIDGE document still stops it — and the
    // fail-closed reading of an UNANSWERABLE probe is unit-tested in
    // verbs3::kill_tests, which is where a mock cannot help.
    let on = Bridge::start_with(&[("SWX_ALLOW_USER_WRITES", "1")]);
    on.call("swx_start", json!({}));
    on.call("swx_new_document", json!({"type": "part"}));
    on.call("swx_props_set", json!({"properties": {"x": "1"}}));
    let r = on.call("swx_kill", json!({
        "reason": "wedged", "confirm": true, "allowUserWrites": true
    }));
    check!(
        on,
        "swx_kill still refuses while documents have unsaved changes",
        r["errorCode"] == "unsaved_documents",
        s(&r)
    );

    // C2: the application FRAME is not a dialog.
    let st = off.call("swx_status", json!({}));
    check!(off, "the bridge is in the default posture for this check", st["userWrites"] == "disabled", s(&st));
    // swx_window_info marks frames, and the mock's mainHwnd is 4242.
    let r = off.call("swx_close_window", json!({
        "hwnd": 4242, "reason": "tidying up", "confirm": true
    }));
    // Pinned to the FRAME code specifically. Accepting `window_not_attributed`
    // as an alternative meant this assertion passed for the wrong reason (ab is
    // unreachable in this bridge) and pinned nothing.
    check!(
        off,
        "swx_close_window refuses the SOLIDWORKS application frame, by frame",
        r["errorCode"] == "window_is_application_frame",
        s(&r)
    );
    check!(
        off,
        "...and never reports success on it",
        r["success"] == false,
        s(&r)
    );
}

#[test]
fn the_ab_delegated_half_is_gated_and_dispatches_nothing_when_refused() {
    // The half of the bridge that never speaks to the com host. Until now these
    // verbs only ever ran their "ab is unreachable" branch in tests, so a guard
    // on this side could be deleted with every test still green — which is how
    // swx_kill force-killing SOLIDWORKS in the default posture survived six
    // reviews. The stub makes the ab side real: it reports windows WITH pids, so
    // attribution actually succeeds, and it records what was dispatched.
    let ab = common::AbStub::start(json!([]));
    let b = Bridge::start_with(&[("ADOM_DIRECT_API_URL", &ab.url)]);
    b.call("swx_start", json!({}));
    b.call("swx_open", json!({"path": "C:\\users\\gearbox.sldasm"}));
    // Attribution matches on OWNER PID, so the stub's windows have to carry the
    // pid SOLIDWORKS is actually reporting — which is only knowable now.
    let state = b.call("swx_get_app_state", json!({}));
    let sw_pid = state["processId"].as_i64().expect("the mock reports a process id");
    let main = state["mainHwnd"].as_i64().expect("and a main window handle");
    ab.set_windows(json!([
        {"hwnd": main, "title": "SOLIDWORKS Design Professional for Makers 2026",
         "className": "Afx:0000000140000000", "pid": sw_pid, "rect": {}},
        {"hwnd": 858186, "title": "Export", "className": "#32770", "pid": sw_pid, "rect": {}},
        {"hwnd": 9001, "title": "Save changes to gearbox?", "className": "#32770", "pid": sw_pid, "rect": {}},
        {"hwnd": 9002, "title": "System Options", "className": "#32770", "pid": sw_pid, "rect": {}}
    ]));

    // The mock's mainHwnd is 4242 and the stub reports that pid, so windows are
    // genuinely attributable here — the condition under which the guard matters.
    let wi = b.call("swx_window_info", json!({}));
    let frame = wi["windows"].as_array().unwrap().iter().find(|w| w["hwnd"] == main).cloned();
    check!(b, "the stub's windows are attributable", frame.is_some(), s(&wi));
    let frame = frame.unwrap();
    check!(b, "the main window is ownerConfirmed", frame["ownerConfirmed"] == true, s(&frame));
    check!(b, "...and is marked as a FRAME", frame["isFrame"] == true, s(&frame));
    check!(b, "...and therefore NOT closable", frame["closable"] == false, s(&frame));

    // C2: closing the frame quits SOLIDWORKS. `ownerConfirmed` is true exactly
    // when a window is most provably ours, so the attribution guard PASSED on
    // the one window it must never pass on.
    let r = b.call("swx_close_window", json!({"hwnd": main, "reason": "tidying", "confirm": true}));
    check!(b, "swx_close_window refuses the application frame", r["errorCode"] == "window_is_application_frame", s(&r));

    // A SECOND SOLIDWORKS frame — a separate document window — is not the one
    // COM told us about, so it takes the attribution path rather than the
    // main-hwnd shortcut. It is still a frame, and closing it still quits.
    ab.set_windows(json!([
        {"hwnd": main, "title": "SOLIDWORKS", "className": "Afx:0000000140000000", "pid": sw_pid, "rect": {}},
        {"hwnd": 5555, "title": "SOLIDWORKS Premium 2026 - [bracket.sldprt]",
         "className": "Afx:0000000140000001", "pid": sw_pid, "rect": {}},
        {"hwnd": 858186, "title": "Export", "className": "#32770", "pid": sw_pid, "rect": {}},
        {"hwnd": 9001, "title": "Save changes to gearbox?", "className": "#32770", "pid": sw_pid, "rect": {}},
        {"hwnd": 9002, "title": "System Options", "className": "#32770", "pid": sw_pid, "rect": {}}
    ]));
    let r = b.call("swx_close_window", json!({"hwnd": 5555, "reason": "tidying", "confirm": true}));
    check!(
        b,
        "swx_close_window refuses a SECOND SOLIDWORKS frame too, not just the main hwnd",
        r["errorCode"] == "window_is_application_frame",
        s(&r)
    );

    // C1: force-kill, with both of its old gates satisfied.
    let r = b.call("swx_kill", json!({"reason": "self-granted", "confirm": true, "force": true}));
    check!(b, "swx_kill is refused in the default posture", r["errorCode"] == "user_writes_disabled", s(&r));

    // H1: with attribution working, a dialog the bridge did NOT raise becomes
    // closable unless the opt-in is present. `Export` is ours; `System Options`
    // and `Save changes?` are the user's.
    let r = b.call("swx_dismiss_blocking_dialogs", json!({
        "close": true, "confirm": true, "reason": "tidying up"
    }));
    let refused: Vec<String> = r["refused"]
        .as_array()
        .unwrap()
        .iter()
        .map(|x| x["title"].as_str().unwrap_or("").to_string())
        .collect();
    check!(
        b,
        "a 'settings' dialog the user may be answering is NOT closed without the opt-in",
        refused.iter().any(|t| t == "System Options"),
        s(&r)
    );
    check!(
        b,
        "and neither is the bridge's OWN export sheet — closing any modal can take SOLIDWORKS down",
        refused.iter().any(|t| t == "Export"),
        s(&r)
    );
    check!(
        b,
        "a Save-changes dialog is never closed at all",
        refused.iter().any(|t| t.starts_with("Save changes")),
        s(&r)
    );

    // THE assertion that matters: nothing destructive was DISPATCHED. A refusal
    // that returns an error while still sending the request is not a refusal.
    check!(
        b,
        "NOTHING destructive reached ab",
        ab.destructive_calls().is_empty(),
        format!("{:?}", ab.destructive_calls())
    );
    check!(b, "...though ab was genuinely reachable", !ab.calls_to("desktop_list_windows").is_empty(), "no window calls");

    // With the opt-in, the bridge's OWN export sheet is closable — the narrow
    // case this verb exists for.
    // The export sheet's WORDS are read before it is closed (0.9.7, F6: one
    // classifier with judge_window), so the scenario supplies them.
    let words = TempDir::new("dismiss-words");
    std::fs::write(words.join("windows.json"), "[]").unwrap();
    std::fs::write(
        words.join("dialog-open.json"),
        json!({"hwnd": 858186, "text": ["Export options"], "buttons": ["OK", "Cancel"]}).to_string(),
    )
    .unwrap();
    let on = Bridge::start_with(&[
        ("ADOM_DIRECT_API_URL", &ab.url),
        ("SWX_ALLOW_USER_WRITES", "1"),
        ("SWX_LAUNCH_FAKE_DIR", &words.path()),
    ]);
    on.call("swx_start", json!({}));
    let on_state = on.call("swx_get_app_state", json!({}));
    let on_pid = on_state["processId"].as_i64().unwrap_or(sw_pid);
    ab.set_windows(json!([
        {"hwnd": on_state["mainHwnd"].as_i64().unwrap_or(main), "title": "SOLIDWORKS",
         "className": "Afx:0000000140000000", "pid": on_pid, "rect": {}},
        {"hwnd": 858186, "title": "Export", "className": "#32770", "pid": on_pid, "rect": {}},
        {"hwnd": 9001, "title": "Save changes to gearbox?", "className": "#32770", "pid": on_pid, "rect": {}}
    ]));
    let r = on.call("swx_dismiss_blocking_dialogs", json!({
        "close": true, "confirm": true, "allowUserWrites": true,
        "reason": "clearing the export sheet my own SaveAs3 raised"
    }));
    let closed: Vec<String> = r["closed"]
        .as_array()
        .unwrap()
        .iter()
        .map(|x| x["title"].as_str().unwrap_or("").to_string())
        .collect();
    check!(on, "the bridge's own export sheet closes with the opt-in", closed.iter().any(|t| t == "Export"), s(&r));
    check!(
        on,
        "...and the user's Save-changes dialog STILL is not touched",
        !closed.iter().any(|t| t.starts_with("Save changes")),
        s(&r)
    );
}

/// ONE CLASSIFIER (0.9.7, adversary pass 44 F6): swx_dismiss_blocking_dialogs
/// reads a window's WORDS with the classifier judge_window uses before it
/// closes anything. A window titled "Warning" (kind `message`, answerable by
/// title) whose body is a save question is NOT closed under the opt-in; a
/// window whose words cannot be read is not closed either.
#[test]
fn a_save_question_under_a_warning_title_is_never_dismissed() {
    let ab = common::AbStub::start(json!([]));
    let words = TempDir::new("dismiss-warning-words");
    std::fs::write(words.join("windows.json"), "[]").unwrap();
    std::fs::write(
        words.join("dialog-open.json"),
        json!({"hwnd": 858187, "text": ["Do you want to save changes to Part1.SLDPRT?"],
               "buttons": ["Save", "Don't Save", "Cancel"]}).to_string(),
    )
    .unwrap();
    let on = Bridge::start_with(&[
        ("ADOM_DIRECT_API_URL", &ab.url),
        ("SWX_ALLOW_USER_WRITES", "1"),
        ("SWX_LAUNCH_FAKE_DIR", &words.path()),
    ]);
    on.call("swx_start", json!({}));
    let st = on.call("swx_get_app_state", json!({}));
    let pid = st["processId"].as_i64().unwrap();
    ab.set_windows(json!([
        {"hwnd": st["mainHwnd"].as_i64().unwrap(), "title": "SOLIDWORKS", "className": "Afx:0001", "pid": pid, "rect": {}},
        {"hwnd": 858187, "title": "Warning", "className": "#32770", "pid": pid, "rect": {}},
        {"hwnd": 858188, "title": "Rebuild Errors", "className": "#32770", "pid": pid, "rect": {}}
    ]));
    let r = on.call("swx_dismiss_blocking_dialogs", json!({
        "close": true, "confirm": true, "allowUserWrites": true, "reason": "tidying"
    }));
    check!(on, "nothing was closed", r["closed"].as_array().map(|c| c.is_empty()).unwrap_or(false), s(&r));
    let refused = r["refused"].as_array().cloned().unwrap_or_default();
    check!(
        on,
        "the 'Warning' window is refused BY ITS TEXT as a save question",
        refused.iter().any(|x| x["hwnd"] == 858187 && x["kind"] == "save_changes"
            && x["why"].as_str().unwrap_or("").contains("by its text")),
        s(&r)
    );
    check!(
        on,
        "a window whose words cannot be read is refused, not closed",
        refused.iter().any(|x| x["hwnd"] == 858188 && x["why"].as_str().unwrap_or("").contains("could not be read")),
        s(&r)
    );
    check!(on, "NOTHING destructive reached ab", ab.destructive_calls().is_empty(), format!("{:?}", ab.destructive_calls()));
}

#[test]
fn a_host_record_from_another_solidworks_session_is_not_evidence() {
    // M1: the persisted record carried no session id and was cleared only on a
    // clean `stop`. After a crash, a kill, or the user quitting SOLIDWORKS, it
    // survived — and their next `Part1` matched it. The server's record is
    // session-scoped so the write was still refused end to end, but a second
    // veto that can be wrong is not a second veto.
    let b = Bridge::start();
    let store = std::path::Path::new(&b.scratch.path()).join("com-host-created.json");
    std::fs::create_dir_all(&b.scratch.path()).ok();
    std::fs::write(
        &store,
        json!({"session": 111111, "documents": [{"title": "Part1", "path": null}]}).to_string(),
    )
    .expect("plant a stale record");

    b.call("swx_start", json!({}));
    // The USER's Part1 — same title, different SOLIDWORKS session.
    b.call("swx_open", json!({"path": "C:\\users\\Part1.sldprt"}));
    let r = b.call("swx_props_set", json!({"targetDocument": "Part1.sldprt", "properties": {"x": "1"}}));
    check!(
        b,
        "a record from another SOLIDWORKS session confers no ownership",
        r["success"] == false,
        s(&r)
    );
}

#[test]
fn closing_a_window_is_gated_the_same_way_its_sibling_is() {
    // ROUND 8's Critical. `swx_close_window` had neither the `neverAutoAnswer`
    // refusal nor the write opt-in, while `swx_dismiss_blocking_dialogs` — the
    // sibling operating on the SAME window list — had both. And
    // `swx_window_info` advertised the dialog as `closable:true`, the same
    // discoverability shape as round 7's `mainHwnd`.
    let ab = common::AbStub::start(json!([]));
    let b = Bridge::start_with(&[("ADOM_DIRECT_API_URL", &ab.url)]);
    b.call("swx_start", json!({}));
    let state = b.call("swx_get_app_state", json!({}));
    let sw_pid = state["processId"].as_i64().unwrap();
    let main = state["mainHwnd"].as_i64().unwrap();
    ab.set_windows(json!([
        {"hwnd": main, "title": "SOLIDWORKS", "className": "Afx:0001", "pid": sw_pid, "rect": {}},
        {"hwnd": 9001, "title": "Save changes to gearbox?", "className": "#32770", "pid": sw_pid, "rect": {}},
        {"hwnd": 9002, "title": "SOLIDWORKS Document Recovery", "className": "#32770", "pid": sw_pid, "rect": {}},
        {"hwnd": 9003, "title": "Export", "className": "#32770", "pid": sw_pid, "rect": {}},
        // C1b: ab reported this one with NO className at all.
        {"hwnd": 9004, "title": "bracket.SLDPRT", "pid": sw_pid, "rect": {}},
        // M2(iii): a dialog ab reports with NO pid — unattributable. It stays in
        // the census (a bare #32770 is a candidate) but must never be closed.
        {"hwnd": 9005, "title": "Export", "className": "#32770", "rect": {}}
    ]));

    // C1: the dialog that asks about the user's unsaved work. Closing it answers
    // it — and by this bridge's own live evidence can take SOLIDWORKS down with
    // every unsaved document in it.
    let r = b.call("swx_close_window", json!({"hwnd": 9001, "reason": "tidying", "confirm": true}));
    check!(
        b,
        "swx_close_window refuses a Save-changes dialog outright",
        r["errorCode"] == "dialog_belongs_to_the_user",
        s(&r)
    );
    let r = b.call("swx_close_window", json!({"hwnd": 9002, "reason": "tidying", "confirm": true}));
    check!(b, "...and Document Recovery", r["errorCode"] == "dialog_belongs_to_the_user", s(&r));

    // Even a dialog the bridge itself raised needs the opt-in, exactly as the
    // sibling verb requires.
    let r = b.call("swx_close_window", json!({"hwnd": 9003, "reason": "my own export sheet", "confirm": true}));
    check!(
        b,
        "swx_close_window needs the process-level opt-in even for the bridge's own dialog",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );

    // C1b: an unknown window class must count as a FRAME, not as a dialog. The
    // old `!class.is_empty() &&` made an unreadable class mean "closable".
    let r = b.call("swx_close_window", json!({"hwnd": 9004, "reason": "tidying", "confirm": true}));
    check!(
        b,
        "a window with NO className is treated as a frame, not as a dialog",
        r["errorCode"] == "window_is_application_frame",
        s(&r)
    );

    // ...and swx_window_info must not advertise any of them as closable.
    let wi = b.call("swx_window_info", json!({}));
    let closable: Vec<i64> = wi["windows"]
        .as_array()
        .unwrap()
        .iter()
        .filter(|w| w["closable"] == true)
        .map(|w| w["hwnd"].as_i64().unwrap_or(0))
        .collect();
    check!(
        b,
        "swx_window_info marks the user's dialogs and the no-class window NOT closable",
        !closable.contains(&9001) && !closable.contains(&9002) && !closable.contains(&9004),
        format!("closable: {closable:?}")
    );

    // M2(ii): SOLIDWORKS' main window, reported with the DIALOG class. Only the
    // main-hwnd shortcut in `is_frame_window` catches this one — the class test
    // would wave it through as a dialog.
    ab.set_windows(json!([
        {"hwnd": main, "title": "SOLIDWORKS", "className": "#32770", "pid": sw_pid, "rect": {}}
    ]));
    let wi = b.call("swx_window_info", json!({}));
    check!(
        b,
        "the main window is a FRAME even when ab reports it with the dialog class",
        wi["windows"][0]["isFrame"] == true && wi["windows"][0]["closable"] == false,
        s(&wi)
    );

    check!(
        b,
        "NOTHING was dispatched to ab for any of it",
        ab.destructive_calls().is_empty(),
        format!("{:?}", ab.destructive_calls())
    );

    // M2(iii): under the OPT-IN, an UNATTRIBUTABLE dialog must still be refused.
    // Every stub window previously carried the SOLIDWORKS pid, so this branch
    // was unreachable and a stranger's dialog closing would have gone unnoticed.
    let ab2 = common::AbStub::start(json!([]));
    let on = Bridge::start_with(&[("ADOM_DIRECT_API_URL", &ab2.url), ("SWX_ALLOW_USER_WRITES", "1")]);
    on.call("swx_start", json!({}));
    let st2 = on.call("swx_get_app_state", json!({}));
    ab2.set_windows(json!([
        {"hwnd": st2["mainHwnd"].as_i64().unwrap(), "title": "SOLIDWORKS", "className": "Afx:0001",
         "pid": st2["processId"].as_i64().unwrap(), "rect": {}},
        // A #32770 with SOMEBODY ELSE'S pid — Word's Save dialog, say.
        {"hwnd": 7777, "title": "Export", "className": "#32770", "pid": 999_999, "rect": {}},
        // ...and one ab reports with NO pid at all: a candidate, never a fact.
        // This is the row that reaches the `ownerConfirmed` guard, which every
        // previous stub made unreachable by giving every window the SW pid.
        {"hwnd": 7778, "title": "Export", "className": "#32770", "rect": {}}
    ]));
    let r = on.call("swx_dismiss_blocking_dialogs", json!({
        "close": true, "confirm": true, "allowUserWrites": true, "reason": "tidying"
    }));
    check!(
        on,
        "even WITH the opt-in, a dialog owned by another process is not closed",
        r["closed"].as_array().map(|c| c.is_empty()).unwrap_or(false),
        s(&r)
    );
    check!(
        on,
        "...and an UNATTRIBUTABLE dialog is refused on that basis, not silently dropped",
        r["refused"].as_array().unwrap().iter().any(|x| x["hwnd"] == 7778
            && x["why"].as_str().unwrap_or("").contains("cannot prove")),
        s(&r)
    );
    check!(
        on,
        "...and nothing was dispatched for it",
        ab2.destructive_calls().is_empty(),
        format!("{:?}", ab2.destructive_calls())
    );
}

#[test]
fn a_write_lock_on_the_users_file_is_a_write() {
    // H1: round 7 changed swx_open's DEFAULT to read-only and left the harmful
    // mode caller-settable, on the com host's safe list where authorize_command
    // never runs. readOnly:false takes a WRITE LOCK on the user's file and
    // converts-and-dirties an older-version document in memory, so SOLIDWORKS
    // offers to save it on close.
    let b = Bridge::start();
    b.call("swx_start", json!({}));

    // M2(iv): the DEFAULT itself had zero tests.
    let r = b.call("swx_open", json!({"path": "C:\\users\\gearbox.sldasm"}));
    check!(b, "swx_open succeeds on the user's document", r["success"] == true, s(&r));
    check!(b, "...and is READ-ONLY by default", r["readOnly"] == true, s(&r));

    let r = b.call("swx_open", json!({"path": "C:\\users\\other.sldprt", "readOnly": false}));
    check!(
        b,
        "swx_open {readOnly:false} on the user's document is refused",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );

    // The bridge's OWN document opens for writing without ceremony.
    let tmp = TempDir::new("openrw");
    let mine = tmp.join("mine.sldprt");
    b.call("swx_new_document", json!({"type": "part"}));
    let saved = b.call("swx_save_as", json!({"outputPath": mine.to_string_lossy()}));
    check!(b, "the bridge saved its own document", saved["success"] == true, s(&saved));
    let r = b.call("swx_open", json!({"path": mine.to_string_lossy(), "readOnly": false}));
    check!(b, "...and opens it for writing freely while it is ours", r["success"] == true, s(&r));
    check!(b, "...reporting readOnly:false", r["readOnly"] == false, s(&r));

    // Once CLOSED it is no longer tracked, by either veto, and reopening it for
    // writing needs the opt-in again. Ownership means "a document this session
    // created and still holds", not "a file this bridge once wrote" — the
    // narrower reading is the one that cannot drift into someone else's file.
    b.call("swx_close_doc", json!({"path": mine.to_string_lossy()}));
    let r = b.call("swx_open", json!({"path": mine.to_string_lossy(), "readOnly": false}));
    check!(
        b,
        "a CLOSED document is no longer ours to reopen for writing",
        r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    let r = b.call("swx_open", json!({"path": mine.to_string_lossy()}));
    check!(b, "...though read-only always works", r["success"] == true, s(&r));
}

#[test]
fn the_screenshot_verb_captures_solidworks_and_nothing_else() {
    // M1: `titleContains` was forwarded straight to ab, so a verb catalogued as
    // "screenshot the SOLIDWORKS window" would capture any window on the
    // desktop that matched. Not a write — but it is the user's data, it was
    // ungated, and it had no test.
    let ab = common::AbStub::start(json!([]));
    let b = Bridge::start_with(&[("ADOM_DIRECT_API_URL", &ab.url)]);
    b.call("swx_start", json!({}));
    let state = b.call("swx_get_app_state", json!({}));
    let sw_pid = state["processId"].as_i64().unwrap();
    let main = state["mainHwnd"].as_i64().unwrap();
    ab.set_windows(json!([
        {"hwnd": main, "title": "SOLIDWORKS", "className": "Afx:0001", "pid": sw_pid, "rect": {}},
        {"hwnd": 3131, "title": "1Password", "className": "Chrome_WidgetWin_1", "pid": 999_999, "rect": {}}
    ]));

    let r = b.call("swx_screenshot", json!({"titleContains": "1Password"}));
    check!(b, "swx_screenshot ignores a free-text title", r["hwnd"] == main, s(&r));
    let r = b.call("swx_screenshot", json!({"hwnd": 3131}));
    check!(
        b,
        "swx_screenshot refuses an hwnd it cannot attribute to SOLIDWORKS",
        r["errorCode"] == "window_not_attributed",
        s(&r)
    );
    let shots = ab.calls_to("desktop_screenshot_window");
    check!(
        b,
        "every capture ab was asked for was BY HANDLE, and only SOLIDWORKS' own",
        shots.iter().all(|c| c["args"]["hwnd"] == main && c["args"].get("titleContains").is_none()),
        format!("{shots:?}")
    );
}

#[test]
fn a_document_that_has_never_been_saved_is_addressable_everywhere() {
    // THE LIVE BUG. `swx_new_document` produced a `Part2` that `swx_docs`
    // listed and every other verb reported as "document not open" — including
    // with no target at all, because the server always sends the resolved
    // identity now. The whole create → model → export flow was dead for new
    // documents, and 89 mock tests passed because the mock resolved titles from
    // its own map instead of the way SOLIDWORKS does.
    //
    // Root cause: a pathless document's `path` is EMPTY, and
    // `GetOpenDocumentByName` — which wants a full path — cannot find one by
    // title. Round 4 made path the identity; that was right, and it
    // over-corrected. For a document with no path the TITLE is the identity,
    // which is exactly what my own round-3 rebuttal argued.
    let b = Bridge::start();
    b.call("swx_start", json!({}));
    // A document the USER has open, to make sure the fix does not resolve by
    // title so loosely that it starts matching theirs.
    b.call("swx_open", json!({"path": "C:\\users\\gearbox.sldasm"}));

    // `keepUnsaved:true`, because 0.6.0 gives every new document a file of its
    // own at birth — precisely so this situation stops arising. The PATHLESS case
    // is still reachable (and this is how), and everything it proves still has to
    // hold for it: a document whose only name is its title must be addressable by
    // that title, everywhere.
    let made = b.call("swx_new_document", json!({"type": "part", "keepUnsaved": true}));
    let title = made["created"]["title"].as_str().unwrap_or("").to_string();
    check!(b, "swx_new_document created a part", made["success"] == true, s(&made));
    check!(b, "...with NO path, which is the whole difficulty", made["created"]["path"] == "", s(&made));

    // swx_docs lists it — the verb that always worked.
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "swx_docs lists the unsaved document",
        docs["docs"].as_array().unwrap().iter().any(|d| d["title"] == json!(title.clone())),
        s(&docs)
    );

    // ...and now so does everything else. These are the four calls that failed
    // live, in the order they failed.
    let r = b.call("swx_design_info", json!({"targetDocument": title.clone()}));
    check!(b, "swx_design_info resolves it BY TITLE", r["success"] == true, s(&r));
    let r = b.call("swx_design_info", json!({}));
    check!(b, "swx_design_info resolves it as the ACTIVE document", r["success"] == true, s(&r));
    check!(b, "...and it really is the one we made", r["doc"]["title"] == json!(title.clone()), s(&r));

    // The create → model → export flow that never got to run live.
    let r = b.call("swx_run_script", json!({"script": [
        {"op": "sketch_rect", "plane": "Front Plane", "widthMm": 50, "heightMm": 30},
        {"op": "extrude", "depthMm": 20}
    ], "targetDocument": title.clone()}));
    check!(b, "swx_run_script builds into a pathless document", r["success"] == true, s(&r));
    let r = b.call("swx_inspect_bodies", json!({"targetDocument": title.clone()}));
    check!(b, "swx_inspect_bodies reads it back", r["bodyCount"] == 1, s(&r));
    let tmp = TempDir::new("pathless");
    let out = tmp.join("from-scratch.step");
    let r = b.call("swx_export_step", json!({"outputPath": out.to_string_lossy(), "targetDocument": title.clone()}));
    check!(b, "swx_export_step exports it", r["success"] == true && out.is_file(), s(&r));

    // reset_workspace swept it, and close_doc can close it by name.
    let r = b.call("swx_reset_workspace", json!({}));
    check!(
        b,
        "swx_reset_workspace closes the pathless document it created",
        r["closed"].as_array().unwrap().contains(&json!(title.clone())),
        s(&r)
    );
    check!(
        b,
        "...and still skips the user's document",
        r["skipped"].as_array().unwrap().iter().any(|x| x["title"] == "gearbox.sldasm"),
        s(&r)
    );

    // close_doc by name, on a second one.
    let made = b.call("swx_new_document", json!({"type": "part"}));
    let t2 = made["created"]["title"].as_str().unwrap_or("").to_string();
    let r = b.call("swx_close_doc", json!({"name": t2.clone(), "save": false}));
    check!(b, "swx_close_doc closes a pathless document by name", r["success"] == true, s(&r));
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "...and it is gone",
        !docs["docs"].as_array().unwrap().iter().any(|d| d["title"] == json!(t2)),
        s(&docs)
    );

    // An EMPTY path must mean "no path", not "match any document that has no
    // path" — with two unsaved documents open, the latter silently picks one.
    let a = b.call("swx_new_document", json!({"type": "part"}));
    let ta = a["created"]["title"].as_str().unwrap_or("").to_string();
    let c = b.call("swx_new_document", json!({"type": "part"}));
    let tc = c["created"]["title"].as_str().unwrap_or("").to_string();
    check!(b, "two unsaved documents are open", ta != tc && !ta.is_empty(), format!("{ta} {tc}"));
    let r = b.call("swx_design_info", json!({"targetDocument": tc.clone(), "path": ""}));
    check!(
        b,
        "an empty path is ignored and the TITLE decides which document",
        r["doc"]["title"] == json!(tc.clone()),
        s(&r)
    );
    b.call("swx_close_doc", json!({"name": ta, "save": false}));
    b.call("swx_close_doc", json!({"name": tc, "save": false}));

    // A name nothing answers to must still be a BRANCHABLE refusal, not prose.
    let r = b.call("swx_design_info", json!({"targetDocument": "NoSuchDocument"}));
    check!(b, "a missing document is refused with a stable code", r["errorCode"] == "document_not_open", s(&r));
}

#[test]
fn the_bridge_can_clean_up_a_scratch_document_it_has_saved() {
    // THE ACCEPTANCE TEST for live run 2's headline bug. The suite created a
    // part, modelled it, saved it — and the bridge then refused to close it:
    // "would close 'smoke.SLDPRT', which this bridge did NOT create". It had
    // created it. The moment save_as gave the document a path, the ownership
    // record (holding the path we ASKED for, `smoke.sldprt`) stopped matching
    // the path SOLIDWORKS REPORTS (`smoke.SLDPRT`), and the bridge disowned its
    // own scratch document — so it could neither touch nor clean it up. That
    // cascaded into four of the nine failures and left an orphan on the machine.
    //
    // Ownership follows the DOCUMENT, not the string that used to name it.
    let b = Bridge::start();
    b.call("swx_start", json!({}));
    let tmp = TempDir::new("acceptance");
    let out = tmp.join("smoke.sldprt"); // lowercase, as a caller writes it

    let made = b.call("swx_new_document", json!({"type": "part"}));
    let title = made["created"]["title"].as_str().unwrap_or("").to_string();
    b.call("swx_run_script", json!({"script": [
        {"op": "sketch_rect", "plane": "Front Plane", "widthMm": 50, "heightMm": 30},
        {"op": "extrude", "depthMm": 20}
    ], "targetDocument": title.clone()}));

    let saved = b.call("swx_save_as", json!({"outputPath": out.to_string_lossy(), "targetDocument": title.clone()}));
    check!(b, "the bridge saved its own scratch document", saved["success"] == true, s(&saved));
    let reported = saved["doc"]["path"].as_str().unwrap_or("").to_string();
    check!(
        b,
        "SOLIDWORKS reports the path with its own casing, not ours",
        !reported.is_empty() && reported != out.to_string_lossy(),
        format!("asked {} got {reported}", out.to_string_lossy())
    );

    // STILL OURS — by the reported path, by the requested path, and by title.
    let now = saved["doc"]["title"].as_str().unwrap_or("").to_string();
    let sweep = b.call("swx_reset_workspace", json!({"titles": ["nothing"]}));
    check!(
        b,
        "our claim followed the document through the save",
        sweep["trackedScratchDocuments"].as_array().unwrap().iter()
            .any(|t| t.as_str().unwrap_or("").eq_ignore_ascii_case(&now)),
        s(&sweep)
    );

    // Every route the live run tried, now working.
    let r = b.call("swx_set_preference", json!({"name": "lengthUnitRaw", "value": 1, "path": reported.clone()}));
    check!(b, "swx_set_preference works on the saved scratch document", r["success"] == true, s(&r));
    let r = b.call("swx_run_script", json!({"script": [{"op": "rebuild"}], "targetDocument": now.clone()}));
    check!(b, "swx_run_script works on it", r["success"] == true, s(&r));

    // THE acceptance: close it by the path the CALLER wrote, casing and all.
    let r = b.call("swx_close_doc", json!({"path": out.to_string_lossy(), "save": false}));
    check!(
        b,
        "swx_close_doc closes the bridge's own saved scratch document",
        r["success"] == true,
        s(&r)
    );
    let docs = b.call("swx_docs", json!({}));
    check!(b, "...and nothing is left open", docs["docs"].as_array().unwrap().is_empty(), s(&docs));
}

#[test]
fn closing_by_path_is_unambiguous_even_when_titles_collide() {
    // Live run 2's second bug: `swx_import` of the file the suite had just saved
    // produced a SECOND document with the same title, so close-by-title
    // correctly refused — but the bridge had manufactured the ambiguity itself.
    // A PATH identifies exactly one document, so the path branch must resolve
    // before the title-ambiguity check can fire.
    let b = Bridge::start();
    b.call("swx_start", json!({}));
    let tmp = TempDir::new("collide");
    let out = tmp.join("smoke.sldprt");

    let made = b.call("swx_new_document", json!({"type": "part"}));
    let title = made["created"]["title"].as_str().unwrap_or("").to_string();
    let saved = b.call("swx_save_as", json!({"outputPath": out.to_string_lossy(), "targetDocument": title}));
    let saved_title = saved["doc"]["title"].as_str().unwrap_or("").to_string();
    let saved_path = saved["doc"]["path"].as_str().unwrap_or("").to_string();

    // Import the very file we just saved: a second document, same title.
    let imported = b.call("swx_import", json!({"filePath": out.to_string_lossy()}));
    check!(b, "the import opened a document", imported["success"] == true, s(&imported));
    let docs = b.call("swx_docs", json!({}));
    let same_title = docs["docs"]
        .as_array()
        .unwrap()
        .iter()
        .filter(|d| d["title"].as_str().unwrap_or("").eq_ignore_ascii_case(&saved_title))
        .count();
    check!(b, "two open documents now share a title", same_title == 2, s(&docs));

    // By TITLE: correctly refused.
    let r = b.call("swx_close_doc", json!({"name": saved_title.clone(), "save": false}));
    check!(b, "closing by the shared title is refused", r["errorCode"] == "ambiguous_target", s(&r));

    // By PATH: unambiguous, and it closes the RIGHT one — the saved document,
    // not the imported copy that has no path.
    let r = b.call("swx_close_doc", json!({"path": saved_path.clone(), "save": false}));
    check!(b, "closing by path succeeds despite the collision", r["success"] == true, s(&r));
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "...and the document that went is the SAVED one",
        !docs["docs"].as_array().unwrap().iter().any(|d| d["path"] == json!(saved_path)),
        s(&docs)
    );
}

#[test]
fn what_the_human_authorizes_in_full_the_bridge_actually_does() {
    // THE ACCEPTANCE TEST for live run 3's aftermath. Drew authorized closing
    // ALL the leftover documents from three live runs, including his own blank
    // Part1. The bridge was restarted with SWX_ALLOW_USER_WRITES=1 and every
    // call carried allowUserWrites + confirm + reason. It closed 3 of 5.
    //
    //   swx_close_doc            -> "the com host refuses to close_doc: this
    //                               document was not created by this bridge"
    //   swx_close_all_documents  -> closed the clean ones, skipped the dirty
    //                               foreign ones unconditionally
    //
    // The server AUTHORIZED the close and then told the host nothing: only the
    // `save:true` branch built a Grant, so `close_doc {save:false}` went to the
    // host with no evidence of the permission, and the host — holding its own
    // independent veto, correctly — refused. Two vetoes are a safety property
    // only while BOTH can be opened by the person who owns the machine.
    let on = Bridge::start_with(&[("SWX_ALLOW_USER_WRITES", "1")]);
    on.call("swx_start", json!({}));
    let tmp = TempDir::new("theirs");

    // Two documents that are emphatically NOT ours: files on disk that existed
    // before the bridge did.
    let a = tmp.join("their-part.sldprt");
    let bfile = tmp.join("their-other.sldprt");
    std::fs::write(&a, b"theirs").unwrap();
    std::fs::write(&bfile, b"theirs too").unwrap();
    on.call("swx_open", json!({"path": a.to_string_lossy()}));
    on.call("swx_open", json!({"path": bfile.to_string_lossy()}));

    // DEFAULT posture first, on a second bridge: the refusal must still be the
    // refusal. A fix that opens the hatch must not leave it open.
    {
        let off = Bridge::start_with(&[("SWX_TEST_NO_LAUNCH", "0")]);
        off.call("swx_start", json!({}));
        let theirs = tmp.join("untouchable.sldprt");
        std::fs::write(&theirs, b"theirs").unwrap();
        off.call("swx_open", json!({"path": theirs.to_string_lossy()}));
        let r = off.call("swx_close_doc", json!({
            "name": "untouchable.sldprt", "save": false,
            "confirm": true, "allowUserWrites": true, "reason": "trying it on"
        }));
        check!(
            off,
            "without the PROCESS-level opt-in the close is still refused",
            r["success"] == false && r["errorCode"] == "user_writes_disabled",
            s(&r)
        );
        let docs = off.call("swx_docs", json!({}));
        check!(
            off,
            "...and the document is still open",
            docs["docs"].as_array().unwrap().len() == 1,
            s(&docs)
        );
    }

    // Opted in, in full: it closes. This is the exact call that failed live.
    let r = on.call("swx_close_doc", json!({
        "name": "their-part.sldprt", "save": false,
        "confirm": true, "allowUserWrites": true,
        "reason": "Drew asked me to close the leftovers from the live runs"
    }));
    check!(
        on,
        "the full opt-in closes a document the bridge did not create",
        r["success"] == true,
        s(&r)
    );
    // And the grant REACHED the host: the host's veto is the thing that fired
    // live, so a pass here that came from the server alone would prove nothing.
    check!(
        on,
        "...and the host was told, so its own veto did not fire",
        r["error"].as_str().map(|e| !e.contains("com host refuses")).unwrap_or(true),
        s(&r)
    );

    // The ledger records the exception for the human, with their reason.
    let led = on.call("swx_action_ledger", json!({}));
    check!(
        on,
        "the granted exception is in the human's ledger with the reason given",
        s(&led).contains("Drew asked me to close the leftovers"),
        s(&led)
    );

    // Now the bulk verb, on a dirty foreign document — the other live failure.
    let dirtied = on.call("swx_props_set", json!({
        "path": bfile.to_string_lossy(), "properties": {"Revision": "B"},
        "confirm": true, "allowUserWrites": true, "reason": "make it dirty for the test"
    }));
    check!(on, "the foreign document was modified in memory", dirtied["success"] == true, s(&dirtied));
    let docs = on.call("swx_docs", json!({}));
    check!(
        on,
        "the foreign document is dirty and still open",
        docs["docs"][0]["dirty"] == true,
        s(&docs)
    );
    let r = on.call("swx_close_all_documents", json!({
        "confirm": true, "closeUnsaved": true,
        "allowUserWrites": true,
        "reason": "Drew authorized closing every leftover, unsaved ones included"
    }));
    check!(
        on,
        "closeUnsaved with the full opt-in closes the user's dirty document too",
        r["success"] == true && r["discarded"].as_array().unwrap().len() == 1,
        s(&r)
    );
    let docs = on.call("swx_docs", json!({}));
    check!(
        on,
        "SOLIDWORKS is left with nothing open — 5 of 5, not 3 of 5",
        docs["docs"].as_array().unwrap().is_empty(),
        s(&docs)
    );
    check!(
        on,
        "discarding the user's unsaved work is recorded for them",
        s(&on.call("swx_action_ledger", json!({}))).contains("user_document_changes_discarded"),
        s(&r)
    );
}

#[test]
fn close_all_documents_accounts_for_every_document_it_leaves_open() {
    // Live run 3's follow-up: `closeUnsaved:true` left two documents behind and
    // the response explained neither. `skipped` was empty (the foreign dirty
    // pair never entered the loop, because a document whose dirtiness
    // SOLIDWORKS would not report was read as CLEAN via `unwrap_or(false)`),
    // and the host's `remaining` came back as a bare list with no reasons. A
    // caller saw success, saw documents still open, and had nothing to act on.
    // `swx_close_all_documents` ends the user's session, so it needs the
    // process-level opt-in to run at all — the accounting question is what it
    // says about documents it leaves behind once it IS allowed to run.
    let b = Bridge::start_with(&[("SWX_ALLOW_USER_WRITES", "1")]);
    b.call("swx_start", json!({}));
    let tmp = TempDir::new("accounting");
    let theirs = tmp.join("still-theirs.sldprt");
    std::fs::write(&theirs, b"theirs").unwrap();
    b.call("swx_open", json!({"path": theirs.to_string_lossy()}));
    // Dirty, so SOLIDWORKS will decline to close it without being told to
    // discard the changes.
    b.call("swx_props_set", json!({
        "path": theirs.to_string_lossy(), "properties": {"Revision": "C"},
        "confirm": true, "allowUserWrites": true, "reason": "make it dirty for the test"
    }));
    let mine = b.call("swx_new_document", json!({"type": "part"}));
    let mine = mine["created"]["title"].as_str().unwrap_or("").to_string();

    // closeUnsaved NOT set: the user's dirty document must survive, WITH an
    // explanation naming it.
    let r = b.call("swx_close_all_documents", json!({
        "confirm": true, "allowUserWrites": true,
        "reason": "clearing the bridge's own scratch"
    }));
    check!(b, "the bulk close succeeds", r["success"] == true, s(&r));
    check!(
        b,
        "the bridge's own clean document was closed",
        !r["closed"].as_array().map(|a| a.is_empty()).unwrap_or(true)
            && !s(&b.call("swx_docs", json!({}))).contains(&mine),
        s(&r)
    );
    let docs = b.call("swx_docs", json!({}));
    let left: Vec<String> = docs["docs"]
        .as_array()
        .unwrap()
        .iter()
        .map(|d| d["title"].as_str().unwrap_or("").to_string())
        .collect();
    let skipped = r["skipped"].as_array().cloned().unwrap_or_default();
    check!(
        b,
        "the user's document was NOT closed",
        left.iter().any(|t| t == "still-theirs.sldprt"),
        s(&docs)
    );
    // THE INVARIANT: nothing is left open without an entry naming it.
    for title in &left {
        check!(
            b,
            &format!("'{title}' is left open AND accounted for in `skipped`"),
            skipped.iter().any(|e| e["title"].as_str() == Some(title.as_str())),
            format!("left={left:?} skipped={}", serde_json::to_string(&skipped).unwrap())
        );
    }
    check!(
        b,
        "...and each entry says why, and how the user could close it",
        skipped.iter().all(|e| e["why"].as_str().map(|w| !w.is_empty()).unwrap_or(false)),
        serde_json::to_string(&skipped).unwrap()
    );
}

#[test]
fn asking_solidworks_to_quit_is_not_the_same_as_it_quitting() {
    // Live: `swx_stop {force:true, confirm, allowUserWrites, reason}` answered
    // `success:true, stopped:false` — declined, silently, with no errorCode and
    // no reason. A caller (and an AI planning its next step) reads that as
    // done. The host had done its job: it re-attaches after ExitApp and reports
    // honestly that SOLIDWORKS is still there. The SERVER then dressed that up
    // as a success.
    let machine = quittable_machine("stop-honesty", r#"{"a":"exited"}"#);
    let b = Bridge::start_with(&[
        ("SWX_ALLOW_USER_WRITES", "1"),
        ("SWX_LAUNCH_FAKE_DIR", &machine.path()),
        ("SWX_QUIT_SETTLE_MS", "80"),
    ]);
    // Not started: the host's own "nothing to stop" answer is the same shape.
    let r = b.call("swx_stop", json!({
        "force": true, "confirm": true, "allowUserWrites": true, "reason": "tidy up"
    }));
    check!(
        b,
        "a stop that did not stop anything is reported as a FAILURE",
        r["success"] == false,
        s(&r)
    );
    check!(
        b,
        "...with a stable errorCode",
        r["errorCode"].is_string() && r["errorCode"] != "",
        s(&r)
    );
    check!(
        b,
        "...and the host's own reason is preserved rather than replaced",
        r["stopped"] == false && r["reason"] == "not running",
        s(&r)
    );
    check!(
        b,
        "...and the hint does not send the caller to swx_kill",
        !s(&r).contains("use swx_kill"),
        s(&r)
    );

    // The success path still reads as a success.
    b.call("swx_start", json!({}));
    let r = b.call("swx_stop", json!({
        "confirm": true, "allowUserWrites": true, "reason": "done with SOLIDWORKS"
    }));
    check!(b, "a stop that DID stop it succeeds", r["success"] == true && r["stopped"] == true, s(&r));
}

#[test]
fn solidworks_connected_can_be_started_through_the_platform_shortcut() {
    // THE LAUNCH ANSWER (2026-09-03). This bridge spent three live rounds
    // reporting `host_app_launch_blocked` on the grounds that SOLIDWORKS
    // Connected "cannot be launched programmatically". That conclusion came
    // from the wrong experiment: we called CoCreateInstance on
    // SldWorks.Application, which starts sldworks.exe DIRECTLY, and the
    // application refused because it had been given no tenant and no registry.
    // Reading the Start-Menu shortcut shows the sanctioned chain —
    //
    //   CATSTART.exe -run "SWXDesktopLauncher.exe"
    //                -object "--AppName=\"SWXCSWK_AP\" -tenant=<TENANT> -monoapp
    //                         -3DRegistryURL=https://<region>-makers-registry..."
    //                -nowindow
    //
    // — so the refusal was OURS, for bypassing the launcher. Invoking the user's
    // own shortcut runs exactly what Dassault intends, with their tenant, and
    // nothing is reverse-engineered.
    let tmp = TempDir::new("shortcut");
    let lnk = tmp.join("SOLIDWORKS Design.lnk");
    std::fs::write(&lnk, b"shortcut").unwrap();
    let lnk = lnk.to_string_lossy().to_string();

    // ── the machine has a shortcut, and SOLIDWORKS comes up ─────────────────
    {
        let b = Bridge::start_with(&[
            ("SWX_SOLIDWORKS_SHORTCUT", &lnk),
            ("SWX_MOCK_SHORTCUT_ATTACHES", "1"),
        ]);
        let st = b.call("swx_status", json!({}));
        check!(
            b,
            "swx_status reports the shortcut it found and the route it would take",
            st["solidworks"]["shortcut"] == lnk.as_str()
                && st["solidworks"]["launchRoute"] == "platformShortcut",
            s(&st)
        );

        // GATED AS A SESSION-STARTING ACTION: a reason, and nothing more. It
        // runs a program on somebody's desktop and signs in to their tenant, so
        // it is recorded for them — but it creates nothing and destroys nothing,
        // so it does not go near the write choke point.
        let r = b.call("swx_start", json!({}));
        check!(
            b,
            "launching through the shortcut needs a reason written for the human",
            r["success"] == false && r["errorCode"] == "reason_required",
            s(&r)
        );
        check!(
            b,
            "...and it does NOT demand the write opt-in, which starting an app should not need",
            !s(&r).contains("allowUserWrites"),
            s(&r)
        );

        let r = b.call("swx_start", json!({"reason": "Drew asked me to model a bracket"}));
        check!(
            b,
            "with a reason, SOLIDWORKS Connected STARTS — the launch answer",
            r["success"] == true && r["started"] == true && r["attached"] == true,
            s(&r)
        );
        check!(
            b,
            "...by the sanctioned route, named in the response",
            r["launchRoute"] == "platformShortcut" && r["shortcut"] == lnk.as_str(),
            s(&r)
        );
        check!(
            b,
            "...and it is genuinely usable, not just 'launched'",
            b.call("swx_new_document", json!({"type": "part"}))["success"] == true,
            s(&r)
        );
        check!(
            b,
            "the launch is recorded for the human with the route and the reason",
            s(&b.call("swx_action_ledger", json!({}))).contains("platformShortcut"),
            s(&r)
        );
    }

    // ── the launcher was invoked but is still coming up ─────────────────────
    // A Connected cold start runs one to three minutes and may stop at a
    // sign-in nobody has answered. The verb must NOT hold the com host for
    // that: it is the server's only channel, so blocking it would freeze
    // swx_progress and every other verb. And it must not report a FAILURE —
    // that invites a second launch, which means two sign-in windows.
    {
        let b = Bridge::start_with(&[("SWX_SOLIDWORKS_SHORTCUT", &lnk)]);
        // waitSeconds:0 — do not block at all, so this is the answer a caller
        // gets the instant the launcher has been fired.
        let r = b.call("swx_start", json!({
            "reason": "starting SOLIDWORKS for Drew", "waitSeconds": 0
        }));
        check!(
            b,
            "a launch still in flight is not a failure",
            r["success"] == true && r["started"] == true,
            s(&r)
        );
        check!(
            b,
            "...it says so plainly, so the caller polls instead of launching again",
            r["stillLaunching"] == true && r["attached"] == false,
            s(&r)
        );
        check!(
            b,
            "...and the hint warns against a second launch",
            s(&r).contains("two sign-in windows"),
            s(&r)
        );
        // The bridge is still ANSWERING — the whole point of not blocking.
        check!(b, "the bridge is still responsive", b.call("swx_status", json!({}))["success"] == true, s(&r));
    }

    // ── the launcher was invoked and SOLIDWORKS arrives WHILE WE WAIT ───────
    // The attach poll, which is the reason this verb is not a one-shot. The
    // mock's launcher becomes attachable after a delay, exactly as a Connected
    // cold start does, so the loop is genuinely exercised rather than asserted.
    {
        let b = Bridge::start_with(&[
            ("SWX_SOLIDWORKS_SHORTCUT", &lnk),
            ("SWX_MOCK_SHORTCUT_ATTACHES_AFTER_MS", "3000"),
        ]);
        let r = b.call("swx_start", json!({
            "reason": "starting SOLIDWORKS for Drew", "waitSeconds": 20
        }));
        check!(
            b,
            "the poll waits out a slow launcher and attaches when it arrives",
            r["success"] == true && r["attached"] == true && r["stillLaunching"] == false,
            s(&r)
        );
        check!(
            b,
            "...having actually waited for it, not guessed",
            r["elapsedSeconds"].as_u64().unwrap_or(0) >= 3,
            s(&r)
        );
        check!(
            b,
            "...and only ONE launch was made, however many times we probed",
            b.call("swx_docs", json!({}))["success"] == true,
            s(&r)
        );
    }

    // ── no shortcut anywhere: blocked, and ONLY then ────────────────────────
    {
        let b = Bridge::start_with(&[("SWX_TEST_NO_LAUNCH", "1")]);
        let r = b.call("swx_start", json!({"reason": "trying"}));
        check!(
            b,
            "with no shortcut to invoke, the bridge asks the user — the one remaining block",
            r["success"] == false && r["errorCode"] == "host_app_launch_blocked",
            s(&r)
        );
        check!(
            b,
            "...and says the block is a MISSING SHORTCUT, not an impossible edition",
            s(&r).contains("could not FIND that shortcut")
                && s(&r).contains("SWX_SOLIDWORKS_SHORTCUT"),
            s(&r)
        );
    }
}

#[test]
fn a_refused_bulk_close_closes_nothing_at_all() {
    // Found while proving the fix above. `swx_close_all_documents` ran its
    // discard loop and only THEN asked whether it was allowed to end the
    // session — so in the DEFAULT posture it closed the bridge's own dirty
    // documents, discarding their contents, and returned a refusal. Side
    // effects on the way to "no". A refusal has to mean nothing happened.
    let b = Bridge::start();
    b.call("swx_start", json!({}));
    let made = b.call("swx_new_document", json!({"type": "part"}));
    let title = made["created"]["title"].as_str().unwrap_or("").to_string();
    b.call("swx_run_script", json!({"script": [
        {"op": "sketch_rect", "plane": "Front Plane", "widthMm": 40, "heightMm": 40},
        {"op": "extrude", "depthMm": 10}
    ], "targetDocument": title.clone()}));
    let docs = b.call("swx_docs", json!({}));
    check!(b, "the bridge has one dirty document of its own", docs["docs"][0]["dirty"] == true, s(&docs));

    let r = b.call("swx_close_all_documents", json!({
        "confirm": true, "closeUnsaved": true, "reason": "clearing up"
    }));
    check!(
        b,
        "the bulk close is refused without the process-level opt-in",
        r["success"] == false && r["errorCode"] == "user_writes_disabled",
        s(&r)
    );
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "AND NOTHING WAS CLOSED — a refusal that already destroyed work is not a refusal",
        docs["docs"].as_array().unwrap().len() == 1 && docs["docs"][0]["title"] == title.as_str(),
        s(&docs)
    );
    check!(
        b,
        "...and the work is still there, not silently discarded",
        docs["docs"][0]["dirty"] == true,
        s(&docs)
    );
}

#[test]
fn a_document_solidworks_will_not_answer_for_is_treated_as_unsaved() {
    // SOLIDWORKS does not always report whether a document is dirty. Every
    // other verb treats an unanswerable question as "dirty" — swx_close_doc
    // says so in as many words — but `swx_close_all_documents` read the field
    // with `unwrap_or(false)`, so a document whose state could not be
    // established was classified CLEAN. It then never entered the discard loop,
    // `CloseAllDocuments(false)` left it alone because it did in fact need
    // saving, and it came back in the host's `remaining` — left open by a call
    // that had been told to close everything, with nothing anywhere saying why.
    // That is one of the two documents live run 3's cleanup could not shift.
    let b = Bridge::start_with(&[
        ("SWX_ALLOW_USER_WRITES", "1"),
        ("SWX_MOCK_DIRTY_UNKNOWN", "1"),
    ]);
    b.call("swx_start", json!({}));
    let tmp = TempDir::new("unknown-dirty");
    let theirs = tmp.join("unanswerable.sldprt");
    std::fs::write(&theirs, b"theirs").unwrap();
    b.call("swx_open", json!({"path": theirs.to_string_lossy()}));
    b.call("swx_props_set", json!({
        "path": theirs.to_string_lossy(), "properties": {"Revision": "D"},
        "confirm": true, "allowUserWrites": true, "reason": "make it genuinely unsaved"
    }));
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "SOLIDWORKS will not say whether this document is dirty",
        docs["docs"][0]["dirty"].is_null(),
        s(&docs)
    );

    let r = b.call("swx_close_all_documents", json!({
        "confirm": true, "closeUnsaved": true, "allowUserWrites": true,
        "reason": "Drew authorized clearing every leftover"
    }));
    check!(b, "the bulk close succeeds", r["success"] == true, s(&r));
    let docs = b.call("swx_docs", json!({}));
    check!(
        b,
        "a document whose state is UNKNOWN is closed as unsaved, not skipped as clean",
        docs["docs"].as_array().unwrap().is_empty(),
        format!("{} / {}", s(&r), s(&docs))
    );
    check!(
        b,
        "...and it is recorded as a discard, because that is what it might have been",
        s(&b.call("swx_action_ledger", json!({}))).contains("user_document_changes_discarded"),
        s(&r)
    );
}

#[test]
fn running_a_macro_is_arbitrary_code_and_is_gated_as_such() {
    // `swx_run_macro` wraps ISldWorks::RunMacro2. A macro is a VBA project with
    // the whole SOLIDWORKS API in scope and the filesystem behind it: it can
    // model, save over anything, batch-export, delete or quit, to documents this
    // bridge has never seen. The two questions the write choke point asks of
    // everything else — is the document ours, is the destination clear — cannot
    // bound it. So there is NO safe case, and this verb is always gated.
    let tmp = TempDir::new("macros");
    let mac = tmp.join("adom-hello.swp");
    std::fs::write(&mac, b"' a macro").unwrap();
    let mac = mac.to_string_lossy().to_string();

    // ── the default posture refuses, and keeps refusing ─────────────────────
    {
        let off = Bridge::start();
        off.call("swx_start", json!({}));
        // Even fully "confirmed" by the caller: an AI cannot grant itself the
        // right to run arbitrary code on somebody's desktop.
        let r = off.call("swx_run_macro", json!({
            "path": mac.clone(), "confirm": true, "allowUserWrites": true,
            "reason": "I would like to run this"
        }));
        // And the gate comes FIRST: an unauthorized caller does not even learn
        // whether the path exists.
        let probe = off.call("swx_run_macro", json!({
            "path": tmp.join("does-not-exist.swp").to_string_lossy(),
            "confirm": true, "allowUserWrites": true, "reason": "probing"
        }));
        check!(
            off,
            "the gate is checked BEFORE the filesystem, so a refusal leaks nothing about it",
            probe["errorCode"] == "user_writes_disabled",
            s(&probe)
        );
        check!(
            off,
            "the default posture refuses to run a macro, however it is asked",
            r["success"] == false && r["errorCode"] == "user_writes_disabled",
            s(&r)
        );
        check!(
            off,
            "...and says what it is refusing: arbitrary code, not a document write",
            s(&r).contains("arbitrary code"),
            s(&r)
        );
        check!(
            off,
            "...and names the process-level opt-in it would need",
            r["requires"]["env"] == "SWX_ALLOW_USER_WRITES=1",
            s(&r)
        );
    }

    // ── opted in: it runs, and every partial chain still refuses ────────────
    let on = Bridge::start_with(&[("SWX_ALLOW_USER_WRITES", "1")]);
    on.call("swx_start", json!({}));

    for (missing, args) in [
        ("nothing at all", json!({"path": mac.clone()})),
        ("confirm and reason", json!({"path": mac.clone(), "allowUserWrites": true})),
        ("a reason", json!({"path": mac.clone(), "allowUserWrites": true, "confirm": true})),
        ("allowUserWrites", json!({"path": mac.clone(), "confirm": true, "reason": "why"})),
    ] {
        let r = on.call("swx_run_macro", args);
        check!(
            on,
            &format!("a call missing {missing} does not run a macro"),
            r["success"] == false,
            s(&r)
        );
    }

    // A path that does not exist is caught HERE, not turned into a bare
    // RunMacro2 error code.
    let r = on.call("swx_run_macro", json!({
        "path": tmp.join("nope.swp").to_string_lossy(),
        "allowUserWrites": true, "confirm": true, "reason": "Drew asked for it"
    }));
    check!(
        on,
        "a missing macro is a clear error, not a numeric run code",
        r["success"] == false && r["errorCode"] == "macro_not_found",
        s(&r)
    );

    // THE WHOLE CHAIN: it runs.
    let r = on.call("swx_run_macro", json!({
        "path": mac.clone(),
        "allowUserWrites": true, "confirm": true,
        "reason": "Drew asked me to run his hello macro"
    }));
    check!(
        on,
        "with the full opt-in the macro runs",
        r["success"] == true && r["ran"] == true && r["runError"] == 0,
        s(&r)
    );
    check!(
        on,
        "the macro is unloaded afterwards, so an edited macro does not run its old code",
        r["unloadedAfterRun"] == true,
        s(&r)
    );
    check!(
        on,
        "the response admits this verb has never run on a live machine",
        r["provenLive"] == false && s(&r).contains("NOT YET PROVEN ON A LIVE MACHINE"),
        s(&r)
    );
    check!(
        on,
        "the run is recorded for the human with the reason they gave",
        s(&on.call("swx_action_ledger", json!({}))).contains("Drew asked me to run his hello macro"),
        s(&r)
    );

    // A module/procedure that is not in the project: RunMacro2 returns FALSE
    // with the reason ONLY in the out parameter, which is the detail most
    // easily got wrong.
    let r = on.call("swx_run_macro", json!({
        "path": mac.clone(), "module": "main", "procedure": "noSuchProc",
        "allowUserWrites": true, "confirm": true, "reason": "Drew asked for it"
    }));
    check!(
        on,
        "a missing procedure surfaces the swRunMacroError_e out parameter, not just 'false'",
        r["ran"] == false && r["runError"] == 1 && r["runErrorText"].as_str().unwrap_or("").contains("could not be found"),
        s(&r)
    );

    // Not a macro at all.
    let notmac = tmp.join("thing.txt");
    std::fs::write(&notmac, b"x").unwrap();
    let r = on.call("swx_run_macro", json!({
        "path": notmac.to_string_lossy(),
        "allowUserWrites": true, "confirm": true, "reason": "Drew asked for it"
    }));
    check!(on, "a file that is not a macro is refused", r["success"] == false, s(&r));
}

// ════════════════════════════════════════════════════════════════════════════
// A GUARD THAT NOTHING CALLS IS A COMMENT WITH A TEST ATTACHED
// ════════════════════════════════════════════════════════════════════════════

/// Stage a launch record whose attribution is about a DIFFERENT SOLIDWORKS than
/// the one COM will answer for. This is the shape a stale or wrong claim has, and
/// the three verbs that can end or empty a session must all refuse it.
fn stage_a_claim_about_another_process(scratch: &TempDir) {
    std::fs::write(
        scratch.join("launch-state.json"),
        json!({
            "attempt": {
                "id": 1,
                "startedAt": 1_700_000_000u64,
                "shortcut": "SOLIDWORKS Design.lnk",
                "route": "shellExecute",
                "invokedAt": 1_700_000_000u64,
                "stage": "attached",
                "finished": true,
                "outcome": "attachedAfterSignIn",
                "runBeginSeen": true,
                // THE CLAIM: a process this bridge says it launched — which is
                // NOT the one the mock will report as attached.
                "attributedSolidworks": {"pid": 424242, "createdAt": 1_700_000_001u64},
            },
            "preferredRoute": "shellExecute",
            "consecutiveFailures": 0,
        })
        .to_string(),
    )
    .unwrap();
}

/// WIRING, not the function. `identity_matches_attribution` shipped in 0.6.7
/// unit-tested and with ZERO production callers — the fifth guard in this project
/// to do that, and the third about attribution. These tests go through the VERBS,
/// so deleting the call site (not the function) fails them.
#[test]
fn swx_stop_refuses_when_the_launch_claim_names_another_session() {
    let scratch = TempDir::new("claim-stop");
    stage_a_claim_about_another_process(&scratch);
    // A machine whose session this bridge CAN identify: without one the live
    // identity is unknown, and an unknown refuses for that reason instead —
    // which would leave the claim check unexercised.
    let machine = quittable_machine("claim-stop-machine", r#"{"a":"exited"}"#);
    let b = Bridge::start_in(
        TempDir::borrowed(&scratch.0),
        &[("SWX_ALLOW_USER_WRITES", "1"), ("SWX_LAUNCH_FAKE_DIR", &machine.path()),
          ("SWX_QUIT_SETTLE_MS", "80")],
    );
    b.call("swx_start", json!({}));
    let r = b.call("swx_stop", json!({
        "confirm": true, "allowUserWrites": true, "force": true,
        "reason": "the caller asked to end the session",
    }));
    check!(
        b,
        "swx_stop refuses a session its own launch record does not cover",
        r["errorCode"] == "identity_mismatch",
        s(&r)
    );
    check!(
        b,
        "...and names both processes",
        r["error"].as_str().unwrap_or("").contains("424242"),
        s(&r)
    );
}

#[test]
fn swx_close_all_documents_refuses_when_the_launch_claim_names_another_session() {
    let scratch = TempDir::new("claim-closeall");
    stage_a_claim_about_another_process(&scratch);
    // A machine whose session this bridge CAN identify: without one the live
    // identity is unknown, and an unknown refuses for that reason instead —
    // which would leave the claim check unexercised.
    let machine = quittable_machine("claim-closeall-machine", r#"{"a":"exited"}"#);
    let b = Bridge::start_in(
        TempDir::borrowed(&scratch.0),
        &[("SWX_ALLOW_USER_WRITES", "1"), ("SWX_LAUNCH_FAKE_DIR", &machine.path()),
          ("SWX_QUIT_SETTLE_MS", "80")],
    );
    b.call("swx_start", json!({}));
    let r = b.call("swx_close_all_documents", json!({
        "confirm": true, "allowUserWrites": true, "closeUnsaved": true,
        "reason": "the caller asked for a clean session",
    }));
    check!(
        b,
        "swx_close_all_documents refuses it too",
        r["errorCode"] == "identity_mismatch",
        s(&r)
    );
}

#[test]
fn swx_reset_workspace_refuses_when_the_launch_claim_names_another_session() {
    let scratch = TempDir::new("claim-reset");
    stage_a_claim_about_another_process(&scratch);
    // A machine whose session this bridge CAN identify: without one the live
    // identity is unknown, and an unknown refuses for that reason instead —
    // which would leave the claim check unexercised.
    let machine = quittable_machine("claim-reset-machine", r#"{"a":"exited"}"#);
    let b = Bridge::start_in(
        TempDir::borrowed(&scratch.0),
        &[("SWX_LAUNCH_FAKE_DIR", &machine.path())],
    );
    b.call("swx_start", json!({}));
    let r = b.call("swx_reset_workspace", json!({"reason": "clearing our scratch documents"}));
    check!(
        b,
        "swx_reset_workspace refuses it too — it closes documents by name in that session",
        r["errorCode"] == "identity_mismatch",
        s(&r)
    );
}

/// ...and with NO claim recorded, nothing changes: the ordinary rules decide.
#[test]
fn with_no_launch_claim_the_ordinary_rules_still_decide() {
    let b = Bridge::start();
    b.call("swx_start", json!({}));
    let r = b.call("swx_reset_workspace", json!({"reason": "clearing"}));
    check!(
        b,
        "a bridge that never launched anything is not blocked by the claim check",
        r["errorCode"] != "identity_mismatch",
        s(&r)
    );
}