fusion_start returns success:true with addinConnected:false, contradicting its documented block-until-ready contract

John Lauer · 2mo ago ·closed by John Lauer

fusion_start returns success: true with addinConnected: false, while fusion_readiness tells the truth in the same second

Measured on AdomLapper just now (ab 2.0.74, fusion-bridge 1.9.90, Fusion 360 running, add-in not loaded):

fusion_start {}
  -> success:        true
     addinConnected: FALSE
     alreadyRunning: true
     output:         "Fusion 360 is already running."

fusion_readiness {}          (same state, seconds apart)
  -> success: true
     ready:   FALSE
     _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)."

fusion_readiness is exactly right: honest verdict, both plausible causes, and the precise remedy. That hint is what unblocked me.

fusion_start is the problem. Its own contract says it blocks until ready, and fusion_get_app_state's hint tells the caller to rely on that:

"Call fusion_start to start Fusion 360, then wait for the add-in to become ready (fusion_start blocks until ready). Then retry this command."

So a caller does the documented thing, gets success: true, retries its real command, and fails - because the add-in was never connected. It reports the truth in addinConnected while contradicting it in success, which is the worst combination: the field a caller checks says yes, the field that matters says no.

How it cost me

A 10-part matrix through ab's web-control demo. Fusion had just been restarted, so the add-in was not loaded. Each card called the show verb, hit not-responding, auto-called fusion_start, got success: true, retried, and failed again. Two cells burned ~100s each before I stopped it. Without fusion_readiness I would have concluded the show verbs were broken.

The ask

success should reflect the postcondition the verb promises. Either:

  1. Block for real - do not return until addinConnected: true or a timeout, and return success: false with the readiness hint on timeout; or
  2. Stop promising - if alreadyRunning and the add-in is not connected, return success: false, errorCode: "fusion_addin_not_connected" carrying the same remedy fusion_readiness gives.

(1) matches the documented contract; (2) is honest and cheaper. Either beats today.

The alreadyRunning: true path looks like where it slips: the verb sees the process up and returns success without ever checking the add-in it claims to wait for.

This is the same class as the false success you fixed in adom/kicad-bridge#42, and as your own #36. A hard failure is recoverable because the caller reacts; a false success is not, because nothing has a reason to look again. Your fusion_host_hung work from #38 was exactly the right instinct applied to the neighbouring case.

Also worth noting the pair works well together right now: fusion_readiness is a genuinely good verb and its hint named both causes and the fix. If fusion_start simply deferred to it before returning, this would be closed.

1 Reply

John Lauer · 2mo ago

Fixed in 1.9.93, and you were right that this is the worst combination - the field a caller checks saying yes while the field that matters says no.

Cause: fusion_start's WARM path returned success: true whenever Fusion was already running, regardless of addin_ok. 1.9.88 hardened the cold loop and fusion_readiness with a real command round-trip, and stopped one line short of this early return - so the fix landed everywhere except the path your matrix actually took.

Now, per the doctrine: "running but no add-in" cannot be fixed by waiting, because the add-in only loads AT LAUNCH. So the warm path force-restarts Fusion and falls through to the cold path rather than reporting a cheerful false positive. Verified on AdomLapper:

fusion_start  ->  success: true   addinConnected: true   startKind: warm   (2s)

One thing worth flagging, because my first fix was wrong. 1.9.92 made the warm path restart Fusion, and the whole verb then ran past ab's 90s window and returned timed_out. That is not a fix - the caller is still blocked, just differently. The relay budget was being measured from the cold section rather than from function entry, so the warm probe and the restart were spent before the clock started. 1.9.93 measures from entry and returns stillLaunching inside the window with progress and statusVerb. Worth remembering generally: when a verb grows a remediation step, its budget has to grow backwards to cover it, or you trade a wrong answer for no answer.

Closing. #40 is answered separately.

John Lauer closed this · 2mo ago
Drew Owens mentioned this in pull request #40 · 6d ago

Log in to reply.