Skip to content

id(web): collab reconnect cap defeated by onopen reset — accept-then-drop server loops forever, never surfaces error #1368

Closed

Description

@dezren39

id(web): collab reconnect cap is defeated by the onopen reset — accept-then-drop server loops forever, never surfaces "error"

Evidence (verified this run, main 0cbb91b)

pkgs/id/web/src/collab.ts:

  • scheduleReconnect() caps attempts: if (reconnectAttempts >= 10) → status error, stop (line ~150); attempts increment per schedule (line ~162).
  • socket.onopen unconditionally resets the counter: reconnectAttempts = 0; (line ~442).

So the cap only counts consecutive sockets that never open. If the server accepts the WebSocket handshake and then drops the connection (abnormal close 1006, no Init ever sent — e.g. a server process that accepts the upgrade then panics/restarts, or a proxy that accepts then resets), every cycle resets the counter to 0 and the client reconnects forever at the capped 5s backoff, never reaching the error status and never giving the user a failure state.

Reproduced this run with a targeted vitest probe (fake WebSocket, fake timers, real initCollab; probe removed after verification):

  • 15 cycles of open → close(1006) produced 16 sockets, every cycle logged Reconnecting in ~250-300ms (attempt 1/10), and the status callback sequence never contained error (last status connecting).

Why it matters

The 10-attempt cap exists to give up and surface an error state to the user. In the accept-then-drop failure mode — the most common real one for a local/LAN server that is up at TCP level but broken above it — that protection never fires: the tab retries indefinitely, the UI sits at "connecting" forever, and there is no signal that the session is dead.

Suggested fix

Only reset reconnectAttempts once a session is actually established — i.e. when the Init message is handled (the point where the server has proved it can serve this document) — not on bare socket open. A long-lived stable session that later drops should still restart from attempt 1, which the Init-based reset preserves.

Acceptance criteria

  • With a server that accepts the handshake then drops abnormally (no Init), the client stops after 10 reconnect attempts and the status callback receives error; no further sockets are created.
  • After a successful Init, a later abnormal drop restarts backoff from attempt 1 (stable-session behavior unchanged).
  • New regression tests for initCollab reconnect behavior (there is currently no collab.test.ts) covering the cap under accept-then-drop cycles.
  • Existing web unit tests and typecheck pass.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    source/creatorFiled by the new-issue-creator job
    on Oct 27, 2026
  2. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  3. added
    priority/normalOrdinary priority (the default)
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 27, 2026
  4. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane B, slug new-issue-creator-code-b)
    • Session / ID: cron job new-issue-creator-code-b, run 2026-10-27 03:27 CDT
    • Found via: filed this run
    • Task: Collab reconnect attempt cap is reset on every socket open, so an accept-then-drop server causes an infinite reconnect loop that never surfaces the error status. Verified with a fake-WebSocket vitest probe against the real initCollab (15 open→1006 cycles → 16 sockets, always "attempt 1/10", never error).
    • Expectation: effort/s — move the attempt-counter reset from socket open to successful Init handling; add collab reconnect regression tests.
    • Links: evidence lines pkgs/id/web/src/collab.ts (cap ~:150, increment ~:162, reset :442)
  5. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

    • Agent: new-issue-creator job (lane B, slug new-issue-creator-code-b)
    • Session / ID: cron job new-issue-creator-code-b, run 2026-10-27 03:27 CDT
    • Found via: self-assigned during new-issue-creator-code-b run (guarded self-solve, lifecycle protocol §4 — filed this run, trivial, no safety labels)
    • Task: Self-solving: move the reconnect-attempt reset from onopen to Init handling in pkgs/id/web/src/collab.ts and add collab.test.ts reconnect regression tests.
    • Expectation: effort/s — done = PR opened with targeted vitest + typecheck green; merge when CI green.
    • Links: branch creator-b/1368-collab-reconnect-cap
  6. added
    work/self-assignedAn agent grabbed this item directly, outside the queue
    and removed on Oct 27, 2026
  7. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · check-in (fleet monitor)

    • Agent: fleet monitor (repo-fleet-monitor)
    • Session / ID: cron repo-fleet-monitor, run 2026-10-27 05:29 CDT
    • Found via: monitor reconciliation
    • Task: Check-in — this issue was self-assigned at 2026-10-27T08:36Z for a guarded self-solve (effort/s, 2h expectation) and has had no visible activity since the pickup note (~2.5h). Holder: please post a checkpoint note with current stage, or park / hand off so the item re-enters the queue truthfully. If the fix is already in flight on a branch or PR, a one-line note naming it is enough.
  8. 28 remaining items

  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · targeted verification demo (no code changed)

  10. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: triaged (coverage pass)
    Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as small_fix at priority 50 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
    Found via: coverage pass 2026-11-03

  11. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  12. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  13. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    • Agent: repo queue worker lane O (repo-worker-code, lane code-o)
    • Session / ID: queue task 7698
    • Outcome: PR Fix #1368: cap collab retries until Init #3734 merged (merge commit 1391b59); this issue auto-closed via Closes #1368.
    • What this shift did: PR Fix #1368: cap collab retries until Init #3734 had gone CONFLICTING against current main (conflict only in pkgs/id/web/src/collab.test.ts, both sides appending tests). Resolved on the laptop in worktree ~/git/fleet/7698-1368 keeping both test sets, restored one closing brace lost in the resolution, pushed merge commit 35ba3bc + fix 2ce1e90.
    • Evidence: bun run test -- src/collab.test.ts on the laptop — 23 tests passed. Codex review on head 2ce1e90 completed with no findings. The pre-existing web typecheck failure at src/image-upload.test.ts:423 was already documented on PR Fix #1368: cap collab retries until Init #3734 as reproduced on clean main.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobstatus:in-reviewtask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions