Code: OneTimeRuntime.open in lib/src/remote/burrow/one-time-runtime.ts; its caller #openOneTime in lib/src/host/remote/service.ts, which stores the promise in #oneTimeOpening and returns it to every later open request while it is set.
Failure path: open() arms the ONE_TIME_OPEN_TIMEOUT_MS (8 s) deadline, then runs await generateNoiseKeyPair() before it returns the opened promise. If key generation stalls, the deadline still ends the runtime (unreachable) and the state settles, but open() itself does not return until key generation does. Until then the service's #oneTimeOpening stays set. Every later "One-time connection" click joins that stuck promise rather than opening a new runtime, and the panel cannot open a link until key generation completes or the host restarts. The phase guard after the await already stops a late socket, so the problem is only the hung promise.
Suggested fix: return opened without awaiting key generation inline. Run it as a detached step (void this.#mint()) that checks the phase after it settles, as the current guard does. To test it, inject a key generator that never resolves, advance the clock past ONE_TIME_OPEN_TIMEOUT_MS, and assert that open() resolves ended {reason: 'unreachable'} and that a second service open mints a new runtime.
Found while trimming #904, which had parked this as a spec "Known gap".
🤖 Generated with Claude Code
Code:
OneTimeRuntime.openinlib/src/remote/burrow/one-time-runtime.ts; its caller#openOneTimeinlib/src/host/remote/service.ts, which stores the promise in#oneTimeOpeningand returns it to every later open request while it is set.Failure path:
open()arms theONE_TIME_OPEN_TIMEOUT_MS(8 s) deadline, then runsawait generateNoiseKeyPair()before it returns theopenedpromise. If key generation stalls, the deadline still ends the runtime (unreachable) and the state settles, butopen()itself does not return until key generation does. Until then the service's#oneTimeOpeningstays set. Every later "One-time connection" click joins that stuck promise rather than opening a new runtime, and the panel cannot open a link until key generation completes or the host restarts. The phase guard after theawaitalready stops a late socket, so the problem is only the hung promise.Suggested fix: return
openedwithout awaiting key generation inline. Run it as a detached step (void this.#mint()) that checks the phase after it settles, as the current guard does. To test it, inject a key generator that never resolves, advance the clock pastONE_TIME_OPEN_TIMEOUT_MS, and assert thatopen()resolvesended {reason: 'unreachable'}and that a second service open mints a new runtime.Found while trimming #904, which had parked this as a spec "Known gap".
🤖 Generated with Claude Code