v0.12.23 — Calendar auto-join discipline, and Teams CSRC transcription
Calendar-dispatched bots now follow a fixed, observable contract: dispatch at
start−2 min, wait up to 15 min in the lobby, retry genuine failures once per bounded
backoff inside the occurrence window, never re-arm a served or stopped meeting,
record under the same flag as manually started bots, and honour an explicit stop on
every path. Teams transcription routes the mixed audio into per-speaker windows from
the RTP transport's contributing sources; a speaker name stays provisional until the
roster has settled.
Calendar & scheduled bots
- Multiple calendar feeds, managed from the dashboard: named, independently synced
ICS connections; meetings deduplicate across feeds and keep every source visible
(#1150). - Bots dispatch two minutes before the scheduled start and wait up to fifteen
minutes to be admitted (#1210). - A failed auto-join retries on a bounded backoff, and the reason for the wait is
readable on the meeting (#1200). - A meeting already served or stopped is never re-armed; only genuine failures
retry, and only within their own occurrence window
(#1211). - An explicit stop is stop: stopping a scheduled meeting cancels it before
dispatch, a stop that races a starting bot leaves nothing running, and the stop
is recorded as the outcome (#1212). - Calendar auto-joined meetings are recorded like manually started ones
(#1217).
Teams
- CSRC transport activity routes the mixed audio into per-speaker transcription
windows with the same buffering contract as Google Meet
(#499 — attribution work; the
exactly-once oracle that issue asks for stays open). - A speaker name earned before the participant list is complete stays provisional
and is corrected as evidence accumulates — no more locking one person's words
under another's name (#1228). - Names resolve from Teams' stable
data-tidattributes instead of hashed CSS
classes; only themainAudiomix is transcribed, and double-mirrored tracks are
deduplicated (#1024).
Correctness & API surface
- One bot per meeting, even under concurrent requests; a request for a live
meeting adopts the running bot (#1185). - Self-hosted deployments fail closed when that guarantee cannot be enforced: the
admin service refuses to start without the unique index
(#1187). - API keys only do what their scope allows — scope is enforced on bot lifecycle
and user-config routes (#1236). - Meeting responses ship owner-private fields (webhook URL, delivery config) to
the owner and nothing sensitive to a transcript-share viewer
(#1243,
#1244). - Operator plumbing: admin identity by authoritative ID (#994), producer-observed
service provenance on completed meetings (#984), optional external service
authority (#988), signed system callback for terminal meeting facts (#992).
Infrastructure
- Every deploy surface — Lite, Compose, Helm — now runs
Valkey 8.1.9 instead of Redis
(#653). - Release promotion copies registry manifest bytes exactly and reads back every
frozen descriptor; nothing is rebuilt after the witness (#951).
Docs
New guides and honest-status pages: n8n (#1076), the
MCP server boundary (#1077), share-links and
interactive-bots status (#1078, #1086), hosted-runs-0.12 start-here (#954),
signal-driven redirects (#1111), and FunASR validation attributed to the upstream
maintainers who ran it (#928).
Getting it
Images are published multi-arch (linux/amd64 + linux/arm64) under
:v0.12.23, byte-identical to the witnessed release candidate
(v0.12.23-rc.21). Lite and Docker Compose build and run green at this source.
Upgrade notes
- Self-hosted with an existing database: the admin service now refuses to
start if the one-bot-per-meeting unique index is missing (#1187). Apply the
shipped schema migration before rolling this version; a fresh install needs
nothing. - The Redis→Valkey swap is transparent for stock deployments; custom images or
pinnedredis:*references need the new image name (#653). - The declared
api.v1surface has not been re-frozen for the routes added since
0.12.18; the reconciliation is tracked in
#1234.
Not claimed
- A transport-contested phrase on Teams is currently published under both
contributing tracks — detected and counted in pipeline health, not yet
resolved or marked in the public transcript (#499, documented in-repo as
deliberately unresolved). - Teams naming under heavy participant churn can still flap before settling;
hysteresis and a fully deterministic CSRC→name path are tracked (#1229, #1230). - Jitsi: the alone-leave timer and admitted→active lag have known residuals (#1214).
- A stop arriving before the meeting row exists is lost rather than remembered (#1213).
- Zoom: not updated in this release.
Credits
Jacob Schooley (@jbschooley) — Teams speaker-name
resolution from stable data-tid, mainAudio-only transcription and track
dedup, from #1024.
The FunASR maintainers (@LauraGPT) — upstream
validation of the FunASR/SenseVoice custom-STT path
(#928).