v0.49.6

thevoiceguy/siphon-aiv0.49.6Aug 19, 2026by github-actions[bot]

Upgrading?

AI Summary

Fixes SIPp harness port collisions and SIP ladder eviction logic to protect live calls from scanner noise.

Key Highlights

  • SIPp harness now fails fast on port collisions instead of reporting 17 false failures.
  • Live calls are now a separate population, protected from eviction by scanner noise.
  • Added `[[trunk]]` rows to sightglass's trunks tab.

Full Release Notes

Everything a single load run turned up. The ring's own bounds held at
203 concurrent — nothing dropped, no warning logged — but the run
surfaced an eviction flaw waiting for a busier node, a trunk an operator
could not see, and a test harness that reported port collisions as
product regressions.

**Upgrade note:** this is the first release since 0.49.2 that changes
daemon behaviour, so unlike 0.49.5 it wants a restart to take effect.
No config change, no protocol change (WS stays version `"1"`), no CDR
change (still v8), and no dependency moved.

### Fixed

- **The SIPp harness now fails fast on a port collision instead of reporting one as 17 scenario failures.** Thirteen auxiliary phases hard-coded `9091` for their `[observability]` listener — the same port `configs/local-dev.toml` uses, and therefore the same port a daemon already running on the box is using. The daemon exited at startup with `Address already in use` and every affected phase reported as a *scenario* failure, which reads like a signalling regression: a local run scored 17 of 40 red on 2026-08-19, none of it real. `SIPHON_AI_CONFIG` only ever fixed the main phase, because the auxiliary phases generate their own configs. Every port the harness binds (`SIPP_PORT`, `DAEMON_PORT`, `ADMIN_API_PORT`, the new shared `AUX_OBS_PORT`, `ECHO_WS_PORT`) now reads from the environment, and a preflight check refuses to start on a busy TCP listener, naming the variable and a free port to use — the same treatment the missing-echo-server case already got, and for the same reason.


### Fixed

- **A live call's SIP ladder could be evicted by scanner noise.** The ring bounds its not-yet-completed traces least-recently-touched, but **an established call is SIP-silent between its ACK and its BYE** — its `last_touched` never advances, while rejected scanner INVITEs and REGISTER refreshes keep arriving with fresh ones. The live call was therefore the *oldest* entry and would be evicted **before** the transient noise the bound exists to contain, discarding the ladder of the call an operator is most likely to be looking at. Live calls are now a separate population, promoted when the control registry accepts the call, bounded separately at `MAX_LIVE = 512`, and never evicted to make room for noise. Found by the 0.49.5 load run (`test-harness/load/RESULTS-0.49.5-sip-ring.md`), which did not trip the bound at 203 concurrent but showed the trace-growth curve that makes it inevitable on a busier or longer-lived node.

### Added

- **`GET /admin/v1/trunks` and `[[trunk]]` rows in sightglass's trunks tab.** The tab showed only `[[register]]` bindings, so on a node with a registered PBX *and* an IP-authenticated carrier trunk, the carrier was simply absent — indistinguishable from a config mistake, and reported as exactly that confusion from a live session. Trunks have no credentials and no registration, hence no live state to poll, which is why DESIGN_SIGHTGLASS.md §6.6 deferred them; but "nothing to poll" is not a reason to render nothing. Trunk rows now list their peer CIDRs with a dim `ip-auth` marker and dashes where a registration would show state, so they never read as "up". Readonly role; active OPTIONS probing toward gateways remains the deferred part.

- **`test-harness/load/RESULTS-0.49.5-sip-ring.md`** — the ring shipped enabled-by-default in 0.49.3 and had never been load-tested. At 203 concurrent it dropped nothing at either bound, and the run also caught **47 of 250 calls dying on `ws_disconnect`**: the generator's WS server, not the daemon, and §1.4 of the load plan happening as written. Carries `ringstat.sh` into the harness.

---

**Artifacts**

- Static musl binaries for `x86_64` and `aarch64` (`.tar.gz`).
- Debian packages (`.deb`) for `amd64` and `arm64` — `apt install ./siphon-ai_*_amd64.deb`.
- `SHA256SUMS` — verify with `sha256sum -c SHA256SUMS`.
- `*-sbom.cdx.json` — CycloneDX SBOM.
- `SHA256SUMS.cosign.bundle` — cosign keyless signature over the checksums.
- Container: `ghcr.io/thevoiceguy/siphon-ai:v0.49.6` (multi-arch, cosign-signed).

Verify the checksums signature:
```
cosign verify-blob --bundle SHA256SUMS.cosign.bundle \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp 'release.yml@' SHA256SUMS
```

Related Repositories