Skip to content

feat(api): add PostHog exception capture to the hosted ORB Worker path#8611

Merged
loopover-orb[bot] merged 1 commit into
mainfrom
claude/posthog-hosted-worker-error-tracking
Jul 25, 2026
Merged

feat(api): add PostHog exception capture to the hosted ORB Worker path#8611
loopover-orb[bot] merged 1 commit into
mainfrom
claude/posthog-hosted-worker-error-tracking

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • Adds src/api/worker-posthog.ts, a parallel PostHog error-tracking sink for the hosted ORB Worker alongside the existing @sentry/hono/cloudflare middleware in src/api/routes.ts.
  • Uses posthog-node's own captureException() rather than a hand-built raw $exception HTTP payload — see the correction comment on PostHog error tracking for the hosted ORB Worker path (raw $exception, no SDK in the bundle) #8288 for why: PostHog's docs warn a manually constructed exception event's strict schema "fails in the vast majority of cases", and their own Cloudflare Workers guide recommends installing posthog-node itself for exactly this edge lifecycle. This Worker already bundles posthog-node for src/mcp/telemetry.ts's MCP usage events (feat(mcp): add a typed PostHog wrapper module for src/mcp/server.ts (remote) #6235), so this adds zero new bundle weight.
  • Ephemeral-client-per-call design, mirroring src/mcp/telemetry.ts's identical choice for the identical edge-lifecycle reason (flushAt: 1, flushInterval: 0, immediate send, no long-lived batching client that could be torn down mid-flush).
  • Wired via Hono's documented c.error check after next(), not a try/catch — Hono's own default errorHandler (installed even without an explicit app.onError()) converts a thrown exception into a response several dispatch levels below an outer middleware's next() call, so a plain try/catch there never sees it. Confirmed via a minimal repro before settling on this approach.
  • WORKER_POSTHOG_API_KEY/WORKER_POSTHOG_HOST/WORKER_POSTHOG_ENVIRONMENT are separate from the dual-purpose POSTHOG_API_KEY (MCP telemetry + self-host PostHog error tracking for the ORB self-host server (swap the src/selfhost/sentry.ts sink; cron-monitor heartbeat design) #8287), mirroring WORKER_SENTRY_DSN's separation from self-host's SENTRY_DSN for the same cross-wire-avoidance reason (self-host's server.ts calls this same exported worker.fetch).
  • Redaction reuses src/selfhost/redaction-scrub.ts's primitives (confirmed Workers-safe).
  • Parallel-run alongside Sentry per the epic's gated decommission plan (Sentry decommission: gated cutover checklist across all six surfaces #8298) — Sentry is untouched.

Closes #8288

Test plan

  • npm run typecheck clean
  • npx vitest run test/unit/worker-posthog.test.ts — 25/25 passing, 100% line/branch coverage on the new module
  • npm run test:workers (real Cloudflare Workers isolate) — 4/4 passing, including a new smoke test mirroring the existing WORKER_SENTRY_DSN-unset case
  • npm run test:coverage — full suite green (one pre-existing, unrelated failure confirmed present on main independent of this branch: mcp-cli-profiles.test.ts's changelog-JSON test, tracked separately)
  • test:engine-parity, test:live-gate-parity, test:driver-parity, engine's own test suite, test:mcp-pack, test:miner-pack, test:engine-pack, test:ui-kit-pack, test:miner-deployment-docs-audit, rees:test all green

Adds src/api/worker-posthog.ts, a parallel PostHog error-tracking sink
for the hosted Worker alongside the existing @sentry/hono/cloudflare
middleware. Uses posthog-node's own captureException() (already bundled
here for src/mcp/telemetry.ts's MCP usage events) rather than a
hand-built raw $exception payload -- PostHog's own docs warn that a
manually constructed exception event's strict schema "fails in the vast
majority of cases", and their Cloudflare Workers guide recommends
installing posthog-node itself with flushAt:1/flushInterval:0 for
exactly this edge lifecycle.

Wired via Hono's documented c.error check after next() (not a
try/catch): Hono's own default errorHandler converts a thrown exception
into a response several dispatch levels below an outer middleware's
next() call, so a plain try/catch there never sees it.

WORKER_POSTHOG_API_KEY/HOST/ENVIRONMENT are separate from the dual-
purpose POSTHOG_API_KEY (MCP telemetry + self-host #8287), mirroring
WORKER_SENTRY_DSN's separation from self-host's SENTRY_DSN for the same
cross-wire-avoidance reason. Redaction reuses src/selfhost/redaction-
scrub.ts's primitives. Parallel-run alongside Sentry per the epic's
gated decommission plan (#8298).

Closes #8288
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 25, 2026
@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.00%. Comparing base (a972353) to head (cd8ca79).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8611      +/-   ##
==========================================
- Coverage   92.55%   92.00%   -0.56%     
==========================================
  Files         798      799       +1     
  Lines       79850    79887      +37     
  Branches    24120    24132      +12     
==========================================
- Hits        73908    73500     -408     
- Misses       4803     5311     +508     
+ Partials     1139     1076      -63     
Flag Coverage Δ
backend 92.96% <100.00%> (-0.78%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/api/routes.ts 95.29% <ø> (ø)
src/api/worker-posthog.ts 100.00% <100.00%> (ø)

... and 3 files with indirect coverage changes

@loopover-orb

loopover-orb Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-25 07:54:02 UTC

5 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This adds a parallel PostHog error-capture sink for the hosted ORB Worker, using posthog-node's captureException() with an ephemeral per-request client (flushAt:1/flushInterval:0), wired via Hono's documented c.error check (not try/catch) and gated behind isCloudflareWorkerRuntime() + WORKER_POSTHOG_API_KEY. The design faithfully mirrors two already-established patterns in this codebase (src/mcp/telemetry.ts's ephemeral client, WORKER_SENTRY_DSN's separate-env-var cross-wire avoidance for the self-host/hosted shared fetch handler), and the redaction reuses src/selfhost/redaction-scrub.ts's primitives applied via before_send plus an explicit scrub on the request path. Tests cover scrubbing, config detection, client construction, error wrapping, and the middleware's passthrough/capture/fallback-executionCtx paths.

Nits — 6 non-blocking
  • src/api/worker-posthog.ts:67 scrubWorkerPostHogEvent returns null (dropping the whole event) on any scrub failure rather than a narrower fallback — acceptable given the best-effort telemetry contract, but worth a one-line comment noting the drop is intentional so a future reader doesn't 'fix' it into propagating the error.
  • src/api/worker-posthog.ts:27 the DEFAULT_POSTHOG_HOST literal duplicates the same string already hardcoded in src/mcp/telemetry.ts and src/selfhost/posthog.ts — consider hoisting to one shared constant to avoid the three copies drifting if PostHog ever changes their default ingestion host.
  • The `environment: trimmedOrUndefined(...) ?? "production"` default (worker-posthog.ts:~124) has both arms exercised in the test file per the diff, so this is fine — just confirm the same is true for the WORKER_POSTHOG_HOST default-vs-override branch, which the diff does show tested.
  • Consider factoring the `DEFAULT_POSTHOG_HOST` constant into a shared module used by worker-posthog.ts, mcp/telemetry.ts, and selfhost/posthog.ts to remove the triplicated literal.
  • The 8-line resolveExecutionCtx no-op fallback object is duplicated from src/mcp/server.ts's getExecutionContext per the doc comment — if a third caller ever needs it, extract to a shared tiny helper rather than a third copy.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8288
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 13 registered-repo PR(s), 13 merged, 250 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 13 PR(s), 250 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Partially addressed
The PR delivers env-gated capture, WORKER_POSTHOG_* naming, waitUntil-based flush, redaction reuse, and tests, but it explicitly abandons the issue's first deliverable — raw $exception capture over the HTTP API with no SDK in the Worker bundle — in favor of bundling posthog-node's captureException(), which directly contradicts the epic's stated 'no SDK in the Worker bundle' principle.

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, Ruby, Go, MDX, Shell, Solidity, JavaScript
  • Official Gittensor activity: 13 PR(s), 250 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit a9056ae into main Jul 25, 2026
7 checks passed
@loopover-orb
loopover-orb Bot deleted the claude/posthog-hosted-worker-error-tracking branch July 25, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostHog error tracking for the hosted ORB Worker path (raw $exception, no SDK in the bundle)

1 participant