Skip to content

Biorouter v1.91.1

Choose a tag to compare

@Broccolito Broccolito released this 22 Sep 11:25

Biorouter v1.91.1

A reliability release. On Windows, Biorouter's own network sockets no longer leak into the
programs it starts. On macOS, an extension that starts from inline Python no longer
occasionally dies before it runs. Most of the rest is work on the test suite, so that a red
build means something is actually broken.

Windows: sockets no longer leak into child processes

On Windows, the async runtime Biorouter uses creates network sockets that any child process
inherits, and Biorouter starts children all day: extensions, shells, agents, coding-agent
CLIs. A child that outlived the socket that it inherited kept it open. The effects, all fixed:

  • A port stayed taken after Biorouter exited. If a child it had started was still
    running, the daemon's listening port (3000, BIOROUTER_PORT or serve --port) could not
    be bound again until that child exited. This applied to every listener: the daemon, the
    ACP websocket server, biorouter web, both OAuth callback servers and the two sign-up
    servers.
  • The remote tunnel could not close cleanly. When the daemon dropped its tunnel
    connection, on an idle reconnect or on exit, the relay was never told, because a child
    still held the socket.
  • The CLI's connections to a running daemon (session watch, attach, send, cancel,
    serve's readiness check, apps) now use the same non-inheritable sockets.

Nothing changes on macOS or Linux, where these sockets were already close-on-exec. The fix
was measured on a Windows CI runner: a child process kept an old-style listener's port
and connection open, and did not keep the new ones open. A build check now refuses any
production code that opens an inheritable socket, for the shipped Windows target as well as
Linux.

macOS: inline-Python extensions no longer fail to start

An extension defined as inline Python is started through uvx. On macOS that start could
very occasionally be killed by the operating system before it ran, leaving the extension
failed with an empty error. The cause is a macOS fork hazard: when a program name has to be
looked up on PATH, the process is started with fork rather than posix_spawn, and a
fork that coincides with another thread's first use of the system notification library is
aborted in the child. uvx is now resolved to its full path first, the way every other
extension command already was, and the daemon and CLI complete that library's one-time setup
at startup, before any other thread exists.

Smaller fixes

  • A blank BIOROUTER_PATH_ROOT is now ignored everywhere. The managed-policy path used to
    treat it as an empty prefix and resolve to a relative path.

For contributors

  • The CI flakes seen around v1.91.0 have root-cause fixes, each reproduced on purpose
    before being fixed, not re-run until green: the Windows bridge listener test, the
    AgentManager's first-run seeding root, a vitest teardown timer, the revoked native-call
    test, the diagnostics bundle picking up another test's logs, a tracing capture that could
    miss its own event, tests that relocated the shared path root while others read it, and a
    sidebar pagination test that counted other tests' chats, and the serve lifecycle tests
    racing other processes for the port they had reserved.
  • The lib and bin test binaries of biorouter, biorouter-server and biorouter-cli pin
    their storage roots before main, and their guards fail if a pin is removed (previously
    they passed with it deleted). Tests that must move the shared path root now do it in a
    process of their own.
  • scripts/check-non-inheritable-sockets.sh is a blocking CI step on Ubuntu and on the
    Windows cross-check.
  • release.sh publish now reads the draft's target commit back and refuses to publish unless
    it equals the commit the artifacts were built from.