v0.48.13

thevoiceguy/siphon-aiv0.48.13Aug 10, 2026by github-actions[bot]

Upgrading?

AI Summary

Maintenance release fixing memory leaks in SIP dialog management by implementing a deferred reaper.

Key Highlights

  • Fixed `DialogManager` memory leak where finished calls left dialogs in the store.
  • Implemented deferred reaper with a 32s grace window (Timer H/J).
  • Added `siphon_ai_dialogs_active` gauge.
  • Fixed RSS growth from ~2.1 KB/call to ~0.78 KB/call.

New Features

  • Dialog reaper mechanism to clean up completed dialogs.

Full Release Notes

### Fixed

- **Finished calls no longer leave their SIP dialog in the shared store forever** (issue #458). `sip-uas` inserts one confirmed dialog per accepted INVITE and siphon-ai never removed it, so `DialogManager` grew for the life of the process — the per-call RSS growth reported against 0.48.10. **The memory was the smaller half of the problem:** `sip-dialog` caps the store at `MAX_CONFIRMED_DIALOGS = 10_000` and `sip-uas` discards the resulting `insert` error (`let _ = ...`), so a daemon past ten thousand cumulative calls silently stops tracking new dialogs altogether — and in-dialog requests (BYE, re-INVITE, the post-REFER NOTIFY, transfer) resolve through exactly that store. At 10k calls/day that is a one-day fuse on a busy node, and nothing in the daemon reported it. Located with a `dhat` heap profile diffing a 100-call run against an 800-call run at constant concurrency: `DialogManager::insert` ← `sip_uas::accept_invite_with_session_timer` ← `BridgingAcceptor::on_matched`, ~976 B/call, with the retained dialog's contact URI and two transaction-metrics `String`s never freed alongside it. Ruled out on the way: metrics cardinality (series count flat at 60 across 4,000 calls), the call registry (empty after every batch), multi-arena glibc fragmentation (`MALLOC_ARENA_MAX=2` was marginally *worse*), untrimmed heap (aggressive `MALLOC_TRIM_THRESHOLD_` changed nothing), and the transaction map (genuinely bounded — it evicts oldest at `max_server_transactions`).
  - The fix is a **deferred reaper** (`crates/core/src/dialog_reaper.rs`) rather than a removal at teardown, because the dialog store is what in-dialog requests match against: dropping a dialog the moment its call ends would race the very BYE that ended it, and a peer retransmitting BYE after our `200 OK` must still get a `200`, not "unknown dialog". Teardown *retires* a `DialogId`; a sweeper removes it once a 32 s grace window (SIP Timer H/J — the BYE retransmission window) has passed. Within that window behaviour is exactly as before. The upstream `terminate()` + `cleanup_terminated()` pairing was the intended shape but is unusable from here — `DialogManager::get` returns a *clone*, so `Dialog::terminate()` marks a copy and leaves the stored dialog untouched.
  - New gauge **`siphon_ai_dialogs_active`**, sampled each sweep, because there was previously no way for an operator to watch this grow — the other half of why it went unnoticed. It should track `calls_active` lagging by the grace window.
  - Verified live over 4,000 calls at constant concurrency: `dialogs_active` returns to **0** after every batch (it previously grew 1:1 with call count), all 4,000 terminated `caller_hangup`, SIPp reported zero failures, and the daemon logged **no warnings and no `481`s** — the retransmitted-BYE path the deferral protects. Steady-state RSS growth after pool warm-up fell from ~2.1 KB/call to ~0.78 KB/call; the residue is allocator overhead and the bounded transaction map, not retained dialogs.

---

**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.48.13` (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