Skip to content

CL-6496: a global error sink - #228

Merged
TheGreatAxios merged 4 commits into
mainfrom
cl-6496-error-sink
Aug 21, 2026
Merged

TheGreatAxios merged 4 commits into
mainfrom
cl-6496-error-sink

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Summary

Owner ruling: never swallow an error, push it to a global sink instead. This is unit one of three (sink -> guard -> sweep) -- the 141-site sweep is explicitly out of scope here.

Consolidation, not a second logger. The repo already has one logging concept -- @intx/log (LogTape underneath), 65+ getLogger([...])/log.error call sites across apps/hub, apps/sidecar, and a dozen packages. It already ships a pluggable-sink seam (LogTape sinks) and universal runtime support (Node, Bun, browsers). @corbits/client-log has only 4 call sites, all in apps/web, and exists only because @intx/log wasn't adopted there -- not because LogTape can't run in a browser.

So @corbits/error-sink adds only what was missing: reportError(error, context), a fixed structured shape (operation, optional tenantId/roomId/agentId, a refId a person can quote to support -- matching packages/onboarding's reportOnboardingError precedent) plus a redaction pass, delivered through getLogger(["errors"]). Reaching OTEL/Sentry later is one LogTape sink registered via @intx/log's own configureSync/setup -- no call site of reportError changes when that happens.

Never throws. A malformed context degrades to operation: "unknown" instead of rejecting the report; a throwing sink can't propagate back through reportError's own try/catch (proven against a real throwing LogTape sink in tests, not a mock).

Reference call site: apps/hub/src/index.ts's resolveFallbackWorkbenchId -- a bare catch { return undefined; } with zero logging, the exact silent-swallow pattern behind this ruling. The sibling lane (CL-6495) has a worktree for new-workbench-picker.tsx's bare catch but no commits/PR yet, so that call site was left for them per the coordination note.

Retirement plan for @corbits/client-log (not executed here, see packages/error-sink/README.md): migrate its 4 call sites (instant-agent-create.ts, auth-screen.tsx, main.tsx, app-error-boundary.tsx) onto @intx/log directly, confirm LogTape's browser sink covers the same devtools-visibility bar, then delete the package. Small enough for one follow-up PR.

Guard brief (for unit 2)

Based on this sink's actual shape, the guard should flag:

  • A catch block (or .catch()) whose body neither calls reportError nor rethrows nor returns/logs through @intx/log -- i.e., a block that discards the caught value entirely.
  • A catch that only does console.* with the caught error (bypasses the sink, no refId, no structured context).
  • A call to reportError whose context.operation is a non-literal / dynamically empty string, or whose context is missing a tenantId on hub-side code paths that have one in scope (an easy way to accidentally omit context that was available).
  • No need for the guard to special-case @intx/log call sites that already do log.error(err, {...}) directly with a similar shape -- that's already a legitimate reported error, not a swallow.

Test plan

  • cd packages/error-sink && bun test -- 16 pass
  • cd packages/error-sink && bun run typecheck -- clean
  • cd apps/hub && bun run typecheck -- clean
  • bun run lint from repo root -- passes (12 pre-existing warnings unrelated to this change)
  • bun run check:packages from repo root -- ok
  • bun run check:licenses from repo root -- ok

DO NOT MERGE without a peer review -- guard (unit 2) and the 141-site sweep (unit 3) still remain, and this issue stays open until all three land.

Covers context capture (operation, tenant/room/agent ids, refId minting
and reuse), secret redaction (key- and pattern-based), and the
never-throws guarantee against a real throwing LogTape sink.
The owner ruling behind CL-6496: never swallow an error, push it to a
global sink instead. Rather than add a second logging concept,
reportError(error, context) is a thin convention on top of @intx/log
(LogTape) -- already the repo's one logger, with 65+ getLogger/log.error
call sites and its own pluggable-sink seam. This package adds only what
that seam was missing: a fixed structured shape (operation, optional
tenant/room/agent identifiers, a refId a person can quote to support --
matching packages/onboarding's reportOnboardingError precedent) and a
redaction pass, so no call site hand-rolls that shape or leaks a secret.
reportError itself never throws; a malformed context degrades to
operation: "unknown" instead of rejecting the report.
Reference call site for CL-6496: this catch block returned undefined on
any failure with zero logging -- the exact silent-swallow pattern that
triggered the owner's ruling. Now reported with tenantId context and a
support-quotable refId before the same best-effort fallback happens.
@TheGreatAxios
TheGreatAxios merged commit 312c932 into main Aug 21, 2026
2 checks passed
@TheGreatAxios
TheGreatAxios deleted the cl-6496-error-sink branch August 25, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant