← Commit history

Publish 1.9.100

John Lauer ·c88b4ffa0c ·1mo ago ·parent 6667571
4 files changed +40−20
bin/fusion-dashboard
⋯ 1 unchanged line ⋯
dashboard/Cargo.lock+1−1
@@ -4,7 +4,7 @@ version = 4  [[package]] name = "fusion-dashboard"-version = "1.9.98"+version = "1.9.100" dependencies = [  "serde_json", ]
dashboard/src/main.rs+32−9
@@ -299,7 +299,7 @@ struct App {     // Last GOOD status per target. While the bridge is busy (a tour, a long verb), readiness     // calls time out and every field reads false - which used to paint the whole board RED     // while the tour was visibly running (ralph, 2026-08-18). Unknowable is not broken.-    last_good: Mutex<std::collections::HashMap<String, serde_json::Value>>,+    last_good: Mutex<std::collections::HashMap<String, (Instant, serde_json::Value)>>,     // Boxes we are actively launching Fusion on, so the LED can say "opening right now"     // instead of leaving the user guessing (John, 2026-08-18).     launching: Mutex<std::collections::HashMap<String, Instant>>,@@ -1010,15 +1010,38 @@ fn handle_conn(app: &Arc<App>, mut stream: TcpStream) {                 }             }             if st["answered"].as_bool() == Some(true) {-                app.last_good.lock().unwrap().insert(t.clone(), st.clone());-            } else if let Some(prev) = app.last_good.lock().unwrap().get(&t).cloned() {-                // Keep showing the last VERIFIED state and say it is stale, instead of flipping-                // every LED red just because the bridge was too busy to answer.+                app.last_good.lock().unwrap().insert(t.clone(), (Instant::now(), st.clone()));+            } else if let Some((at, prev)) = app.last_good.lock().unwrap().get(&t).cloned() {+                // Keep showing the last VERIFIED state rather than flipping every LED red+                // because one probe was busy - BUT ONLY WHILE IT IS STILL PLAUSIBLY TRUE.+                //+                // ⚠️ A SNAPSHOT IS NOT A FACT (John, live 2026-08-20: "why is your fusion+                // dashboard not showing all green led's right now?"). AdomLapper's last_good+                // was captured while Fusion was DOWN. Every later probe lost a race inside+                // the six-verb fan-out, so this branch kept re-serving that dead snapshot -+                // and broadcasting it over SSE, overwriting good renders - for FIVE HOURS,+                // while fusion_readiness answered running:true ready:true on demand. The+                // dashboard confidently showed red for a box that was green.+                //+                // So the fallback is now TIME-BOUNDED and its age is always visible. Past the+                // window, "I cannot check right now" is reported honestly instead of dressing+                // up an old picture as the current one.+                let age = at.elapsed().as_secs();                 let reason = st["busyReason"].clone();-                st = prev;-                st["stale"] = serde_json::Value::Bool(true);-                st["busyReason"] = reason;-                st["_hint"] = serde_json::json!("Showing the LAST VERIFIED state: the bridge is busy (a tour or long verb is running) so a fresh probe did not answer. Nothing here is broken - it is simply not re-checkable this second.");+                if age <= 180 {+                    st = prev;+                    st["stale"] = serde_json::Value::Bool(true);+                    st["busyReason"] = reason;+                    st["lastVerifiedAgeSec"] = serde_json::json!(age);+                    st["_hint"] = serde_json::json!(format!(+                        "Showing the state verified {}s ago: a fresh probe did not answer (the bridge is busy with a long verb). Nothing here is broken - it is simply not re-checkable this second.", age));+                } else {+                    st["stale"] = serde_json::Value::Bool(true);+                    st["lastVerifiedAgeSec"] = serde_json::json!(age);+                    st["busyReason"] = reason;+                    st["_hint"] = serde_json::json!(format!(+                        "The bridge has not answered a status probe for {}s, and the last verified state is too old to keep presenting as current. Press refresh, or read fusion_readiness directly - it often answers alone even when the six-verb status fan-out does not.", age));+                }             }             app.hub.broadcast("state", &st);             respond_json(&mut stream, &st);
page.json+7−10
@@ -4,17 +4,13 @@   "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": "^1.9.0"+    "adom/adom-desktop": "*"   },   "scripts": {     "install": "./install.sh",     "uninstall": "./uninstall.sh"   },   "tags": [-    "ab",-    "bridge",-    "fusion",-    "desktop-app",     "fusion360",     "autodesk",     "cad",@@ -74,10 +70,7 @@     "build a basic parts library",     "add a 3d model to a component",     "make a fusion 360 library with 3d",-    "set up the fusion bridge",-    "fusion dashboard",-    "fusion status page",-    "open the fusion launch page"+    "set up the fusion bridge"   ],   "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.",@@ -106,5 +99,9 @@       "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