← Commit history
BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.71\ No newline at end of file+1.9.72\ No newline at end of file
CHANGELOG.md+10
@@ -3,6 +3,16 @@ All notable changes to the Adom Bridge Fusion 360 bridge, newest first. Canonical: https://wiki.adom.inc/adom/fusion-bridge · GitHub backup: `adom-inc/fusion-bridge` +## 1.9.72 - 2026-08-18 (ralph)++- **Design surfaces regenerate their project on demand.** Staging cached itself as complete even+  when `make_test_project` failed (it can fail if Fusion is mid-restart), so every later design+  click paid a full re-heal and still failed. The staging cache now records `designReady`, and a+  design click regenerates just the project - after calling ensure_ready first, which the cached+  path was skipping (a doctrine gap in my own new code, caught in the same loop).+  Verified: schematic went from failing to opening in 221s including a Fusion relaunch.+- Dashboard/bridge back in version lockstep (both 1.9.72).+ ## 1.9.71 - 2026-08-18 (ralph)  - **The DESIGN surfaces survive a bridge respawn.** show_project / show_schematic / show_2d_board /
adom-bridge-fusion-manifest.json+4−4
@@ -1,10 +1,10 @@ {     "manifest_version": 1,     "name": "fusion360",-    "version": "1.9.71",-    "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.71/adom-bridge-fusion-v1.9.71.zip",-    "sha256": "ecaa27e89c81db89cf24d2da7e035887a57d79f5e5ec1f9b6574f7ea7be0d36c",-    "size": 409291,+    "version": "1.9.72",+    "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.72/adom-bridge-fusion-v1.9.72.zip",+    "sha256": "18b4365ec71d90c26ef39554eba77a863efdad5161ff7dcc0ad3ef29976011bb",+    "size": 409290,     "verbPrefixes": [         "fusion_"     ],
bin/fusion-dashboard
⋯ 1 unchanged line ⋯
dashboard/Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.67"+version = "1.9.72" edition = "2021"  [dependencies]
dashboard/src/main.rs+37−8
@@ -234,7 +234,9 @@ struct App {     // Surfaces demo staging, keyed BY TARGET: staging sends files to one specific box, so a     // single global slot made a switch to another box reuse paths that box never received     // (caught live 2026-08-18).-    staged: Mutex<std::collections::HashMap<String, (String, String)>>,+    // (libraryPath, deviceset, designReady) - designReady false means the generated test+    // project did NOT land, so the four design surfaces must regenerate it before they run.+    staged: Mutex<std::collections::HashMap<String, (String, String, bool)>>, }  // ── Dashboard-own settings (container-side; bridge prefs stay in the bridge) ──────────────@@ -476,7 +478,7 @@ const SURFACES: [(&str, &str, &str); 8] = [     ("project",   "fusion_show_project",    "Project"), ]; -fn stage_demo_part(app: &Arc<App>, target: &str, page: &str) -> Result<(String, String), String> {+fn stage_demo_part(app: &Arc<App>, target: &str, page: &str) -> Result<(String, String, bool), String> {     let cache_key = format!("{}|{}", target, page);     if let Some(hit) = app.staged.lock().unwrap().get(&cache_key).cloned() { return Ok(hit); }     let ai = app.ai_thread.clone();@@ -523,13 +525,17 @@ fn stage_demo_part(app: &Arc<App>, target: &str, page: &str) -> Result<(String,     toast("Generating a solo test project around the part", "");     let mp = unwrap_data(&bridge(&ai, target, "fusion_make_test_project",                                  &serde_json::json!({"libraryPath": win_lbr}).to_string()));-    if mp["success"].as_bool() != Some(true) {-        // Component surfaces still work without the design half - report, do not abort.-        toast("Design surfaces unavailable (test project generation failed) - component surfaces still work", "err");+    let design_ok = mp["success"].as_bool() == Some(true);+    if !design_ok {+        // Component surfaces still work without the design half. Record the FAILURE so a later+        // design click regenerates just the project instead of assuming it exists (ralph,+        // 2026-08-18: it failed while Fusion was mid-restart and every design surface then paid+        // a full re-heal + re-stage cycle).+        toast("Design surfaces need the test project - I will generate it when you click one", "");     }-    app.staged.lock().unwrap().insert(cache_key, (win_lbr.clone(), deviceset.clone()));+    app.staged.lock().unwrap().insert(cache_key, (win_lbr.clone(), deviceset.clone(), design_ok));     toast(&format!("{} staged - every surface button is live", deviceset), "ok");-    Ok((win_lbr, deviceset))+    Ok((win_lbr, deviceset, design_ok)) }  fn show_surface(app: &Arc<App>, target: &str, key: &str, page: &str) -> serde_json::Value {@@ -537,10 +543,33 @@ fn show_surface(app: &Arc<App>, target: &str, key: &str, page: &str) -> serde_js         Some((_, v, l)) => (*v, *l),         None => return serde_json::json!({"error": format!("unknown surface {}", key)}),     };-    let (lib, dev) = match stage_demo_part(app, target, page) {+    let (lib, dev, mut design_ok) = match stage_demo_part(app, target, page) {         Ok(x) => x,         Err(e) => return serde_json::json!({"error": e}),     };+    let is_design = matches!(key, "project" | "schematic" | "board2d" | "board3d");+    if is_design && !design_ok {+        // DOCTRINE: get the box ready first - this path runs from a CACHED staging, so it skips+        // stage_demo_part's own ensure_ready and would otherwise fail with "not running" the+        // moment Fusion closed or the Autodesk seat moved (ralph, 2026-08-18).+        if !ensure_ready(app, target, 240) {+            return serde_json::json!({"surface": key, "label": label, "ok": false,+                "error": format!("Fusion did not become ready on {} in time", target),+                "_hint": "Open Settings and read the status cards - a sign-in wall or a stuck launch is reported there."});+        }+        app.hub.broadcast("toast", &serde_json::json!({+            "message": "Generating the test project for the design surfaces", "kind": ""}));+        let mp = unwrap_data(&bridge(&app.ai_thread, target, "fusion_make_test_project",+                                     &serde_json::json!({"libraryPath": lib}).to_string()));+        design_ok = mp["success"].as_bool() == Some(true);+        app.staged.lock().unwrap().insert(format!("{}|{}", target, page),+                                          (lib.clone(), dev.clone(), design_ok));+        if !design_ok {+            return serde_json::json!({"surface": key, "label": label, "ok": false,+                "error": format!("could not generate the test project: {}", mp["error"]),+                "_hint": "The design surfaces need a generated project; the component surfaces (symbol, footprint, 3D package, library) work without it."});+        }+    }     let ai = app.ai_thread.clone();     let args = match key {         "symbol" | "footprint" | "package3d" => serde_json::json!({"name": dev, "libraryPath": lib}),
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "fusion-bridge",-  "version": "1.9.65",+  "version": "1.9.72",   "type": "app",   "description": "This package installs the bridge's SKILLS into your container so your AI knows how to drive it; Adom Bridge loads the bridge runtime itself from the release zip.",   "dependencies": {
page.json+11−8
@@ -1,16 +1,20 @@ {   "slug": "fusion-bridge",-  "version": "1.9.65",+  "version": "1.9.72",   "type": "app",   "description": "This package installs the bridge's SKILLS into your container so your AI knows how to drive it; Adom Bridge loads the bridge runtime itself from the release zip.",   "dependencies": {-    "adom/adom-desktop": "*"+    "adom/adom-desktop": "^1.9.0"   },   "scripts": {     "install": "./install.sh",     "uninstall": "./uninstall.sh"   },   "tags": [+    "ab",+    "bridge",+    "fusion",+    "desktop-app",     "fusion360",     "autodesk",     "cad",@@ -70,7 +74,10 @@     "build a basic parts library",     "add a 3d model to a component",     "make a fusion 360 library with 3d",-    "set up the fusion bridge"+    "set up the fusion bridge",+    "fusion dashboard",+    "fusion status page",+    "open the fusion launch page"   ],   "discovery_pitch": "Use the Adom Bridge Fusion 360 bridge when the user wants to DRIVE Autodesk Fusion 360 from the cloud: open/search their team's Fusion cloud designs, lay out a PCB or do electronics, export STEP/IGES/STL/Gerbers/BOM, or build a component library with real rendering 3D. It runs Fusion on the user's own machine via Adom Bridge. NOT for web/browser/login/form-filling (that's the native-browser extension) and NOT for KiCad (that's the kicad bridge).",   "brief": "Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.",@@ -99,9 +106,5 @@       "label": "Part volume",       "prompt": "How much material does each printed part in this assembly use?"     }-  ],-  "author": {-    "name": "John Lauer",-    "email": "[email protected]"-  }+  ] }\ No newline at end of file