NA-Ingest could not list a single audio interface.
The module had been installed from the catalog, which ships source only because the capture binary is gitignored. The admin page's device picker shells out to that binary with --list, so it returned nothing:
[spl-meter] device list failed: spawn .../spl-capture ENOENT
The missing-binary build already existed, but only inside the listener — and the listener only starts once a device has been picked. No tool meant no device list, and no device meant no listener to build the tool. Nothing was going to break that cycle on its own, which makes this a trap for every future catalog install rather than a one-off on one machine.
The fix
The build moved to module scope and both callers use it:
init() asks for it on mount, whether or not a device is configured
/devices asks again on every call, so simply opening the admin page starts it
It is still a plain non-blocking spawn — that part was fixed in 0.4.0 after a spawnSync copied from the LTC listener froze the whole server for two minutes on AB. health() now names the situation too, rather than leaving an empty dropdown unexplained.
While moving it I found two per-listener build flags left shadowing the new module-scope ones. They would have made the "is a build already running" test always false and allowed a second build to start under the first.
Tested the way it failed
A data directory holding only the six source files and no binary, exactly as a catalog install arrives. The build starts on mount and /devices answers with the real device list moments later.
Deployed to both machines: NA now lists 4 interfaces, AB lists 12.
NA-Ingest could not list a single audio interface.
The module had been installed from the catalog, which ships source only because the capture binary is gitignored. The admin page's device picker shells out to that binary with `--list`, so it returned nothing:
```
[spl-meter] device list failed: spawn .../spl-capture ENOENT
```
The missing-binary build already existed, but only inside the listener — and the listener only starts once a device has been picked. **No tool meant no device list, and no device meant no listener to build the tool.** Nothing was going to break that cycle on its own, which makes this a trap for every future catalog install rather than a one-off on one machine.
## The fix
The build moved to module scope and both callers use it:
- `init()` asks for it on mount, whether or not a device is configured
- `/devices` asks again on every call, so simply opening the admin page starts it
It is still a plain non-blocking `spawn` — that part was fixed in 0.4.0 after a `spawnSync` copied from the LTC listener froze the whole server for two minutes on AB. `health()` now names the situation too, rather than leaving an empty dropdown unexplained.
While moving it I found two per-listener build flags left shadowing the new module-scope ones. They would have made the "is a build already running" test always false and allowed a second build to start under the first.
## Tested the way it failed
A data directory holding only the six source files and no binary, exactly as a catalog install arrives. The build starts on mount and `/devices` answers with the real device list moments later.
Deployed to both machines: NA now lists 4 interfaces, AB lists 12.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
NA could not list a single audio interface. The module was installed from
the catalog, which ships source only because the capture binary is
gitignored, and the picker shells out to that binary with --list. So it
returned nothing, forever:
[spl-meter] device list failed: spawn .../spl-capture ENOENT
The missing-binary build existed, but only inside the listener, and the
listener only starts once a device has been picked. No tool meant no device
list, and no device meant no listener to build the tool. Nothing was going
to break that on its own.
The build now lives at module scope and both callers use it: init() asks for
it on mount whether or not a device is configured, and /devices asks again
each time it is called, so opening the admin page is enough to start it. It
is still a plain spawn that never touches the event loop, and health() now
names the situation instead of leaving an empty dropdown unexplained.
Also removed two per-listener build flags left shadowing the module-scope
ones, which would have made the "is a build already running" test always
false and let a second build start under the first.
Tested the way it actually failed: a data directory holding only the six
source files, no binary. The build starts on mount and /devices answers with
the real device list moments later.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
NA-Ingest could not list a single audio interface.
The module had been installed from the catalog, which ships source only because the capture binary is gitignored. The admin page's device picker shells out to that binary with
--list, so it returned nothing:The missing-binary build already existed, but only inside the listener — and the listener only starts once a device has been picked. No tool meant no device list, and no device meant no listener to build the tool. Nothing was going to break that cycle on its own, which makes this a trap for every future catalog install rather than a one-off on one machine.
The fix
The build moved to module scope and both callers use it:
init()asks for it on mount, whether or not a device is configured/devicesasks again on every call, so simply opening the admin page starts itIt is still a plain non-blocking
spawn— that part was fixed in 0.4.0 after aspawnSynccopied from the LTC listener froze the whole server for two minutes on AB.health()now names the situation too, rather than leaving an empty dropdown unexplained.While moving it I found two per-listener build flags left shadowing the new module-scope ones. They would have made the "is a build already running" test always false and allowed a second build to start under the first.
Tested the way it failed
A data directory holding only the six source files and no binary, exactly as a catalog install arrives. The build starts on mount and
/devicesanswers with the real device list moments later.Deployed to both machines: NA now lists 4 interfaces, AB lists 12.
🤖 Generated with Claude Code