CL-6496: a global error sink - #228
Merged
Merged
Conversation
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.
…ient-log retirement plan
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.errorcall 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-loghas only 4 call sites, all in apps/web, and exists only because@intx/logwasn't adopted there -- not because LogTape can't run in a browser.So
@corbits/error-sinkadds only what was missing:reportError(error, context), a fixed structured shape (operation, optionaltenantId/roomId/agentId, arefIda person can quote to support -- matchingpackages/onboarding'sreportOnboardingErrorprecedent) plus a redaction pass, delivered throughgetLogger(["errors"]). Reaching OTEL/Sentry later is one LogTape sink registered via@intx/log's ownconfigureSync/setup-- no call site ofreportErrorchanges when that happens.Never throws. A malformed context degrades to
operation: "unknown"instead of rejecting the report; a throwing sink can't propagate back throughreportError's own try/catch (proven against a real throwing LogTape sink in tests, not a mock).Reference call site:
apps/hub/src/index.ts'sresolveFallbackWorkbenchId-- a barecatch { return undefined; }with zero logging, the exact silent-swallow pattern behind this ruling. The sibling lane (CL-6495) has a worktree fornew-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, seepackages/error-sink/README.md): migrate its 4 call sites (instant-agent-create.ts,auth-screen.tsx,main.tsx,app-error-boundary.tsx) onto@intx/logdirectly, 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:
catchblock (or.catch()) whose body neither callsreportErrornor rethrows nor returns/logs through@intx/log-- i.e., a block that discards the caught value entirely.catchthat only doesconsole.*with the caught error (bypasses the sink, no refId, no structured context).reportErrorwhosecontext.operationis a non-literal / dynamically empty string, or whosecontextis missing atenantIdon hub-side code paths that have one in scope (an easy way to accidentally omit context that was available).@intx/logcall sites that already dolog.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 passcd packages/error-sink && bun run typecheck-- cleancd apps/hub && bun run typecheck-- cleanbun run lintfrom repo root -- passes (12 pre-existing warnings unrelated to this change)bun run check:packagesfrom repo root -- okbun run check:licensesfrom repo root -- okDO 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.