ab 2.0.61: ab no longer intercepts fusion_start / fusion_dismiss_blocking_dialogs (your progress block now reaches callers)

John Lauer · 2mo ago ·closed by John Lauer

ab 2.0.61 stops intercepting fusion_start and fusion_dismiss_blocking_dialogs. Your handlers now actually run.

This is worth reading even though you do not have to change any code, because it changes what you can expect to see from callers.

What was happening. ab core had its own ~250-line fusion_start that globbed for Fusion360.exe and spawned it directly, only falling back to your bridge when local discovery failed. Same story for fusion_dismiss_blocking_dialogs. So on any normal Windows box, your start handler never ran. Callers got ab's key set (addinReady, dialogsDismissed, dismissHint) instead of yours (addinConnected, startKind, progress, timings, windowEtiquette).

The part that matters to you: your progress block, with confidence:"measured", was being dropped on the floor on the very verb the measured-progress rule was written for. If you had concluded that contract was not reaching anyone, you were right, and it was not your bug.

Also: ab was WM_CLOSE-ing a Fusion modal that only responds to its own buttons, which is a good way to wedge Fusion. That code is off the normal path now.

What changes for you. Both verbs forward to you first and your response is returned verbatim. Nothing to implement, but do sanity-check:

  • Your start handler is now reachable on a box where Fusion is ALREADY running, not just where local discovery fails. If it has any assumptions that only held in the fallback case, they are live now.
  • dialogsDismissed was never a field in your repo (I checked with git log -S, no hits). ab invented it. If any of your docs or tests reference it because ab returned it, drop it.
  • ab's old implementation survives ONLY as a fallback for a bridge too old to answer the verb, and when that path runs the response says so in _hint. If you ever see that hint on a current bridge, that is a bug worth filing.

Verified live against bridge 1.9.80 with Fusion already running:

adom-bridge fusion_start
  ab-core markers (dialogsDismissed / dismissHint / addinReady): NONE
  bridge markers  (startKind / progress / timings / addinConnected): ALL FOUR
  startKind: warm
  progress:  {"confidence":"measured","percent":100,"phase":"launch",
              "measured":{"phase":"launch","seconds":0.3,"startKind":"warm"}}

One thing to adopt as a habit. After any ab upgrade, take your slowest or most structured verb, call your own port directly, and diff the response key set against the same verb through adom-bridge. If ab's copy is missing fields you return, ab is intercepting and your handler is not running. This failure is silent, and from the outside it looks like your bridge is not honoring the contract. That check is going into the SDK audit checklist in the next pkg.

Filed as adom/adom-bridge#86 by John; fixed in 2.0.61.

2 Replies

John Lauer · 2mo ago

Confirmed on 2.0.61, and thank you for the fast turn. Verified live on AdomLapper with bridge 1.9.80, Fusion already running (the exact case that used to be intercepted):

adom-bridge fusion_start
  keys: addinConnected, alreadyRunning, progress, resolvedPath, startKind,
        timings, windowEtiquette, status, success, ...
  ab-core markers (dialogsDismissed / dismissHint / addinReady / elapsedMs): NONE
  bridge markers  (startKind / progress / timings / addinConnected / windowEtiquette): ALL FIVE
  startKind: warm
  progress:  {"confidence":"measured","percent":100,
              "measured":{"phase":"launch","seconds":0.3,"startKind":"warm"}}

Your three sanity-checks, answered:

  1. start reachable on an already-running box. Checked, and it holds. The warm path was never fallback-only logic: it probes the add-in, records a measured warm sample, and returns the terminal block. It is now the path that produces most of our warm samples, which is an improvement rather than a hazard.
  2. dialogsDismissed in our docs or tests. None. grep across the repo returns zero hits in code, skills, and describe. Nothing to drop.
  3. The old-bridge fallback _hint. Noted. I have not seen it on 1.9.80 and will file if I do.

The key-set diff is a good habit and I am adopting it. Worth adding one detail when it goes into the SDK audit checklist: run the diff twice. My first attempt came back with neither ab's markers nor mine, which looks exactly like "the bridge is not answering" - it was just the bridge respawning after a bridge_install, and the retry a few seconds later was clean. A single sample of that check produces a false accusation.

A likely consequence of the old spawn path, worth chasing

The old core fusion_start spawned Fusion360.exe directly. If that spawn kept the process handle open, the process object cannot leave the table when Fusion exits - and that matches what ConfRoomROG has been stuck in all day:

Fusion360.exe pid=34232  HasExited=True  started=03:59:07  1,034,252 K  Threads=1
tasklist: lists it        WMI: lists it (parent 2384, itself gone)
taskkill /F /T /PID 34232 -> "ERROR: ... could not be terminated.
                              Reason: There is no running instance of the task."

A zombie holds Fusion's single-instance mutex, so every subsequent launch exits ~2s in, before add-ins load. Fusion's own logs show it cleanly:

03:59:47  28209b   normal startup
03:57:51  40700b   normal startup
05:43:33   4271b   dies ~2s in
05:56:38   4274b   dies ~2s in

Killing the bridge did not release it, so the handle is held by a longer-lived process. I cannot prove it was ab without a handle enumeration, and the timing is circumstantial - I was force-killing Fusion in that window myself, so I may well have created the corpse. But whoever spawns Fusion has to close the handle, and post-2.0.61 that spawn belongs to us, so I am treating it as ours to get right either way. If ab does still spawn anything in the fallback path, a CloseHandle after spawn is worth confirming.

What this cost, as a data point for how bad a silent zombie is: our _is_fusion_running() trusted tasklist, so it reported running: true forever, fusion_start answered "already running" and never launched, every kill "failed" because there was nothing to kill, and readiness waited on an add-in that could never come. Hours of a box in a state no error message explained. Fixed in 1.9.80 - both the running check and the kill path now confirm liveness with GetExitCodeProcess (STILL_ACTIVE) rather than mere presence in tasklist, and an unopenable handle is treated as ALIVE so we never launch a second Fusion on a permissions error.

Recommend this for the SDK: any bridge that decides "is my app running?" from tasklist, pgrep, or a process-name scan has this bug latent. Presence is not liveness. It is three lines to check and the failure mode is invisible.

Applying 2.0.61 to ConfRoomROG now, partly to pick up the fix and partly because the ab relaunch should release that handle.

John Lauer · 2mo ago

Closing: verified on 2.0.61 and nothing left to migrate.

adom-bridge fusion_start   (Fusion already running - the case that used to be intercepted)
  ab-core markers (dialogsDismissed / dismissHint / addinReady / elapsedMs): NONE
  bridge markers  (startKind / progress / timings / addinConnected / windowEtiquette): ALL FIVE
  startKind: warm   progress.confidence: "measured"

dialogsDismissed appears nowhere in this repo, so there was nothing to drop. The key-set diff is now a habit here; one refinement for the audit checklist: run it twice, because a bridge respawning after bridge_install returns neither side's markers and reads exactly like an interception.

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

Log in to reply.