fix(core): dedupe blocker creation — one escalation, one blocker/webhook (#735) - #809
Conversation
…er/webhook (#735) Adapters (verification_wrapper/react_agent/plan agent/builtin) persist a blocker before returning AgentResult(status="blocked"), then runtime.execute_agent creates a second one from result.blocker_question. blockers.create had no dedupe and fired the outbound webhook per call, so every blocked run produced two OPEN blockers + two blocker.created webhooks. Dedupe on (workspace_id, task_id, question, OPEN): if a matching OPEN blocker already exists, return it without inserting a row, emitting an event, or firing a webhook. First writer wins, so the agent-origin blocker is kept over the runtime's human-origin duplicate. Single-point fix covers every double-create path (allowed by the acceptance criteria).
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 43 minutes Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Review — fix(core): dedupe blocker creation (#735)Overall: The fix is correct, well-scoped, and ready to ship. One non-standard comment prefix and a couple of missing edge-case tests are the only items worth addressing. What's rightSingle-point fix covers all callers. Deduping inside NULL task_id handled correctly. Using Column ordering matches Test matrix is solid for the core cases. Deduped, distinct questions, answered-status scoping, and null task_id are all covered. Issues / suggestions1. Non-standard comment prefix — minor # ponytail: read-then-insert, no UNIQUE index — safe here because ...
# NOTE: read-then-insert with no UNIQUE index — safe because the two callers
# run sequentially in the same process. Concurrent cross-process creates could
# race; a partial UNIQUE index on (workspace_id, task_id, question) WHERE status='OPEN'
# would make this atomic.2. Two edge cases not tested — low risk but worth having The WHERE clause is correct (verified by reading the query), but there are no tests that exercise:
3. Mock assertions outside In with patch("codeframe.notifications.webhook.WebhookNotificationService") as MockSvc:
instance = MockSvc.return_value
first = blockers.create(...)
second = blockers.create(...)
assert second.id == first.id
assert second.created_by == first.created_by
instance.send_event_background.assert_called_once()
assert len(blockers.list_open(workspace)) == 1 # no webhook dependency, fine outsideNot an issue (for completeness)
Verdict: Approve with the above suggestions. The two missing edge-case tests (#2) are the only items I'd encourage adding before merge; the rest are cosmetic. |
|
Thanks for the review. Addressed in 243d115:
All findings were minor/cosmetic; no correctness changes to the fix itself. |
Follow-up — all previous items addressed ✓Checked commit 243d115 against my earlier review:
No new issues introduced. The fix is minimal, single-point, and the test matrix now covers all the meaningful boundary conditions. Approving. |
Summary
Fixes #735 — every blocked run produced two OPEN blockers and two
blocker.createdwebhooks.Root cause: adapters (
verification_wrapper,react_agent, planagent,builtin) persist a blocker before returningAgentResult(status="blocked"), thenruntime.execute_agent(runtime.py:825) creates a second one fromresult.blocker_question.blockers.createhad no dedupe and fired the outbound webhook per call.Fix
Dedupe in
blockers.createon(workspace_id, task_id, question, status=OPEN)— the acceptance criteria explicitly allows this. If a matching OPEN blocker already exists, return it without inserting a row, emitting aBLOCKER_CREATEDevent, or firing a webhook. First writer wins, so the agent-origin blocker is kept over the runtime's human-origin duplicate.Single-point fix — covers every double-create path (verification_wrapper, react, plan, external), not just runtime.
Acceptance criteria
(task_id, question, OPEN)— first writer owns it.Verification (outcome evidence)
Simulating the real adapter→runtime double-call:
Only one
BLOCKER_CREATEDevent emitted. Tests:tests/core/test_blockers_webhook.py(dedupe, distinct-question, answered-status, null-task_id cases) + 99 adjacent blocker/runtime/adapter tests pass;ruffclean.Known limitations
ponytail:comment).