Skip to content

fix(webui): stop SSE reload retry storms - #7268

Merged
serrrfirat merged 1 commit into
mainfrom
codex/fix-sse-429-storm
Aug 6, 2026
Merged

serrrfirat merged 1 commit into
mainfrom
codex/fix-sse-429-storm

Conversation

@henrypark133

Copy link
Copy Markdown
Collaborator

Summary

  • Preserve the WebChat SSE connection identity and generation across genuine document reloads so the server supersedes a proxy-held predecessor instead of consuming another per-user slot.
  • Keep fresh and duplicated tabs on independent identities, validate persisted state, and rotate identity before generation exceeds JavaScript's safe integer range.
  • Mark failed/retrying handshakes as unavailable so the activity watchdog cannot race event-source-plus retry ownership.
  • Document and regression-test the reload, duplicated-tab, rollover, and 429-watchdog contracts.

Change Type

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • CI/Infrastructure
  • Security
  • Dependencies

Linked Issue

None — reproduced from an RC deployment report.

Validation

  • cargo fmt --all -- --check — Not applicable: no Rust files changed.
  • cargo clippy --all --benches --tests --examples --all-features -- -D warnings — Not applicable: no Rust files changed.
  • cargo build — Not applicable: frontend-only change; the production Vite build ran directly.
  • Relevant tests pass: corepack pnpm test (126 files, 1,093 tests).
  • cargo test --features integration — Not applicable: no database-backed behavior changed.
  • Manual testing: red-before/green-after hook regressions for reload supersession and competing 429 watchdog reconnect.
  • If a coding agent was used and supports it, review-pr or pr-shepherd --fix was run before requesting review.

Additional gates: corepack pnpm lint, corepack pnpm build with bundle budgets, git diff --check, eight focused review lanes, and a strict maintainability review.

Test Strategy

User behavior: Repeatedly refreshing WebChat no longer consumes independent per-user SSE slots, and a 429 handshake no longer leaves a competing activity-watchdog reconnect armed.

Risk areas:

  • Model behavior
  • Browser
  • Side effect
  • Persistence
  • Security or permissions
  • External provider
  • Cross-component behavior

Tests added or updated:

  • Unit or contract: frontend/src/pages/chat/lib/useSSE.test.ts
  • Reborn integration: Not applicable: no product/runtime orchestration changed.
  • Recorded fixture: Not applicable: no model behavior changed.
  • Browser E2E: Not applicable: the existing source-backed hook harness deterministically drives packaged transport callbacks, navigation timing, storage state, and request query shape.
  • Backend or runtime: Not applicable: server capacity and rate-limit behavior are intentionally unchanged and already covered by WebUI caller-level contracts.
  • Live canary: Not applicable: no live provider dependency.

What the tests prove:

  • A true document reload reuses the predecessor connection_id and increments its generation.
  • A fresh or duplicated tab gets an independent identity.
  • Malformed persisted state fails safely to a fresh identity.
  • Generation rollover rotates identity atomically before exceeding the safe integer limit.
  • A retrying 429 handshake clears the active-stream watchdog and does not launch a second reconnect owner.

Commands run:

  • corepack pnpm exec vitest run src/pages/chat/lib/useSSE.test.ts
  • corepack pnpm test
  • corepack pnpm lint
  • corepack pnpm build
  • git diff --check

Security Impact

None. Persisted values are a bounded opaque connection ID and monotonic generation only; bearer credentials remain in the Authorization header.

Reborn Trust-Boundary Checklist

N/A: frontend transport lifecycle only; no trust-bearing types, prompts, hashes, permissions, runtime variants, serialization contracts, or sandbox boundaries changed. Persisted reload state is shape-validated and bounded before use.

Database Impact

None.

Blast Radius

WebChat SSE connection lifecycle only. Fresh tabs remain independent; SPA thread changes retain one loaded-document identity; server concurrency and request-rate policies are unchanged.

Rollback Plan

Revert commit 2805a466ac. No schema, migration, or server compatibility rollback is required.

Review Follow-Through

One review finding identified the safe-integer generation boundary. The implementation now rotates identity and generation atomically in the per-request query, with dedicated regression coverage. Final review lanes were clean.


Review track: B (browser-facing bug fix)

@coderabbitai

coderabbitai Bot commented Aug 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0d5c8d5e-2826-4bbb-af73-370cf63f6f99

📥 Commits

Reviewing files that changed from the base of the PR and between 2816b0f and 2805a46.

