fix(api,relay,marketing,ui): clear four Sentry issue families
Fixes the four highest-signal unresolved Sentry issue families whose root causes were clear from stack traces + code.
1. Webhook events dropped on NUL bytes — api (Fixes API-10)
GitHub webhook payloads carry U+0000 inside code-diff strings; Postgres jsonb rejects them (NeonDbError: unsupported Unicode escape sequence), so the insert into ingest.webhook_events failed and the event was lost (335 events / 116 orgs over 30d). New stripNullChars deep-cleans payloads before insert on both the GitHub and Linear webhook routes. Functionally verified against a payload shaped like the failing event.
2. Relay tunnel lifecycle noise — relay (Fixes RELAY-1, RELAY-2, RELAY-3, RELAY-4)
"Tunnel disconnected" / "Request timed out" / "Replaced by new tunnel" / "Host not connected" are routine churn but were reported as unhandled exceptions — ~66k Sentry events in 30 days, burying real errors. They're now a typed TunnelLifecycleError dropped in beforeSend; callers still receive the rejections unchanged.
3. Shader crash on non-WebGL browsers — marketing (Fixes MARKETING-35)
@paper-design/shaders-react throws when WebGL is unavailable (bots, old devices — 4k events / 480 users). The decorative DitheredBackground now feature-detects WebGL (cached probe, post-hydration) and renders nothing without it.
4. Gradient unmount crash — ui/web (Fixes WEB-17)
MeshGradient's unmount defense swaps stripe-gradient's el to a detached dummy — but the lib's delayed init reads el.parentElement.classList, and the dummy had no parent, converting the defense into the crash (694 events / 132 users on /agents). The decoy now has both a parent and a child.
Not in this PR (triaged, deeper work)
- API-15/API-1M: crash inside better-auth 1.6.13's endpoint wrapper on
/.well-known/oauth-authorization-server— needs an upstream check/bump. - RELAY-5: Bun's
wsshim rejects node-ws upgrades ("upgrade requires a Request object") — adapter-level change (hono/bunwebsocket helper). - API-18/19/1B/1F/…: one family of transient Neon disconnects — candidate for a shared retry wrapper.
- Browser-extension noise across web/docs/marketing (MetaMask/keplr/tronlink/
onMessage/sseError): to be archived in Sentry, not fixed in code.
Verification
Typecheck clean in api, relay, marketing, ui; Biome lint exits 0; stripNullChars verified with a NUL-carrying payload (5/5 assertions).
https://claude.ai/code/session_01BQ71xVEeJRhAqiU4Dfc5Fs
Summary by cubic
Fixes four high-signal Sentry issue families to stop dropped webhooks, silence expected relay churn, and prevent two frontend crashes. Improves stability across api, relay, marketing, and ui.
- Bug Fixes
- API-10: Strip U+0000 from GitHub/Linear webhook payloads with
stripNullCharsbefore writing to Postgresjsonbto prevent failed inserts. - RELAY-1/2/3/4: Classify routine tunnel churn as
TunnelLifecycleErrorand drop it in SentrybeforeSend; callers still get rejections. - MARKETING-35: Gate
DitheredBackgroundbehind a cached WebGL feature check; render nothing when unsupported to avoid@paper-design/shaders-reactcrashes. - WEB-17: Update
MeshGradientunmount decoy to have a parent and child to satisfystripe-gradientdelayed reads.
- API-10: Strip U+0000 from GitHub/Linear webhook payloads with
Summary by CodeRabbit
-
Bug Fixes
- Improved webhook reliability by safely handling unexpected null characters in incoming payloads.
- Prevented unsupported browsers or devices from displaying the marketing page’s WebGL background incorrectly.
- Improved handling of expected connection lifecycle failures, reducing unnecessary error reporting.
- Fixed cleanup behavior for gradient visuals to prevent potential rendering issues.
-
Reliability
- Preserved webhook processing behavior while making stored event data safer and more consistent.