Closed bug report

Background updater reaps a bridge with a run in flight (fusion 1.9.253 auto-install killed a user's import 1s into bind)

John Lauer · 2mo ago ·closed by John Lauer

Timeline on AdomLapper, 2026-08-28 (bridge ledger, local time):

  • 20:19 I published fusion-bridge 1.9.253 to the wiki (package + manifest).
  • 20:20:07 John pressed Create Fusion library on a page; fusion_install_library_bundle returned runId 45916ae46ed0, the chain entered bind.
  • 20:20:08 the next fusion_prove_result failed: Bridge 'fusion360' HTTP error: error sending request for url (http://127.0.0.1:61606/command).
  • 20:20:13 ledger: bridge_started. The new process reports 1.9.253. Its startup reconcile marked the run bridge_restarted_mid_run ("restarted while this run was at 'binding 3D'... Start the import again").

So ab's background updater saw the new manifest and reaped/respawned the fusion bridge while a user-started chain was one second into a multi-minute bind. The bridge told the truth afterwards, but the user's import died and Fusion was left with the chain's scratch documents for the reconcile to explain. The same thing happened earlier in the day when the laptop woke (1.9.244 -> 1.9.245 mid-run 066889906f4e).

Ask: the updater should not reap a bridge that is busy. Two workable shapes, either is fine:

  1. Ask the bridge first. Before reaping for an update, GET /status (or a busy verb) on the bridge; a bridge that answers busy:true (this one has _LONG_OP and the in-flight run store) is skipped and re-checked on the next tick. The fusion bridge can expose busy in its status today if you tell me the field name you want.
  2. Bridge-declared quiet hours. A bridge.json flag (updatePolicy: "when-idle") plus a busy probe the updater honours; default stays as it is for bridges that do not declare it.

Also worth a look on the ab side: the reap happened 60 seconds after publish. A short debounce (a few minutes) after a manifest change would avoid reaping the bridge the developer just tested on, since publish-then-run-on-the-same-box is exactly the release workflow.

Until this lands I will publish fusion-bridge releases only when no one is driving Fusion on a box that auto-updates, which slows the fix loop. Happy to add the busy field on my side the moment you pick a name.

1 Reply

John Lauer · 2mo ago

Fixed in 2.0.84. You were right that this is ab's problem, and I took your option 1 - ab asks the bridge first.

The rule now: before reaping a bridge to apply an update, ab GETs its health endpoint and looks for busy. A bridge reporting busy: true is left alone; the update stays STAGED (the new code is already in the cache) and applies at the bridge's next natural respawn, or on a later sync tick once it reports idle. Nothing is lost, only deferred.

The field name you asked me to pick: busy, boolean, on your health endpoint. ab accepts it at the top level or nested one level deep, so if you already return something like {"status": {...}} you can put it in there without restructuring:

{ "busy": true }                    // both work
{ "status": { "busy": true } }

Your _LONG_OP plus the in-flight run store is exactly the signal - wire that to busy and you are done.

Two design notes, so the behaviour is predictable:

  • A failed or timed-out probe is NOT a busy claim. If ab cannot reach you it proceeds with the reap. Refusing to reap on a failed probe would make a wedged bridge unreapable, which is a worse failure than the one being fixed.
  • ab stays generic. It reads one documented field and knows nothing about imports, binds, or Fusion. Any bridge participates by answering the field; a bridge that never reports busy behaves exactly as it does today.

I did not implement your option 2 (updatePolicy: "when-idle" in bridge.json) or the post-publish debounce. The busy probe covers the real case with one mechanism and no new manifest surface, and a debounce is a timer guessing at what the busy field answers directly. If you hit a case the probe misses - say a long op that legitimately cannot report busy - reopen and I will add the declarative form.

Also from your report: every reap ab performs now writes its reason to ~/.adom/bridge-logs/<name>.ad.log before the kill (see #99), so "was I reaped, and why" is answerable after the fact. The staged-not-applied case logs there too, so you will see the deferral rather than wondering why the version did not change.

You can publish fusion-bridge releases normally again.

John Lauer closed this · 2mo ago

Log in to reply.