📒 Files selected for processing (3)
  • crates/product/ironclaw_webui/CLAUDE.md
  • crates/product/ironclaw_webui/frontend/src/pages/chat/hooks/useSSE.ts
  • crates/product/ironclaw_webui/frontend/src/pages/chat/lib/useSSE.test.ts

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved chat stream reliability during reconnects, retries, and failed connection handshakes.
    • Prevented stale connections from interrupting active streams.
    • Preserved chat connection state across page reloads within the same browser tab.
    • Ensured duplicated tabs receive independent connections.
    • Improved handling of malformed saved connection state and stream activity timeouts.
  • Documentation

    • Clarified streaming connection behavior, including connection generations and stale stream handling.

Walkthrough

The SSE hook now persists connection identity across reloads, assigns fresh identity to duplicated tabs, sends connection ID and generation per request, and updates stream watchdog handling around validated responses and reconnects. Tests cover persistence, validation, rotation, and rejected handshakes.

Changes

SSE identity and transport

Layer / File(s) Summary
Persisted connection identity
crates/product/ironclaw_webui/frontend/src/pages/chat/hooks/useSSE.ts, crates/product/ironclaw_webui/frontend/src/pages/chat/lib/useSSE.test.ts, crates/product/ironclaw_webui/CLAUDE.md
The hook validates persisted session state, preserves identity across reloads, creates fresh identity for duplicated tabs, and rotates generations at the safe-integer limit. Tests and documentation cover these rules.
Validated SSE transport lifecycle
crates/product/ironclaw_webui/frontend/src/pages/chat/hooks/useSSE.ts, crates/product/ironclaw_webui/frontend/src/pages/chat/lib/useSSE.test.ts
Requests include connection ID and generation. Stream-open state and the activity watchdog now follow validated responses. Reconnect and retry paths clear transport state first. Tests cover rejected handshakes and request query changes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: serrrfirat, benkurrek

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant sessionStorage
  participant useSSE
  participant SSEServer
  Browser->>sessionStorage: Read persisted connection state
  useSSE->>useSSE: Validate navigation and generation
  useSSE->>sessionStorage: Persist connection ID and generation
  useSSE->>SSEServer: Request stream with connection ID and generation
  SSEServer-->>useSSE: Return validated event-stream response
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style and accurately describes the SSE reload retry-storm fix.
Description check ✅ Passed The description covers the required sections, change scope, validation, test strategy, security, database impact, blast radius, rollback, and review follow-through.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@railway-app

railway-app Bot commented Aug 6, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-7268 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Aug 6, 2026 at 7:15 am

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-7268 August 6, 2026 07:06 Destroyed
@github-actions github-actions Bot added scope: docs Documentation size: M 50-199 changed lines risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Aug 6, 2026
@henrypark133
henrypark133 requested a review from serrrfirat August 6, 2026 07:09
@henrypark133
henrypark133 marked this pull request as ready for review August 6, 2026 07:09
Copilot AI lite review requested due to automatic review settings August 6, 2026 07:09

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ironloopai

ironloopai Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Review · PR #7268

🔴 Failed

Execution result is invalid

The structured result could not be verified.

Automatic · PR opened · attempt 1 of 3 · failed after 2m 3s

Failure details
  • Repository: nearai/ironclaw
  • Base: main at 2816b0f
  • Head: codex/fix-sse-429-storm at 2805a46
  • Created: Aug 6, 2026, 7:14 AM UTC
  • Updated: Aug 6, 2026, 7:16 AM UTC
  • Run: 25425e20-1756-470e-a8af-0ef9eeab68a1
  • Latest attempt: 1 · Completed · 9a695590-9a9e-4c8d-823c-9d15e2ac03b7
  • Failed during: Verification
  • Retryable: No
  • Failure: 19a5c42f-bfb1-4701-b473-f0f9288aec55

@serrrfirat
serrrfirat enabled auto-merge August 6, 2026 07:20
@serrrfirat
serrrfirat added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 2f125c3 Aug 6, 2026
42 checks passed
@serrrfirat
serrrfirat deleted the codex/fix-sse-429-storm branch August 6, 2026 07:31
@serrrfirat serrrfirat mentioned this pull request Aug 10, 2026
29 tasks
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-7268 — 2805a466 Deployed Aug 6, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: low Changes to docs, tests, or low-risk modules scope: docs Documentation size: M 50-199 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants