feat(observability): installationId on loggers + config-free MCP retry - #189
Conversation
#177: emit installationId on the 4 webhook child loggers and the daemon job-executor child logger (orchestrator-sourced, optional job:payload field) so a per-installation GitHub rate-limit is greppable to its installation. PAT mode leaves it undefined. #184: decouple the resolve-review-thread stdio MCP server from src/config by dropping retry.ts's static root-logger import; default to a config-free pino logger built from log-redaction primitives, writing to stderr to protect MCP JSON-RPC. Closes #177 Closes #184 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 35 minutes and 29 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR threads ChangesInstallation ID Logging Context Threading
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR improves observability by adding installationId to per-request logging surfaces and removes the remaining config-loading path from the resolve-review-thread MCP server retry flow.
Changes:
- Adds optional
installationIdpropagation through webhook loggers, orchestrator job payloads, daemon job execution, schema validation, docs, and tests. - Reworks
retryWithBackoffto use a config-free default pino logger with shared redaction primitives. - Passes the MCP server logger into
retryWithBackoffcalls for delivery-correlated retry logs.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/webhook/events/issues.ts |
Adds conditional installationId to issue event child logger. |
src/webhook/events/pull-request.ts |
Adds conditional installationId to pull request event child logger. |
src/webhook/events/issue-comment.ts |
Adds conditional installationId to issue comment child logger. |
src/webhook/events/review-comment.ts |
Adds conditional installationId to review comment child logger. |
src/shared/ws-messages.ts |
Extends job:payload schema with optional positive installationId. |
test/shared/ws-messages.test.ts |
Covers valid and invalid installationId parsing. |
src/orchestrator/connection-handler.ts |
Captures App installation id and forwards it in accepted jobs. |
src/orchestrator/job-dispatcher.ts |
Adds optional installationId to job accept payload construction. |
src/daemon/job-executor.ts |
Emits forwarded installationId on daemon child logger. |
src/utils/retry.ts |
Replaces root logger import with config-free pino default logger. |
src/mcp/servers/resolve-review-thread.ts |
Passes MCP logger into retry calls. |
docs/operate/observability.md |
Documents installationId as a common log field. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/utils/retry.ts (1)
36-37:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate the stale doc comment.
The default is now the config-free
defaultLog(stderr), not the root logger.📝 Proposed wording fix
- /** Optional scoped logger. Defaults to the root logger when omitted. */ + /** Optional scoped logger. Defaults to the config-free stderr `defaultLog` when omitted. */ log?: Logger;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/retry.ts` around lines 36 - 37, The doc comment on the optional logger property `log?: Logger` is stale; update it to state that when omitted the code uses the config-free `defaultLog` (which writes to stderr) rather than the root logger—edit the comment above `log?: Logger` to mention `defaultLog` (stderr) as the default and remove mention of the root logger so callers have the correct expectation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/utils/retry.ts`:
- Around line 18-25: The current construction of defaultLog passes
process.env["LOG_LEVEL"] directly to pino (in the defaultLog constant using
pino, Logger, REDACT_PATHS and errSerializer), which can throw at module import
if the env value is an unknown non-core level; validate the env value against
pino's core level names (e.g.,
"fatal","error","warn","info","debug","trace","silent") and if it is not one of
those, fall back to "info" before calling pino so that pino is never given an
invalid custom level string (alternatively accept a configured customLevels map
and require mapping only when present, but default to using a core level to
avoid import-time exceptions).
---
Outside diff comments:
In `@src/utils/retry.ts`:
- Around line 36-37: The doc comment on the optional logger property `log?:
Logger` is stale; update it to state that when omitted the code uses the
config-free `defaultLog` (which writes to stderr) rather than the root
logger—edit the comment above `log?: Logger` to mention `defaultLog` (stderr) as
the default and remove mention of the root logger so callers have the correct
expectation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 64e8fa84-c736-4b6e-a0bd-fabfd4e3f7b2
📒 Files selected for processing (12)
docs/operate/observability.mdsrc/daemon/job-executor.tssrc/mcp/servers/resolve-review-thread.tssrc/orchestrator/connection-handler.tssrc/orchestrator/job-dispatcher.tssrc/shared/ws-messages.tssrc/utils/retry.tssrc/webhook/events/issue-comment.tssrc/webhook/events/issues.tssrc/webhook/events/pull-request.tssrc/webhook/events/review-comment.tstest/shared/ws-messages.test.ts
pino 10 throws at construction on a non-core level string. retry.ts's default logger and createMcpLogger read LOG_LEVEL raw (config-free, no zod gate), so a typo'd value would crash an MCP subprocess at module import. Add a shared config-free resolveLogLevel() in log-redaction.ts that falls back to info, and use it in both loggers. Also reword the retry.ts comment: drop the inaccurate "can never drop a line" claim (LOG_LEVEL=error/fatal does suppress warn/error). Addresses CodeRabbit + Copilot review on PR #189. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# [1.14.0](v1.13.0...v1.14.0) (2026-06-30) ### Bug Fixes * **agent-sdk:** pass settingSources [] so SDK ignores cloned PR .claude/settings.json ([#195](#195)) ([153fef3](153fef3)) * **check:** derive scoped-executor scan set from filesystem (dead guard) ([#208](#208)) ([8b0e8ef](8b0e8ef)) * **daemon:** sweep full workspace triple on startup and crash exit ([#239](#239)) ([56fa714](56fa714)) * **idempotency:** gate side-effecting handlers with Valkey claim to prevent redelivery duplicates ([#212](#212)) ([68dacdb](68dacdb)) * **infrastructure:** patch krb5 HIGH CVE-2026-40356 in shared Docker base ([#180](#180)) ([1d1bc3b](1d1bc3b)) * **mcp:** redact Octokit error tool-results and widen GitHub token regex ([#238](#238)) ([675d610](675d610)) * **mcp:** wrap GitHub-touching MCP servers + state-fetchers in retryWithBackoff ([#205](#205)) ([319beb9](319beb9)) * **observability:** canonicalise child-logger entity id under entityNumber ([#178](#178)) ([808ca46](808ca46)) * **security:** gate LLM scanner redacted_body to deletion-only ([#206](#206)) ([d52cf78](d52cf78)) * **security:** set strictMcpConfig to block cloned-PR .mcp.json auto-load ([#210](#210)) ([2c58ec1](2c58ec1)) * **testing:** run colocated src/**/*.test.ts in CI + add drift guard ([#204](#204)) ([5990e0d](5990e0d)) ### Features * **agent-sdk:** block destructive Bash at runtime via PreToolUse hook ([#241](#241)) ([f3132f2](f3132f2)) * **observability:** add 12 structured Pino event families with Zod-strict schemas ([#251](#251)) ([eaad36b](eaad36b)) * **observability:** add queue_wait_ms to dispatcher offer/no-daemon logs ([#207](#207)) ([7a5cfb0](7a5cfb0)) * **observability:** add structured retry.* events ([#225](#225)) ([6713cbf](6713cbf)) * **observability:** emit failed_stage and failed_stage_delta_ms on pipeline.failed ([#244](#244)) ([4f2483c](4f2483c)) * **observability:** emit structured idempotency events on all 4 claimDelivery outcomes ([#242](#242)) ([e1e7f9e](e1e7f9e)) * **observability:** installationId on loggers + config-free MCP retry ([#189](#189)) ([ba09f76](ba09f76)), closes [#177](#177) [#184](#184) * **observability:** log + persist SDK token usage on executions ([#209](#209)) ([5407dcd](5407dcd)) * **observability:** log octokit rate-limit headers via hook.after ([#183](#183)) ([30e1715](30e1715)) * **observability:** periodic fleet-state gauge snapshot ([#186](#186)) ([7429460](7429460)) * **observability:** redact crash logs via uncaughtException/unhandledRejection handlers ([#181](#181)) ([d4248f4](d4248f4)) * **observability:** structured dispatcher + heartbeat log events ([#188](#188)) ([c615bc4](c615bc4)) * **observability:** structured pino logger for stdio MCP servers ([#185](#185)) ([5244e8a](5244e8a)) * **observability:** structured pipeline.stage timing events with delta_ms ([#182](#182)) ([4125971](4125971))
|
🎉 This PR is included in version 1.14.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
Two
area: observabilityfollow-ups, shipped together. #177 emitsinstallationIdon the per-request child loggers (the 4 webhook handlers and the daemon job executor) so an operator triaging a per-installation GitHub rate-limit can pivot from a log line to its installation. #184 decouples theresolve-review-threadstdio MCP server fromsrc/config:retry.tswas statically importing the rootlogger, which readsconfigat module load, so that subprocess ran full config zod-validation at startup. It was the last gap to "all stdio MCP servers config-free" (the other 5 were fixed in #172).Diagram
Changes
#177 — installationId on child loggers
installationIdspread added tocreateChildLoggerinissues.ts,pull-request.ts,issue-comment.ts,review-comment.ts. The comment-handler installation guards stay in place (the owner-allowlist drop line logs throughlogfirst, so the guard can't move up).installationIdis sourced from the orchestrator (it already resolvesinstallation.idto mint the token inconnection-handler.ts) and threaded as a new optional field on thejob:payloadWS schema →job-dispatcher.tshandleJobAccept→ the daemonjob-executor.tschild logger. PAT mode leaves it undefined (no per-installation bucket). Optional field keeps rolling deploys safe.installationIdrow in the observability "Common log fields" table.job:payloadround-trips the new field; a non-positive id is rejected.#184 — config-free resolve-review-thread MCP server
retry.tsdrops the staticlogger as rootLoggerimport. It importsLoggeras a type only (erased at emit, zero runtime coupling) and builds a config-freedefaultLogfromlog-redaction.ts'sREDACT_PATHS+errSerializer, same redaction parity. Writes to stderr (likecreateMcpLogger), so a default-path retry warning can't corrupt an MCP server's stdout JSON-RPC.resolve-review-thread.tspasses{ log }at bothretryWithBackoffsites for deliveryId correlation.[config] WARNINGmarker is gone fromdist/mcp/servers/resolve-review-thread.js(present on baseline before this change).Related Issues
Test plan
Summary by CodeRabbit
Documentation
installationIdfield details for GitHub App installations.New Features
Tests
installationIdfield support.