Part of epic #8286 (Phase 1 — Errors). The largest surface, and the pattern-setter for the other Node-side swaps.
Current state
src/selfhost/sentry.ts (#1468) is the self-host ORB server's opt-in error tracking — a complete no-op unless the operator sets SENTRY_DSN. It carries five responsibilities that all need a PostHog answer, not just captureException:
- Capture + redaction —
captureException behind a deep scrub pipeline (SECRET_KEY/PAYLOAD_KEY/SECRET_VALUE regexes, PUBLIC_LOCAL_PATH_SCRUB_PATTERN, PUBLIC_UNSAFE_TERMS), operational tags (SENTRY_OPERATIONAL_TAG_KEYS), subsystem taxonomy (SENTRY_OPERATIONAL_SUBSYSTEMS), hashed installation ids.
- Structured-log forwarding —
src/server.ts wraps console sinks so every level:"error"/"fatal" JSON log line becomes an event without per-site wiring.
- Severity thresholds —
SENTRY_MIN_SEVERITY / SENTRY_REPO_MIN_SEVERITY (src/services/severity-threshold.ts) gate what gets reported.
- Cron monitors —
captureCheckIn against five monitors (SENTRY_MONITOR_NAMES: scheduled-loop, orb-export, orb-relay-drain, orb-relay-register, queue-dead-letter-revive) from sqlite-queue.ts/pg-queue.ts/monitored-work.ts/orb-collector.ts. PostHog has no cron-monitor product — this needs a real design: emit a snake_case heartbeat event per check-in and alert on absence via a PostHog insight alert (no-data condition), preserving the "silent death is an alert" property.
- OpenTelemetry bridge —
buildSentryOpenTelemetryBridge() feeds spans to Sentry when configured. Out of scope here: the bridge stays Sentry-side until the decommission issue decides its fate (tracing deferral is its own sub-issue).
Deliverables
Boundaries
Resources
Part of epic #8286 (Phase 1 — Errors). The largest surface, and the pattern-setter for the other Node-side swaps.
Current state
src/selfhost/sentry.ts(#1468) is the self-host ORB server's opt-in error tracking — a complete no-op unless the operator setsSENTRY_DSN. It carries five responsibilities that all need a PostHog answer, not justcaptureException:captureExceptionbehind a deep scrub pipeline (SECRET_KEY/PAYLOAD_KEY/SECRET_VALUEregexes,PUBLIC_LOCAL_PATH_SCRUB_PATTERN,PUBLIC_UNSAFE_TERMS), operational tags (SENTRY_OPERATIONAL_TAG_KEYS), subsystem taxonomy (SENTRY_OPERATIONAL_SUBSYSTEMS), hashed installation ids.src/server.tswraps console sinks so everylevel:"error"/"fatal"JSON log line becomes an event without per-site wiring.SENTRY_MIN_SEVERITY/SENTRY_REPO_MIN_SEVERITY(src/services/severity-threshold.ts) gate what gets reported.captureCheckInagainst five monitors (SENTRY_MONITOR_NAMES: scheduled-loop, orb-export, orb-relay-drain, orb-relay-register, queue-dead-letter-revive) fromsqlite-queue.ts/pg-queue.ts/monitored-work.ts/orb-collector.ts. PostHog has no cron-monitor product — this needs a real design: emit a snake_case heartbeat event per check-in and alert on absence via a PostHog insight alert (no-data condition), preserving the "silent death is an alert" property.buildSentryOpenTelemetryBridge()feeds spans to Sentry when configured. Out of scope here: the bridge stays Sentry-side until the decommission issue decides its fate (tracing deferral is its own sub-issue).Deliverables
$exceptioncapture viaposthog-node(already a root dependency), the full scrub pipeline ported and applied to event properties before capture, severity thresholds preserved unchanged.POSTHOG_API_KEY/POSTHOG_HOST(feat(mcp): add a typed PostHog wrapper module for src/mcp/server.ts (remote) #6235) relate to error tracking (recommend: same project key activates both, with the MCP allowlist untouched) —src/env.d.tsdocs +npm run selfhost:env-referenceregenerated.Boundaries
Resources
$exceptionshape)src/mcp/telemetry.ts— the in-repo posthog-node precedent (flush semantics, never-throws posture)