fix(webhook): subscribe issue_comment.edited/.deleted for cache write-through - #131
Conversation
…-through Closes #129. `src/app.ts:80` only subscribed `issue_comment.created`, so the cache write-through inside `handleIssueComment` (which handles all three actions) never fired for edits or deletes. `comment_cache` rows kept the original body after an edit, and soft-delete on `deleted` never ran. Chat-thread (`src/workflows/ship/scoped/chat-thread.ts`) reads those rows on every turn, so it kept reasoning against pre-edit text the user thought they had retracted or rewritten. The subscription is now the array form `["issue_comment.created", ".edited", ".deleted"]`, mirroring the review-comment block at `src/app.ts:112-121`. The dispatch path is unchanged: the existing early-return at `src/webhook/events/issue-comment.ts:36` still gates `dispatchByIntent` / `dispatchCommentSurface` to created-only, so editing a previously-mentioned comment cannot re-fire the workflow. `writeCommentCacheThrough` is now exported so the new test can drive it directly. Tests cover all three actions plus two source-level invariants (subscription shape and dispatch-gate ordering) that fail loudly if a future refactor reintroduces either side of the bug. Follow-up #130 audits the analogous gap on `issues.*` and `pull_request_review.*` subscriptions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR extends GitHub webhook subscriptions for issue comment events to handle ChangesIssue Comment Webhook Multi-Action Support
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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 fixes a webhook subscription gap where issue_comment.edited and issue_comment.deleted deliveries were never handled, preventing the chat-thread comment_cache write-through from reflecting edits and deletions (and causing the chat-thread executor to reason against stale comment bodies).
Changes:
- Expand
issue_commentwebhook registration to subscribe tocreated,edited, anddeletedactions (matching the existing review-comment pattern). - Keep workflow dispatch behavior unchanged by preserving the created-only dispatch gate inside
handleIssueComment, while still running cache write-through for all actions. - Add regression tests covering DB-backed cache behavior plus source-level invariants guarding subscription shape and dispatch-gate ordering.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/app.ts |
Subscribes to issue_comment.{created,edited,deleted} using the multi-action array form so cache write-through fires for edits/deletes. |
src/webhook/events/issue-comment.ts |
Exports writeCommentCacheThrough (testability) and documents why dispatch remains created-only while cache write-through runs first. |
test/webhook/events/issue-comment-cache.test.ts |
Adds regression coverage for cache insert/update/soft-delete and guards against subscription/ordering regressions via source checks. |
CodeQL flagged the `new RegExp(`['"]${action.replace(/\./g, "\\.")}['"]`)`
construction as "incomplete string escaping or encoding" because it does
not escape backslashes in the input. The action names in the it.each
table are hardcoded literals with no backslashes, so the alert is
defensive only, but a substring check is simpler and removes the entire
class of regex-escape footguns.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
# [1.13.0](v1.12.2...v1.13.0) (2026-05-21) ### Bug Fixes * **deps:** update dependency @anthropic-ai/bedrock-sdk to ^0.29.0 ([#147](#147)) ([eb95c64](eb95c64)) * **deps:** update dependency @anthropic-ai/claude-agent-sdk to ^0.3.0 ([#154](#154)) ([15add8e](15add8e)) * **docs:** anchor-verify src citations to catch silent line-shift rot ([#163](#163)) ([5a67863](5a67863)) * **webhook:** subscribe issue_comment.edited/.deleted for cache write-through ([#131](#131)) ([c84361d](c84361d)) * **webhook:** write-through target_cache on issues/pull_request events ([#130](#130)) ([#132](#132)) ([8b79c10](8b79c10)) ### Features * **prompt:** opt-in cacheable system/user prompt split ([#135](#135)) ([bb80ca7](bb80ca7)) * **review-learnings:** explicit [@bot](https://github.com/bot) remember + autonomous capture ([#160](#160)) ([#162](#162)) ([1c4c53a](1c4c53a)) * **review-learnings:** persistent per-repo review-policy directives ([#161](#161)) ([ba50972](ba50972)) * **scheduler:** scheduled actions via .github-app.yaml ([#159](#159)) ([142a5bc](142a5bc)) * **workflows:** comment-aware structured workflows via LLM discussion digest ([#148](#148)) ([7a6b315](7a6b315))
|
🎉 This PR is included in version 1.13.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
Closes #129.
src/app.ts:80subscribed onlyissue_comment.created, so the chat-threadcomment_cachewrite-through insidehandleIssueComment(which handles all three actions: created/edited/deleted) never fired for edits or deletes. After a user edited a comment to clarify or retract content, the cache kept the original body forever; after a deletion, the soft-delete never ran. The chat-thread executor atsrc/workflows/ship/scoped/chat-thread.tsreads fromcomment_cacheon every turn, so it kept reasoning against pre-edit text the user thought they had changed.The subscription is now the array form
["issue_comment.created", ".edited", ".deleted"], mirroringpull_request_review_comment.*atsrc/app.ts:112-121. Dispatch behaviour is unchanged: the existing early-return atsrc/webhook/events/issue-comment.ts:36still gatesdispatchByIntent/dispatchCommentSurfacetocreated-only, so editing a previously-mentioned comment cannot re-fire the workflow (would be surprising UX and double-bill the user).Diagram
flowchart LR subgraph LIFE["issue_comment lifecycle"] direction TB GHE["User edits or deletes<br/>issue comment"] --> WHK["Webhook delivery"] WHK --> BFR["src/app.ts before<br/>'issue_comment.created' only"]:::bad BFR -->|"created"| BIN["handleIssueComment runs"]:::ok BFR -->|"edited or deleted"| BDR["delivery dropped<br/>cache stays stale"]:::bad BDR --> BST["chat-thread reads<br/>pre-edit body"]:::bad WHK --> AFR["src/app.ts after<br/>array subscription"]:::good AFR --> AIN["handleIssueComment runs<br/>for all three actions"]:::good AIN --> AGT["early-return at line 36<br/>still gates dispatch to created"]:::good AIN --> AWR["writeCommentCacheThrough<br/>updates comment_cache"]:::good AWR --> AFR2["chat-thread sees<br/>current GitHub state"]:::good end classDef bad fill:#7a1f1f,color:#ffffff,stroke:#400,stroke-width:1px classDef ok fill:#3d4f63,color:#ffffff,stroke:#1e2937,stroke-width:1px classDef good fill:#1f5d3a,color:#ffffff,stroke:#063,stroke-width:1pxChanges
src/app.ts— subscription extended from"issue_comment.created"to["issue_comment.created", ".edited", ".deleted"].src/webhook/events/issue-comment.ts— exportedwriteCommentCacheThroughfor testability; added a terse WHY comment above the dispatch early-return to lock in the gate ordering.test/webhook/events/issue-comment-cache.test.ts(new) — 8 tests across three suites:created/edited/deletedpayloads assertingloadConversationreflects the post-edit body and the soft-delete hides the row.src/app.tsand asserts every issue_comment action is present, with the regression shapeapp.webhooks.on("issue_comment.created", ...)explicitly forbidden.Related Issues
issues.*andpull_request_review.*subscriptions (out of scope here to avoid PR bloat).Test plan
bun run typecheckcleanbun run lintclean on changed files (one pre-existing warning onissue-comment.ts:158is from commit 698694b, not introduced here)bun run formatcleanbun test test/webhook/events/issue-comment-cache.test.ts— 8/8 passbun run test— 121/121 files pass withTEST_DATABASE_URLsetsrc/app.tsto the single-action form trips the subscription invariant testsSummary by CodeRabbit
New Features
Tests