app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
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.
← Commit history
Publish 1.9.355
7 files changed
+933−20
.insiders-stage/fusion-bridge/version.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.9.354",- "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.354/adom-bridge-fusion-v1.9.354.zip",- "sha256": "be866be570eb389054cd9f06bb3817c75d3ef5357d6e0a5ac823136d55050d41",- "size": 2239332,+ "version": "1.9.355",+ "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.355/adom-bridge-fusion-v1.9.355.zip",+ "sha256": "07784c41e9931f3d7a273d2b22e0f46a45b56f11b14147c624f5b7f46b40fe63",+ "size": 2277785, "verbPrefixes": [ "fusion_" ],
.release-page-head+1−1@@ -1 +1 @@-2579ddb0cef53f26b44396be18798dee72200ca0+6f27922be73f0cd9200f656dbb2b30ff14954211
page.json+26−10@@ -11,10 +11,6 @@ "uninstall": "./uninstall.sh" }, "tags": [- "ab",- "bridge",- "fusion",- "desktop-app", "fusion360", "autodesk", "cad",@@ -79,10 +75,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.",@@ -111,5 +104,28 @@ "label": "Part volume", "prompt": "How much material does each printed part in this assembly use?" }- ]-}+ ],+ "agent_permissions": {+ "allow_bash": [],+ "allow": [+ "adom-desktop-fusion-bridge read-only verbs (via the adom-bridge CLI): fusion_readiness, fusion_get_app_state, fusion_addin_status, fusion_check_dialogs - state queries; they change nothing.",+ "adom-desktop-fusion-bridge read-only verbs: fusion_alerts (reads Fusion's own log for toasts), fusion_document_info, fusion_window_info, fusion_board_info, fusion_library_parts - inspect only.",+ "adom-desktop-fusion-bridge read-only verbs: fusion_prove_result (a persisted run report), fusion_plan_library_import (report-only preflight), fusion_list_cloud_projects, fusion_describe.",+ "adom-desktop-fusion-bridge evidence captures fusion_screenshot_fusion and fusion_capture_library_views read pixels and write local image files only."+ ],+ "soft_deny": [+ "adom-desktop-fusion-bridge lifecycle verbs fusion_stop, fusion_kill, fusion_restart_for_addin close or kill the Fusion application - keep the human prompt.",+ "adom-desktop-fusion-bridge fusion_install_fusion silently installs Autodesk Fusion on the user's machine.",+ "adom-desktop-fusion-bridge fusion_cleanup_cloud_files deletes files from the user's Autodesk cloud hub.",+ "adom-desktop-fusion-bridge managed-library verbs (fusion_managed_library_push/pull/create/link/unlink) publish to or overwrite the user's library.io libraries."+ ],+ "environment": [+ "adom-desktop-fusion-bridge is the Fusion 360 bridge for Adom Bridge; its fusion_* verbs are invoked through the adom-bridge CLI and drive Autodesk Fusion on the user's own desktop.",+ "adom-desktop-fusion-bridge desktop actions also pass Adom Bridge's own human-approval gate (caller identity, per-call reason, Activity Log) - a container approval is the first of two gates."+ ]+ },+ "author": {+ "name": "John Lauer",+ "email": "[email protected]"+ }+}
rust/Cargo.lock+5−5@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adom-fusion-bridge"-version = "1.9.354"+version = "1.9.355" dependencies = [ "chrono", "fusion-core",@@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "fusion-core"-version = "1.9.354"+version = "1.9.355" dependencies = [ "serde", "serde_json",@@ -193,7 +193,7 @@ dependencies = [ [[package]] name = "fusion-lbr"-version = "1.9.354"+version = "1.9.355" dependencies = [ "regex", "roxmltree",@@ -205,14 +205,14 @@ dependencies = [ [[package]] name = "fusion-os-mac"-version = "1.9.354"+version = "1.9.355" dependencies = [ "fusion-core", ] [[package]] name = "fusion-os-win"-version = "1.9.354"+version = "1.9.355" dependencies = [ "fusion-core", "windows-sys 0.59.0",
rust/core/src/readiness_hints.jsonadded+21@@ -0,0 +1,21 @@+{+ "not_installed": "Fusion 360 is NOT installed. OFFER to install it for the user, then call fusion_install_fusion (no shell approval needed) - it streams the free trial and this verb reports installing:true until done.",+ "installing": "Fusion install is STREAMING (10-30 min) - keep polling fusion_readiness until installed:true.",+ "installed_not_running": "Fusion is INSTALLED but not running - call fusion_start (blocks until the add-in is ready), then retry.",+ "addin_silent": "Fusion is RUNNING but its add-in is NOT responding yet - NOT ready to drive. Either it is still finishing launch / signing in (poll fusion_readiness a few more times), or the add-in did not load (fusion_stop then fusion_start to re-deploy + re-load it). Do NOT fire modeling/export verbs until ready:true.",+ "needs_signin": "Fusion is RUNNING but stuck at the first-run Autodesk SIGN-IN (main UI blocked, add-in cannot serve) - NOT ready. FULL PLAYBOOK: the `fusion-autodesk-signin` skill. Proven sequence + the pitfalls that cost hours on a fresh Hyper-V VM (John 2026-07-14): (1) BLANK white webview on first launch? fusion_stop then fusion_start - the sign-in renders 'Welcome to Fusion' + a 'Sign In' button only after a clean relaunch. (2) ASK the user FIRST (AskUserQuestion): do they have a warm Google/Apple/Microsoft session for the account LINKED to their Autodesk login? Offer to drive it. A truly fresh box has NO warm browser session, so 'Continue with Google' still hits a password wall. (3) Click Fusion 'Sign In' -> it opens the DEFAULT browser (Edge) to the OAuth. Edge windows DO exist even if PowerShell EnumWindows looks empty - that is CLIXML progress noise; set $ProgressPreference='SilentlyContinue', and just desktop_screenshot_window the Edge hwnd (PrintWindow works backgrounded). (4) In the browser: 'Continue with Google' -> type the user's EMAIL (not secret) -> if it asks for a PASSWORD/2FA, STOP and fusion_notify_owner {title, body} to toast their MAIN computer so THEY type it; NEVER enter password/2FA yourself. (5) Handoff back to Fusion is via the 'Autodesk Identity Manager' protocol - Edge shows a 'This site is trying to open...' overlay: tick 'Always allow' + click 'Open'. (6) SPEED MATTERS: the sign-in code EXPIRES in ~2 min; on a high-latency VM slow screenshot/click round-trips let it expire ('Sign-in request expired') and you loop. Minimize steps; if it expires, click Fusion 'Sign In' again for a FRESH code (the browser session stays warm). Then poll until ready:true. FIRST-TIME DEMO? Run fusion_demo instead - it drives this sign-in through the user's NATIVE browser (already signed into Autodesk) and then gives them a real guided tour (project -> schematic -> 2D board -> 3D board).",+ "licensing": "Fusion is blocked by a SEAT/LICENSING dialog ('Active Sessions Exceeded' / 'Suspend Remote Session') - detected DETERMINISTICALLY as an OWNED POPUP of the main Fusion window (its title is just 'Fusion360' and it can be as short as 262px, so it is found by owner+parent-screenshot, NOT a size guess). This verb JUST TRIED to auto-resolve it in the BACKGROUND (UIA 'Continue', Suspend pre-selected so it reclaims the seat) but it is still up - it may be mid-render (the first UIA Invoke no-ops). Just POLL fusion_readiness again in a few seconds; it keeps auto-resolving. Never coordinate-click or ask the user, and never kill/relaunch (the server keeps the seat).",+ "updating": "Fusion is applying an AUTO-UPDATE (multiple webdeploy builds present) and RESTARTS ITSELF every ~30-60s - this is NOT a crash or a bridge failure. Poll fusion_readiness; it stabilizes to ready:true once the update finishes (can take 10-30 min). Meanwhile, wrap modeling/export verbs in a short retry/catch-loop to ride the up-windows rather than treating an intermittent 'not running' as fatal.",+ "ready_signed": "READY - drive Fusion (fusion_open_lbr / build_library_3d / etc.). APS cloud search is signed in too, so use fusion_aps_search for ~2s cloud lookups. Autodesk's MCP server is ",+ "ready_configured": "READY to drive Fusion, but APS CLOUD SEARCH IS NOT SIGNED IN - cloud file search will be slow/blocked. DO IT NOW, do not make the user log in a second time: call fusion_aps_signin RIGHT AFTER a Fusion sign-in, while the browser profile still has a warm Autodesk SSO session - it consents silently (no password, no 2FA). Then fusion_aps_search works. Autodesk's MCP server is ",+ "ready_unconfigured": "READY to drive Fusion. APS cloud search is NOT SET UP (no client ID) - cloud search is the slow path without it. Offer to set it up: fusion_aps_set_client_id then fusion_aps_signin (silent while the browser SSO session is warm). APS is how cloud search gets to ~2 seconds. Autodesk's MCP server is ",+ "mcp_off": "OFF - fusion_mcp_enable can turn it on for the user (~10s, drives the Preferences dialog).",+ "mcp_on": "LIVE (fusion_mcp_* verbs work).",+ "upd_off": " AUTO-UPDATE is OFF (the user opted out, sticky) - do NOT click Fusion's update prompts for them.",+ "stale_template": "STALE add-in: Fusion is running add-in v{reported} but this bridge bundles v{expected}. Newer verbs (e.g. fusion_aps_open/open_by_urn) can fail silently. Fix: fusion_stop then fusion_start - the bridge re-syncs the add-in from its cache on start (only possible with Fusion CLOSED).",+ "roundtrip_note_prefix": " NOTE: ",+ "roundtrip_note": "the add-in's HTTP server is up but its main thread did not execute a test command yet - not drivable this second",+ "upd_applied_template": " AUTO-UPDATE: Fusion was offering an update and I clicked {button} for the user IN THE BACKGROUND - it downloads now and the new build comes up on the next launch. TELL THE USER it is handled; they never need to click the nag. They can opt out with fusion_set_auto_update {enabled:false} (sticky).button",+ "fusion_update_hint_handled": "Fusion offered an update and it was clicked in the background - tell the user it is handled.",+ "fusion_update_hint_pending_template": "Fusion is OFFERING AN UPDATE (auto-update {state}). OFFER to run it: fusion_set_auto_update {enabled:true} or a one-off background click on the next sweep."+}
rust/core/tests/golden/readiness.jsonadded+830@@ -0,0 +1,830 @@+{+ "installed_not_running": {+ "inputs": {+ "addin": null,+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": false,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {},+ "result": {+ "_hint": "Fusion is INSTALLED but not running - call fusion_start (blocks until the add-in is ready), then retry.",+ "bridgeVersion": "TEST",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "ready": false,+ "running": false,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "installing": {+ "inputs": {+ "addin": null,+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": false,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": false,+ "streaming": true,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {},+ "result": {+ "_hint": "Fusion install is STREAMING (10-30 min) - keep polling fusion_readiness until installed:true.",+ "bridgeVersion": "TEST",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": false,+ "installing": true,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "ready": false,+ "running": false,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "licensing": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": true,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "launchStartedAt": 1800000000.0+ },+ "result": {+ "_hint": "Fusion is blocked by a SEAT/LICENSING dialog ('Active Sessions Exceeded' / 'Suspend Remote Session') - detected DETERMINISTICALLY as an OWNED POPUP of the main Fusion window (its title is just 'Fusion360' and it can be as short as 262px, so it is found by owner+parent-screenshot, NOT a size guess). This verb JUST TRIED to auto-resolve it in the BACKGROUND (UIA 'Continue', Suspend pre-selected so it reclaims the seat) but it is still up - it may be mid-render (the first UIA Invoke no-ops). Just POLL fusion_readiness again in a few seconds; it keeps auto-resolving. Never coordinate-click or ask the user, and never kill/relaunch (the server keeps the seat).",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "licensingDialog": true,+ "modelingOrientation": null,+ "progress": {+ "confidence": "measured",+ "elapsedSec": 30,+ "estimatedSec": 45,+ "etaSec": 15,+ "overdue": false,+ "percent": 40,+ "phase": "launch",+ "startKind": "cold",+ "stepLabel": "Clearing the Autodesk seat dialog"+ },+ "ready": false,+ "running": true,+ "statusVerb": "fusion_readiness",+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "needs_signin": {+ "inputs": {+ "addin": null,+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Signing in - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "launchStartedAt": 1800000000.0+ },+ "result": {+ "_hint": "Fusion is RUNNING but stuck at the first-run Autodesk SIGN-IN (main UI blocked, add-in cannot serve) - NOT ready. FULL PLAYBOOK: the `fusion-autodesk-signin` skill. Proven sequence + the pitfalls that cost hours on a fresh Hyper-V VM (John 2026-07-14): (1) BLANK white webview on first launch? fusion_stop then fusion_start - the sign-in renders 'Welcome to Fusion' + a 'Sign In' button only after a clean relaunch. (2) ASK the user FIRST (AskUserQuestion): do they have a warm Google/Apple/Microsoft session for the account LINKED to their Autodesk login? Offer to drive it. A truly fresh box has NO warm browser session, so 'Continue with Google' still hits a password wall. (3) Click Fusion 'Sign In' -> it opens the DEFAULT browser (Edge) to the OAuth. Edge windows DO exist even if PowerShell EnumWindows looks empty - that is CLIXML progress noise; set $ProgressPreference='SilentlyContinue', and just desktop_screenshot_window the Edge hwnd (PrintWindow works backgrounded). (4) In the browser: 'Continue with Google' -> type the user's EMAIL (not secret) -> if it asks for a PASSWORD/2FA, STOP and fusion_notify_owner {title, body} to toast their MAIN computer so THEY type it; NEVER enter password/2FA yourself. (5) Handoff back to Fusion is via the 'Autodesk Identity Manager' protocol - Edge shows a 'This site is trying to open...' overlay: tick 'Always allow' + click 'Open'. (6) SPEED MATTERS: the sign-in code EXPIRES in ~2 min; on a high-latency VM slow screenshot/click round-trips let it expire ('Sign-in request expired') and you loop. Minimize steps; if it expires, click Fusion 'Sign In' again for a FRESH code (the browser session stays warm). Then poll until ready:true. FIRST-TIME DEMO? Run fusion_demo instead - it drives this sign-in through the user's NATIVE browser (already signed into Autodesk) and then gives them a real guided tour (project -> schematic -> 2D board -> 3D board).",+ "bridgeVersion": "TEST",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "needsSignin": true,+ "progress": {+ "confidence": "measured",+ "elapsedSec": 30,+ "estimatedSec": 45,+ "etaSec": 15,+ "overdue": false,+ "percent": 40,+ "phase": "launch",+ "startKind": "cold",+ "stepLabel": "Signing in to Autodesk"+ },+ "ready": false,+ "running": true,+ "statusVerb": "fusion_readiness",+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "not_installed": {+ "inputs": {+ "addin": null,+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": false,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": false,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {},+ "result": {+ "_hint": "Fusion 360 is NOT installed. OFFER to install it for the user, then call fusion_install_fusion (no shell approval needed) - it streams the free trial and this verb reports installing:true until done.",+ "bridgeVersion": "TEST",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": false,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "ready": false,+ "running": false,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_after_launch": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {+ "launchHealAttempts": 1,+ "launchStartedAt": 1799999960.0+ },+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "launchHealAttempts": 0,+ "launchHealedAt": null,+ "launchStartedAt": null+ },+ "result": {+ "_hint": "READY - drive Fusion (fusion_open_lbr / build_library_3d / etc.). APS cloud search is signed in too, so use fusion_aps_search for ~2s cloud lookups. Autodesk's MCP server is OFF - fusion_mcp_enable can turn it on for the user (~10s, drives the Preferences dialog).",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "modelingOrientation": null,+ "ready": true,+ "running": true,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_configured": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": true,+ "apsSignedIn": false,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "launchHealAttempts": 0,+ "launchHealedAt": null+ },+ "result": {+ "_hint": "READY to drive Fusion, but APS CLOUD SEARCH IS NOT SIGNED IN - cloud file search will be slow/blocked. DO IT NOW, do not make the user log in a second time: call fusion_aps_signin RIGHT AFTER a Fusion sign-in, while the browser profile still has a warm Autodesk SSO session - it consents silently (no password, no 2FA). Then fusion_aps_search works. Autodesk's MCP server is OFF - fusion_mcp_enable can turn it on for the user (~10s, drives the Preferences dialog).",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "modelingOrientation": null,+ "ready": true,+ "running": true,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_roundtrip_fail": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": false,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "launchStartedAt": 1800000000.0+ },+ "result": {+ "_hint": "READY - drive Fusion (fusion_open_lbr / build_library_3d / etc.). APS cloud search is signed in too, so use fusion_aps_search for ~2s cloud lookups. Autodesk's MCP server is OFF - fusion_mcp_enable can turn it on for the user (~10s, drives the Preferences dialog). NOTE: the add-in's HTTP server is up but its main thread did not execute a test command yet - not drivable this second",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "progress": {+ "confidence": "measured",+ "elapsedSec": 30,+ "estimatedSec": 45,+ "etaSec": 15,+ "overdue": false,+ "percent": 40,+ "phase": "launch",+ "startKind": "cold",+ "stepLabel": "Fusion is up - waiting for the Adom add-in to serve"+ },+ "ready": false,+ "running": true,+ "statusVerb": "fusion_readiness",+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_signed": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "launchHealAttempts": 0,+ "launchHealedAt": null+ },+ "result": {+ "_hint": "READY - drive Fusion (fusion_open_lbr / build_library_3d / etc.). APS cloud search is signed in too, so use fusion_aps_search for ~2s cloud lookups. Autodesk's MCP server is OFF - fusion_mcp_enable can turn it on for the user (~10s, drives the Preferences dialog).",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "modelingOrientation": null,+ "ready": true,+ "running": true,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_signed_mcp": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": true,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "launchHealAttempts": 0,+ "launchHealedAt": null+ },+ "result": {+ "_hint": "READY - drive Fusion (fusion_open_lbr / build_library_3d / etc.). APS cloud search is signed in too, so use fusion_aps_search for ~2s cloud lookups. Autodesk's MCP server is LIVE (fusion_mcp_* verbs work).",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "modelingOrientation": null,+ "ready": true,+ "running": true,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_stale": {+ "inputs": {+ "addin": "1.0.16",+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "launchHealAttempts": 0,+ "launchHealedAt": null+ },+ "result": {+ "_hint": "STALE add-in: Fusion is running add-in v1.0.16 but this bridge bundles v1.0.19. Newer verbs (e.g. fusion_aps_open/open_by_urn) can fail silently. Fix: fusion_stop then fusion_start - the bridge re-syncs the add-in from its cache on start (only possible with Fusion CLOSED).",+ "_staleHint": "STALE add-in: Fusion is running add-in v1.0.16 but this bridge bundles v1.0.19. Newer verbs (e.g. fusion_aps_open/open_by_urn) can fail silently. Fix: fusion_stop then fusion_start - the bridge re-syncs the add-in from its cache on start (only possible with Fusion CLOSED).",+ "addinStale": true,+ "addinVersion": "1.0.16",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "modelingOrientation": null,+ "ready": true,+ "running": true,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_unconfigured": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": false,+ "apsSignedIn": false,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "launchHealAttempts": 0,+ "launchHealedAt": null+ },+ "result": {+ "_hint": "READY to drive Fusion. APS cloud search is NOT SET UP (no client ID) - cloud search is the slow path without it. Offer to set it up: fusion_aps_set_client_id then fusion_aps_signin (silent while the browser SSO session is warm). APS is how cloud search gets to ~2 seconds. Autodesk's MCP server is OFF - fusion_mcp_enable can turn it on for the user (~10s, drives the Preferences dialog).",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "modelingOrientation": null,+ "ready": true,+ "running": true,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "ready_upd_off": {+ "inputs": {+ "addin": "1.0.19",+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": false,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "launchHealAttempts": 0,+ "launchHealedAt": null+ },+ "result": {+ "_hint": "READY - drive Fusion (fusion_open_lbr / build_library_3d / etc.). APS cloud search is signed in too, so use fusion_aps_search for ~2s cloud lookups. Autodesk's MCP server is OFF - fusion_mcp_enable can turn it on for the user (~10s, drives the Preferences dialog). AUTO-UPDATE is OFF (the user opted out, sticky) - do NOT click Fusion's update prompts for them.",+ "addinStale": false,+ "addinVersion": "1.0.19",+ "bridgeVersion": "TEST",+ "expectedAddinVersion": "1.0.19",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": "2026-09-03T14:00:00",+ "lastSignedInAt": "2026-09-03T14:00:00",+ "modelingOrientation": null,+ "ready": true,+ "running": true,+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "running_addin_silent": {+ "inputs": {+ "addin": null,+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "launchStartedAt": 1800000000.0+ },+ "result": {+ "_hint": "Fusion is RUNNING but its add-in is NOT responding yet - NOT ready to drive. Either it is still finishing launch / signing in (poll fusion_readiness a few more times), or the add-in did not load (fusion_stop then fusion_start to re-deploy + re-load it). Do NOT fire modeling/export verbs until ready:true.",+ "bridgeVersion": "TEST",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "progress": {+ "confidence": "measured",+ "elapsedSec": 30,+ "estimatedSec": 45,+ "etaSec": 15,+ "overdue": false,+ "percent": 40,+ "phase": "launch",+ "startKind": "cold",+ "stepLabel": "Fusion is up - waiting for the Adom add-in to serve"+ },+ "ready": false,+ "running": true,+ "statusVerb": "fusion_readiness",+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "running_addin_silent_launching": {+ "inputs": {+ "addin": null,+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {+ "launchStartedAt": 1799999970.0+ },+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": false+ },+ "prefsAfter": {+ "launchStartedAt": 1799999970.0+ },+ "result": {+ "_hint": "Fusion is RUNNING but its add-in is NOT responding yet - NOT ready to drive. Either it is still finishing launch / signing in (poll fusion_readiness a few more times), or the add-in did not load (fusion_stop then fusion_start to re-deploy + re-load it). Do NOT fire modeling/export verbs until ready:true.",+ "bridgeVersion": "TEST",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "progress": {+ "confidence": "measured",+ "elapsedSec": 30,+ "estimatedSec": 45,+ "etaSec": 15,+ "overdue": false,+ "percent": 40,+ "phase": "launch",+ "startKind": "cold",+ "stepLabel": "Fusion is up - waiting for the Adom add-in to serve"+ },+ "ready": false,+ "running": true,+ "statusVerb": "fusion_readiness",+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ }+ }+ },+ "updating": {+ "inputs": {+ "addin": null,+ "apsConfigured": true,+ "apsSignedIn": true,+ "autoUpdate": true,+ "installed": true,+ "licensing": false,+ "mcp": false,+ "now": 1800000000.0,+ "prefs": {},+ "roundtrip": true,+ "running": true,+ "streaming": false,+ "title": "Home - Autodesk Fusion",+ "updating": true+ },+ "prefsAfter": {+ "launchStartedAt": 1800000000.0+ },+ "result": {+ "_hint": "Fusion is applying an AUTO-UPDATE (multiple webdeploy builds present) and RESTARTS ITSELF every ~30-60s - this is NOT a crash or a bridge failure. Poll fusion_readiness; it stabilizes to ready:true once the update finishes (can take 10-30 min). Meanwhile, wrap modeling/export verbs in a short retry/catch-loop to ride the up-windows rather than treating an intermittent 'not running' as fatal.",+ "bridgeVersion": "TEST",+ "fusionUser": null,+ "hostApp": "Fusion 360",+ "installed": true,+ "installing": false,+ "kicadIngest": false,+ "lastReadyAt": null,+ "lastSignedInAt": null,+ "modelingOrientation": null,+ "progress": {+ "confidence": "measured",+ "elapsedSec": 30,+ "estimatedSec": 45,+ "etaSec": 15,+ "overdue": false,+ "percent": 40,+ "phase": "launch",+ "startKind": "cold",+ "stepLabel": "Applying a Fusion auto-update"+ },+ "ready": false,+ "running": true,+ "statusVerb": "fusion_readiness",+ "success": true,+ "timings": {+ "cold": {+ "count": 4,+ "lastAt": "2026-09-01T10:00:00",+ "p50": 45.0,+ "p90": 53.0+ }+ },+ "updating": true+ }+ }+}
rust/core/tests/readiness_golden.rsadded+46@@ -0,0 +1,46 @@+//! Every scenario in tests/golden/readiness.json was produced by the Python handler with its+//! helpers stubbed; the Rust computation must return the same result and the same prefs.+use fusion_core::readiness::{compute, Inputs};+use serde_json::{json, Map, Value};+use std::fs;++fn inputs_from(sc: &Value) -> Inputs {+ let i = &sc["inputs"];+ let prefs: Map<String, Value> = i["prefs"].as_object().cloned().unwrap_or_default();+ Inputs {+ installed_raw: i["installed"].as_bool().unwrap(), streaming: i["streaming"].as_bool().unwrap(), running: i["running"].as_bool().unwrap(),+ addin_version: i["addin"].as_str().map(str::to_string), expected_addin_version: "1.0.19".into(),+ needs_signin: { let t = i["title"].as_str().unwrap_or("").to_lowercase(); t.contains("signing in") || t.contains("welcome to fusion") || (t.contains("sign in - autodesk") && t.contains("fusion")) },+ licensing_dialog: i["licensing"].as_bool().unwrap(), updating: i["updating"].as_bool().unwrap(),+ aps_configured: i["apsConfigured"].as_bool().unwrap(), aps_signed_in: i["apsSignedIn"].as_bool().unwrap(),+ mcp_port_open: i["mcp"].as_bool().unwrap(), auto_update_enabled: i["autoUpdate"].as_bool().unwrap(), roundtrip_ok: i["roundtrip"].as_bool().unwrap(),+ kicad_ingest: false, fusion_user: None, modeling_orientation: None, bridge_version: "TEST".into(),+ prefs, now: i["now"].as_f64().unwrap(), now_iso: "2026-09-03T14:00:00".into(),+ timings_launch: json!({"cold": {"p50": 45.0, "p90": 53.0, "count": 4, "lastAt": "2026-09-01T10:00:00"}}),+ launch_stats: json!({"p50": 45.0, "p90": 53.0, "count": 4}),+ progress_override: Some(json!({"phase": "launch", "stepLabel": "", "percent": 40, "elapsedSec": 30, "estimatedSec": 45, "etaSec": 15, "confidence": "measured", "startKind": "cold", "overdue": false})),+ addin_start_failed: None, crash_dialogs_cleared: 0, update_applied_button: None, update_offered: false,+ }+}++#[test]+fn readiness_matches_the_python_handler_in_every_scenario() {+ let g: Value = serde_json::from_str(&fs::read_to_string(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/golden/readiness.json")).unwrap()).unwrap();+ let mut n = 0;+ for (name, sc) in g.as_object().unwrap() {+ let out = compute(&inputs_from(sc));+ let want = &sc["result"];+ let mut got = out.result.clone();+ // fusionUser is a live cache in Python; both are null in the goldens+ if got != *want {+ let (a, b) = (got.as_object_mut().unwrap(), want.as_object().unwrap());+ for k in a.keys().cloned().collect::<Vec<_>>().iter().chain(b.keys()) {+ if a.get(k) != b.get(k) { panic!("{name}: key {k}\n rust: {}\n python: {}", a.get(k).map(|v| v.to_string()).unwrap_or("<absent>".into()), b.get(k).map(|v| v.to_string()).unwrap_or("<absent>".into())); }+ }+ }+ let want_prefs: Map<String, Value> = sc["prefsAfter"].as_object().cloned().unwrap_or_default();+ assert_eq!(Value::Object(out.prefs_after.clone()), Value::Object(want_prefs), "{name}: prefs after");+ n += 1;+ }+ assert!(n >= 16, "{n} scenarios");+}