Skip to content

feat(sentry-monitor): bundle Sentry error monitoring into the fork#4

Merged
gandalfboon[bot] merged 6 commits into
boonfrom
feat/sentry-bundled-monitor
Jun 2, 2026
Merged

feat(sentry-monitor): bundle Sentry error monitoring into the fork#4
gandalfboon[bot] merged 6 commits into
boonfrom
feat/sentry-bundled-monitor

Conversation

@insomnius

@insomnius insomnius commented Jun 2, 2026

Copy link
Copy Markdown

Summary

Bundles Sentry error monitoring directly into the fork as a default-on, DSN-gated plugin (extensions/sentry-monitor/), replacing the separately git-installed @getboon/openclaw-monitor. It forwards every error-bearing lifecycle event to Sentry and stays a clean plugin tapping hooks — no Sentry code in core src/**.

  • Captures model_call_ended (error), agent_end (fail), after_tool_call (error), message_sent (fail), subagent_ended (error/timeout/killed/reset/deleted), cron_changed (run/delivery error), session_end (unknown), plus node uncaught/unhandled rejections. Errors only; no prompt/message/tool content. Inactive until BOON_SENTRY_DSN or plugin-config dsn is set.
  • Ships in core dist; @sentry/node@8.45.0 mirrored at root as an internalized bundled-plugin runtime dep (bonjour/@homebridge/ciao pattern), ignored in both knip bundled-dep lists.
  • Docs docs/gateway/sentry-monitor.md (+ nav); plugin: sentry-monitor labeler entry.

Design / typing

  • Pure per-hook capture builders returning a discriminated SentryCapture union; dispatch typed against a minimal structural client.
  • Lifecycle hooks register via the typed api.on(...) API (per the bundled-plugin contract; file added to the typed-hook allowlist), using the real openclaw/plugin-sdk/types — so a core field change is a compile error, and there are no casts.

Tests

44 unit tests across format, captures, dispatch, register: every trigger boundary, dispatch routing, and the register() activation paths (no-DSN inactive; env/config DSN → init + all 7 hooks + flush).

Verification

node scripts/run-vitest.mjs extensions/sentry-monitor                        # 44 passed
node scripts/run-oxlint.mjs extensions/sentry-monitor                        # 0 errors
node scripts/run-tsgo.mjs -p tsconfig.extensions.json                        # exit 0
node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json     # exit 0
pnpm build                                                                   # clean; emits dist/extensions/sentry-monitor/
node scripts/root-dependency-ownership-audit.mjs --check                     # ok

CI on the prior branch (same tree) was green across lint, docs, dependencies, contracts, and bundled-extension checks.

Real behavior proof

Behavior addressed: Sentry error reporting ships with the fork by default (DSN-gated) as a bundled plugin rather than a separate git install.
Real environment tested: local build + unit/type/lint verification; plugin compiles into dist/extensions/sentry-monitor/ and is discovered by the bundled-plugin build pipeline; full CI suite exercised on the identical tree.
Exact steps or command run after this patch: the commands above plus pnpm build; CI checks on the pushed branch.
Evidence after fix: 44/44 tests pass; oxlint 0 errors; both tsgo lanes exit 0; clean build; dep audit ok; CI lint/docs/dependencies/contracts/bundled checks green.
Observed result after fix: bundled plugin builds, typechecks, lints, and is wired default-on + DSN-gated.
What was not tested: no live gateway run delivering a real event to a Sentry project (logic covered against a mocked client). Channel connect/disconnect capture is out of scope (needs a new core channel_connection_changed hook — follow-up).

Supersedes #3 (recreated with a single signed commit).

🤖 Generated with Claude Code


Summary by cubic

Bundles Sentry error monitoring as a default-on, DSN-gated plugin, replacing @getboon/openclaw-monitor. It forwards only error events to Sentry, stays off with no DSN, and improves host vs environment tagging.

  • New Features

    • Adds extensions/sentry-monitor/ using typed api.on(...) hooks.
    • Captures failures from model calls, agent ends, tool calls, message sends, subagent ends, cron runs, abnormal session ends, plus Node uncaught exceptions and unhandled rejections.
    • Ships in core dist with @sentry/node bundled; docs at docs/gateway/sentry-monitor.md. Strictly typed with unit tests; no prompt/message/tool content sent.
  • Bug Fixes

    • Registers sentry-monitor in bundled startup allowlists; separates hostname (host tag) from Sentry environment.
    • Resolves dsn/environment with ||; rejects non-finite tracesSampleRate before Sentry.init and defaults to 0.
    • cron_changed: capture on status="error" and deliveryStatus="not-delivered", avoid blank messages, remove free-form summary.
    • Marks the plugin package as private; adds a workspace devDependency on @openclaw/plugin-sdk.
    • CI: switch CodeQL/OpenGrep to GitHub-hosted runners and remove Blacksmith Testbox workflows so fork jobs run.

Written for commit 67f96f3. Summary will update on new commits.

Review in cubic

Adds a bundled, default-on (DSN-gated) plugin that forwards every
error-bearing OpenClaw lifecycle event to Sentry: model_call_ended,
agent_end, after_tool_call, message_sent, subagent_ended, cron_changed,
and abnormal session_end, plus node-level uncaught/unhandled rejections.
Inactive (safe no-op) until BOON_SENTRY_DSN or plugin-config dsn is set.

Vendored from @getboon/openclaw-monitor and adapted for in-fork bundling:
ships in core dist, @sentry/node mirrored at root as an internalized
bundled-plugin runtime dependency, ignored in both knip bundled-dep lists.

Strictly typed: pure per-hook capture builders return a discriminated
SentryCapture union; dispatch is typed against a minimal structural
client; lifecycle hooks register via the typed api.on(...) API using the
real openclaw/plugin-sdk/types so core field changes surface at compile
time (no casts). Registered on the bundled typed-hook contract allowlist.

Extensive unit tests cover every trigger boundary, dispatch routing, and
the register() activation paths. Docs at docs/gateway/sentry-monitor.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

4 issues found across 18 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="extensions/sentry-monitor/src/register.ts">

<violation number="1" location="extensions/sentry-monitor/src/register.ts:42">
P2: Environment and host are conflated into one variable, causing incorrect Sentry environment and host tagging.</violation>
</file>

<file name="extensions/sentry-monitor/package.json">

<violation number="1" location="extensions/sentry-monitor/package.json:1">
P2: Missing `"devDependencies": { "@openclaw/plugin-sdk": "workspace:*" }`. The plugin code imports `definePluginEntry` from `openclaw/plugin-sdk/plugin-entry` (index.ts) and imports from `openclaw/plugin-sdk/plugin-entry` in register.ts. Every other extension that imports from the plugin SDK declares it as a workspace devDependency. Without it, TypeScript may fail to resolve the types in independent workspace resolution or when the package is consumed outside the monorepo workspace context.</violation>

<violation number="2" location="extensions/sentry-monitor/package.json:1">
P2: Missing `"private": true` — this is a bundled plugin shipped inside the core dist (not published independently). Every other internal-only bundled extension (admin-http-rpc, canvas, clickclack, deepgram, elevenlabs, senseaudio, webhooks, etc.) sets `"private": true` in package.json to prevent accidental npm publication. Without it, `npm publish` (or similar tooling) could attempt to publish this workspace package.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread extensions/sentry-monitor/src/register.ts Outdated
Comment thread extensions/sentry-monitor/src/captures.ts Outdated
Comment thread extensions/sentry-monitor/package.json
Comment thread extensions/sentry-monitor/package.json
- Register sentry-monitor in the bundled startup-id allowlists
  (EXPECTED_BUNDLED_STARTUP_PLUGIN_IDS + empty-config startup) so the
  bundled-plugin-metadata contract passes.
- Resolve DSN/environment with `||` so an empty-string config value falls
  through to the env var instead of disabling the plugin.
- Validate tracesSampleRate (typeof number) before passing to Sentry.init.
- cron_changed: also capture deliveryStatus="not-delivered" (silently
  dropped output), use `||` for the message to avoid a blank Error(""),
  and stop shipping the free-form `summary` (content) — metadata only.
- Strengthen tests: handler wiring + dispatch, shutdown flush, empty-DSN
  env fallthrough, tracesSampleRate guard, cron not-delivered / no-summary,
  dispatch message contexts+extra forwarding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 6 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread extensions/sentry-monitor/src/register.ts Outdated
insomnius and others added 4 commits June 2, 2026 21:29
- register: separate `hostname` (host tag = real machine) from
  `environment` (configurable Sentry env) so a custom environment no
  longer pollutes the host tag.
- cron_changed: capture on status="error" even when the error text is
  missing (the `||` message fallback covers the blank case).
- package.json: add `"private": true` (internal bundled plugin, never
  published) and the `@openclaw/plugin-sdk` workspace devDependency to
  match every other SDK-importing extension.
- tests updated for the run-error-without-text case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
typeof NaN === "number", so the prior guard let NaN through to Sentry.init.
Use Number.isFinite (with the typeof check to keep the narrowing) so NaN,
Infinity, strings, and missing values all fall back to 0. Covered by a
parametrized test (string / NaN / Infinity).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CodeQL and OpenGrep workflows hardcoded `blacksmith-*` runners, which
only exist on the upstream org — on the getboon fork those jobs queued
forever (and were cancelled by each push), never completing. ci.yml already
falls back to GitHub-hosted runners on forks; mirror that for the security
workflows by switching to ubuntu-24.04 (and macos-latest for the macOS
CodeQL job) so they actually run here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Testbox workflows (ci-check-testbox, ci-build-artifacts-testbox, and the
two windows-*-testbox) rely on Blacksmith-proprietary actions
(useblacksmith/begin-testbox + run-testbox) and Blacksmith runners that the
getboon fork does not have, so the PR-triggered ones queued forever and never
completed. They are also redundant on the fork: ci.yml already runs the same
build/check steps on GitHub-hosted ubuntu-24.04. None are required checks,
reusable workflows, or referenced elsewhere. Remove them on the fork.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@gandalfboon gandalfboon Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed the full diff (not just the description): clean plugin boundary — no Sentry code in src/**, DSN-gated, errors-only with no prompt/message/tool content. Verified all 5 cubic findings are actually fixed in-tree (private:true, plugin-sdk devDep, host/environment split, cron status==error capture, Number.isFinite NaN guard). Boundary-invariant + bundled-metadata allowlists and knip ignores updated correctly. CI fully green. Good to ship. Non-blocking: smoke-test a live event against a real Sentry project once BOON_SENTRY_DSN is wired.

@gandalfboon gandalfboon Bot merged commit 671cb6b into boon Jun 2, 2026
92 checks passed
@gandalfboon gandalfboon Bot deleted the feat/sentry-bundled-monitor branch June 2, 2026 18:14
insomnius added a commit that referenced this pull request Jun 3, 2026
Bump version to capture PR #4 (bundled Sentry monitor) on top of
boon.1 (session-takeover hardening, PR #2). Base = stock 2026.5.18.

ENG-12565.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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