Skip to content

Add collaboration provider diagnostics to sync timeout errors#3404

Merged
caio-pizzol merged 2 commits into
mainfrom
caio/collab-timeout-diagnostics
May 20, 2026
Merged

Add collaboration provider diagnostics to sync timeout errors#3404
caio-pizzol merged 2 commits into
mainfrom
caio/collab-timeout-diagnostics

Conversation

@caio-pizzol

Copy link
Copy Markdown
Contributor

Surfaces the actual provider failure (close code, error message, auth state, event counts) in COLLABORATION_SYNC_TIMEOUT.details instead of the current { timeoutMs }. Several distinct failure modes that customers hit today collapse into the same useless error — this is the load-bearing fix that lets a customer report self-diagnose to "expected 101", "DNS failed", "auth rejected", or "broker accepted upgrade but never synced".

Sanitization redacts token / auth / secret / password / credential / apiKey in both URL fields and captured event payload strings. The provider self-reference in y-websocket's [event, provider] emit pattern is dropped to keep envelopes compact and forward-leak-safe.

Existing runtime.test.ts mocks updated: the previous constructor pattern returned undefined instances under bun's mock wrapping, which was harmless when the runtime did not touch the provider synchronously. The new diagnostics binding does. 23 new tests added covering redaction, field shape, event capture, null-payload close filtering, provider self-ref stripping, and defensive subscription.

Verified: bun test inside apps/cli → 1260 pass, 0 fail (346 skipped). Live customer replication against the live test endpoint now returns a fully populated details payload instead of { timeoutMs: 10000 }.

Before, COLLABORATION_SYNC_TIMEOUT details only contained
{ timeoutMs }. DNS failures, refused TCP, failed WS upgrades, and
auth rejections all collapsed to the same useless payload. The
timeout now captures last status/connection-error/connection-close/
authenticationFailed plus event counts, sanitized URL, documentId,
tokenEnv state, and paramsKeys.

Sensitive query params are redacted in URL and event payload
strings. y-websocket's [event, provider] emit pattern is reduced
to the first arg so the provider self-ref graph does not bloat
the envelope or risk leaking document content.

Mock constructors in runtime.test.ts updated: the previous pattern
returned undefined instances under bun's mock wrapping, which was
harmless when the runtime did not touch the provider synchronously.
The new attachProviderDiagnostics binding does.
@caio-pizzol
caio-pizzol requested a review from a team as a code owner May 20, 2026 13:44

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

Copy link
Copy Markdown

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: d14abfffac

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/cli/src/lib/collaboration/diagnostics.ts Outdated
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

decodeURIComponent throws URIError on malformed percent-encoding
(e.g. a raw `%` in a query key). The diagnostics sanitizer runs
inside the sync-timeout callback, so an uncaught throw would
suppress the COLLABORATION_SYNC_TIMEOUT envelope entirely - the
exact failure mode the rest of the module defends against.

Falls back to the raw key on URIError so the sensitivity check
still runs. Decoding stays in place so encoded variants like
`%74oken` continue to redact correctly.
@caio-pizzol caio-pizzol self-assigned this May 20, 2026
@tupizz
tupizz self-requested a review May 20, 2026 16:54
@tupizz

tupizz commented May 20, 2026

Copy link
Copy Markdown
Contributor

Reviewed and tested against the real triage servers (wss://y-websocket.collab.superdoc.dev and wss://hocuspocus.collab.superdoc.dev) using the compiled SEA binary off this branch and the SUPERDOC_COLLAB_TEST_TOKEN flow. Customer-shape --collaboration-json envelope, no source-mode shortcuts.

Test matrix

# Endpoint Token Result Key field in envelope
A1 y-websocket valid ok: true, sync in 2876ms n/a
A2 y-websocket none timeout lastConnectionClose: { code: 1002, reason: "Expected 101 status code" }, tokenEnvConfigured: false
A3 y-websocket wrong timeout same as A2 + URL shows ?token=[REDACTED] (sanitization confirmed)
B1 hocuspocus valid ok: true, sync in 3161ms n/a
B2 hocuspocus none timeout eventCounts: {}, providerState.status: "connecting" — stuck connecting (no rejection event from server)
B3 hocuspocus wrong timeout lastAuthenticationFailed: { reason: "permission-denied" } + eventCounts: { authenticationFailed: 1, disconnect: 1, close: 1 }
C1 wss://this-host-does-not-exist-abcdef.invalid n/a timeout lastConnectionClose: { code: 1006, reason: "...failed: Failed to connect" }

PR's own suite: bun test --run collaboration92 pass, 0 fail across the 4 files.

What this confirms

  • The fix lands the SD-3233 customer pain end-to-end: the agent now sees the actual close code/reason for every failure mode I exercised.
  • Secret redaction works on the wire (A3 shows ?token=[REDACTED] even though the env var held a long hex string). Important because pre-fix this string would have ended up in the customer's logs.
  • Hocuspocus auth path is covered (B3 surfaces lastAuthenticationFailed.reason: "permission-denied"). y-websocket-only fixes would have missed this entirely because Hocuspocus emits authenticationFailed rather than connection-close.
  • The modular diagnostics.ts split is the right shape — runtime.ts stays small, the diagnostics module is independently testable, and the attachProviderDiagnostics → toTimeoutDetails interface is reusable if/when Liveblocks gets the same treatment.

@caio-pizzol
caio-pizzol enabled auto-merge May 20, 2026 17:16
@caio-pizzol
caio-pizzol disabled auto-merge May 20, 2026 17:16
@caio-pizzol
caio-pizzol merged commit b7f404b into main May 20, 2026
16 checks passed
@caio-pizzol
caio-pizzol deleted the caio/collab-timeout-diagnostics branch May 20, 2026 17:17
@superdoc-bot

superdoc-bot Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in superdoc-cli v0.12.0

The release is available on GitHub release

@superdoc-bot

superdoc-bot Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in superdoc-sdk v1.11.0

@superdoc-bot

superdoc-bot Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in @superdoc-dev/mcp v0.7.0

The release is available on GitHub release

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants