flybrain/infra/docs/release-v0.1.4.md
acamilo 660c3cf00d
Some checks failed
ci / node 22 (test + typecheck) (push) Has been cancelled
ci / rust stable (cargo test --workspace --release) (push) Has been cancelled
ci / infra/tests/lint.sh (push) Has been cancelled
ci / playwright apps/stage (allowed to fail) (push) Has been cancelled
flybrain v0.4.0: public tree (history retained privately)
2026-09-21 15:09:46 +00:00

28 lines
1.7 KiB
Markdown

# Release v0.1.4 — the chat bridge learns to heal itself, method
> **The record lives in the operator's infra repo** (`services/flybrain/release-v0.1.4.md`), verbatim and dated.
> This file keeps only what the run established.
The fifth tagged release, and the fourth deployed to a container that was already
broadcasting. Read `infra/docs/runbook.md`'s "Cutting a release" for the procedure, its
"Chat dead, bridge active" section for what this release ships, and
`docs/design/stage-bridge.md` section B5 for the design.
**v0.1.4 is the first release that changes `flybridge` and the first that restarts
`flypush`**, so it is the first one where the deploy could take chat or the push down
rather than just the sim.
What it shipped, and why: a connected EventSub websocket is **not** a working
subscription. Both sockets can drop, Twitch can refuse the re-created
`channel.chat.message` subscription with "number of websocket transports limit exceeded"
(429), and the bridge then sits `active (running)` with no chat subscription at all —
which is exactly what happened, for an hour. The bridge now exits 75 when that
subscription has been unconfirmed for `EVENTSUB_GRACE_MS`, and systemd restarts it with
a fresh transport; `NOTICE_MIN_INTERVAL_MS` keeps the self-healing restarts from turning
into chat spam. `chatSubscriptionHealthy` is the field to read — never
`eventSubConnected` on its own.
Two auth lessons from the same period, both now in the code: refresh **before** validating
a stored token (a broadcaster token that expired while a previous process held a fresher
one in memory fails startup with 401 in a crash loop), and persist refreshed tokens for
**both** roles when one account holds both.