Skip to content

feat(twitch): preserve accepted chat through local crashes#110852

Merged
steipete merged 2 commits into
mainfrom
claude/ingress-twitch
Jul 18, 2026
Merged

feat(twitch): preserve accepted chat through local crashes#110852
steipete merged 2 commits into
mainfrom
claude/ingress-twitch

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

Twitch chat messages accepted from IRC could be lost if the local process stopped after socket acceptance but before inbound dispatch completed.

Why This Change Was Made

Adds a Twitch-owned durable ingress queue that persists the raw callback envelope before dispatch, drains one channel lane serially, threads the adoption lifecycle into inbound handling, and recovers pending local work after restart.

Never-replay caveat: this transport does not redeliver after socket acceptance; dedupe tombstones are near-inert. The durable queue's value is crash-window durability between accept and dispatch, with local restart recovery.

User Impact

Twitch users get local recovery for accepted chat messages across a process crash in the accept-to-dispatch window. This does not provide end-to-end at-least-once delivery from Twitch and cannot recover a message that was never durably admitted locally.

Evidence

  • node scripts/run-vitest.mjs extensions/twitch: 20 files, 211 tests passed.
  • node scripts/run-vitest.mjs extensions/irc/src/client.test.ts extensions/irc/src/monitor.test.ts: 2 files, 18 real-socket tests passed.
  • Blacksmith Testbox dead-code proof: unused-file scans passed with 0 entries; production, full-tree, and script unused-export scans passed with 0 entries. https://github.com/openclaw/openclaw/actions/runs/29653485446
  • oxfmt 0.58.0 --check passed on all 11 touched files.
  • git diff --check origin/main...HEAD passed.
  • Mandatory autoreview against origin/main: clean, no accepted/actionable findings.

@openclaw-barnacle openclaw-barnacle Bot added channel: twitch Channel integration: twitch size: L maintainer Maintainer-authored PR labels Jul 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c08fbed8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

shutdown.abort(stoppedError());
await drainTask;
await Promise.allSettled(activeDeliveries);
await Promise.allSettled(deferredClaims.values());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not await unresolved deferred claims on stop

When a Twitch message is queued behind an active reply lane, core marks the source deferred (see markFollowupRunEnqueued in src/auto-reply/reply/queue/types.ts) and adoption/abandon may happen much later. This new stop path aborts the ingress and then waits on deferredClaims, but those promises are only resolved by the wrapped onAdopted/onAbandoned callbacks; if the queued turn is not admitted before shutdown, monitor.stop()/gateway abort can hang indefinitely instead of allowing the claimed row to be recovered by the next process.

Useful? React with 👍 / 👎.

@steipete
steipete merged commit e04ea79 into main Jul 18, 2026
107 checks passed
@steipete
steipete deleted the claude/ingress-twitch branch July 18, 2026 17:50

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34038604fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return;
}

void ingress.accept(message).catch((err: unknown) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Filter denied Twitch chat before durable admission

When the bot is connected to a public or busy channel where requireMention, allowFrom, roles, or bot-echo filtering reject most messages, this now sends every raw chat line through ingress.accept() before those gates run in the ingress deliver callback. That means unmentioned/denied messages are synchronously written to the durable SQLite queue and may persist raw chat across crashes, then drain serially just to be discarded; before this change the same filters ran before dispatch without a durable write. Prefiltering obvious non-dispatch messages before admission, while still rechecking on replay, avoids the disk churn/backlog and raw-message retention for traffic the plugin will never handle.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: twitch Channel integration: twitch maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant