Add an env-var-gated, off-by-default Sentry SDK integration so MCP runtime
errors, fail-closed workflow blockers, lease/terminal-lock/stale-runtime
collisions, and recurring watchdog check-ins are visible in a self-hosted
Sentry at https://sentry.prgs.cc/. Gitea stays the source of truth; Sentry is
observe-only.
New module `sentry_observability.py` mirrors the `gitea_audit` conventions
(env-gated, best-effort, redacting):
- Config from MCP_SENTRY_ENABLED / SENTRY_DSN / SENTRY_ENVIRONMENT /
SENTRY_RELEASE / MCP_SENTRY_TRACES_SAMPLE_RATE / MCP_SENTRY_ENABLE_LOGS.
Active only when enabled AND a DSN is present; otherwise a hard no-op.
- Fail OPEN for observability (never blocks a tool success path) and fail
CLOSED for redaction (drop a field rather than risk leaking it).
- `scrub_event` before_send/before_send_log hook + allowlisted tags: no
tokens/passwords/keychain ids/DSNs/cookies, no raw session-state or full
prompt bodies (session_id -> 12-char hash), no full filesystem paths
(worktree path -> coarse category). Reuses incident_bridge + gitea_audit
scrubbers.
- capture_exception, capture_workflow_blocker (with canonical next action),
and monitor_checkin with six stable cron slugs (stale lease scan, terminal
lock scan, allocator health, namespace health, dashboard freshness,
reconciler cleanup).
- `sentry_sdk` is a lazily-imported optional dependency; the module imports
and no-ops cleanly when the package is absent.
Wiring in gitea_mcp_server.py (additive, guarded, best-effort):
- init_sentry() in __main__ before mcp.run.
- capture_exception in the `_audited` failure path; capture_workflow_blocker
in `_audit_pr_result` BLOCKED/FAILED path.
- allocator + namespace-health watchdog check-ins at their MCP tool sites
(domain modules left pure).
Also: pin `sentry-sdk==2.20.0` (optional), document the six env vars in
`.env.example`, and add `docs/observability/sentry-integration.md` covering
project creation in https://sentry.prgs.cc/, DSN handling, local/dev/prod
config, redaction guarantees, and coexistence with the #612 incident bridge.
Tests: tests/test_sentry_observability.py (36 cases) cover disabled / enabled /
missing-DSN / missing-SDK, redaction, exception capture, workflow-blocker
capture, and cron check-in behaviour. Full suite: 2632 passed, 6 skipped.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>