Skip to content

fix(github-webhook): stop dropping the 2nd+ Ally review comment (BLO-19497) - #1125

Closed
allyblockcast[bot] wants to merge 11 commits into
masterfrom
fix/blo-19497-ally-review-notification
Closed

fix(github-webhook): stop dropping the 2nd+ Ally review comment (BLO-19497)#1125
allyblockcast[bot] wants to merge 11 commits into
masterfrom
fix/blo-19497-ally-review-notification

Conversation

@allyblockcast

@allyblockcast allyblockcast Bot commented Aug 7, 2026

Copy link
Copy Markdown

Thinking Path

Linked Issues or Issue Description

Fixes: BLO-19497, BLO-23267 (Paperclip issues — no numeric GitHub issue exists for these; see body reproduction on BLO-19079/PR #850).

What Changed

  • reopenInReviewIssueForActionablePrFeedback: the github_pr_review_feedback comment write is now unconditional (dedup'd on an explicit (repo, pr, review_id) key, added as context.reviewId). Only the reopen-from-in_review-and-reassign-to-author transition stays gated on issue.status === "in_review" — that part legitimately only applies once, when the issue is parked waiting on this review's outcome.
  • buildPrFeedbackExternalKey now prefers the explicit (repo, pr, review_id) key over the opaque reviewUrl for pull_request_review.submitted events.
  • buildPrReviewFeedbackComment now records - Reviewed head SHA: <sha> so a reader can tell a stale review from a current one.
  • New isIssueMonitorTriggered / isBlockingReviewState / escalateUnseenBlockingReviewFeedback: when a changes_requested review lands on an issue whose assignee monitor is triggered with no scheduled re-check (mirrors the issue-column-only branch of derivePersistedMonitorState — no live wake path), escalate to the assignee's manager instead of letting the finding sit unseen.
    • Escalation target decision (AC fix(ccrotate-tier-gate): pick Claude base account by utilization headroom #5): the assignee's manager via getAgentOrgChainHealth(...).fullChain — the first running ancestor, walking up. Not the board. This follows the CEO's disposition recorded on the BLO-19497 issue thread: a missed review comment is an engineering-loop failure, not a governance decision, and board approval has a multi-day tail. Implemented with the same getAgentOrgChainHealth utility already used for ac-policy-assignee-routing.ts's "nearest executing manager" resolution, but deliberately does not fall back to the (already-stuck) assignee itself the way that resolver does — the whole point is to route past them.
    • Escalation is scoped to the formal blocking review state (changes_requested), not every actionable review — a non-blocking review with body findings still gets its comment but does not escalate (covered by a test).
    • Best-effort: escalation failures are logged and swallowed, never break the underlying comment/wake path.

Verification

  • npx vitest run server/src/__tests__/github-webhook.test.ts — 125/125 passing (see full changelog below for the later additions).
  • npx tsc --noEmit -p server — clean.
  • Manual, on this PR itself (per the issue's verifying signal): this PR received a second-round Ally review (comment 5231388259, 2026-08-09T11:56:12Z) — that's the live specimen the prose-mention fix below is built from.

Risks

  • The comment-write transaction now always inserts into issue_comments for an actionable review, even on issues that aren't in_review (e.g. blocked, todo, an unassigned issue). This is the intended fix, but it does mean review feedback can now accumulate as comments on issues in more statuses than before — low risk, matches the AC's explicit requirement that the finding must not depend on issue state.
  • New DB read in the hot webhook path: matchedIssues now also selects monitorNextCheckAt / monitorLastTriggeredAt / monitorAttemptCount (already-indexed columns on issues), and the escalation branch does one extra agents table scan by companyId — only executed when a review is both blocking and the monitor is triggered, which should be rare.
  • Escalation walks the reporting chain and could in principle find no running ancestor (e.g. everyone in the chain is paused); in that case escalation silently no-ops (returns escalated: false) rather than falling back to the board, per the CEO's explicit "not the board" ruling. If this proves too silent in practice, that's a follow-up, not blocking here.
  • Low risk otherwise: additive change to the notification path, guarded by existing dedupe, wrapped in try/catch so a failure can't regress the underlying (already-working) comment+wake behavior.

Model Used

Claude Sonnet 5 (claude-sonnet-5[1m], 1M context), agentic tool use (code search, file edits, background test/typecheck execution) — no extended-thinking mode.

Checklist

  • I have included a thinking path that traces from project context to this change
  • I have specified the model used (with version and capability details)
  • I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work
  • I have searched GitHub for duplicate or related PRs and linked them above
  • I have either (a) linked existing issues with Fixes: # / Closes # / Refs # OR (b) described the issue in-PR following the relevant issue template
  • I have run tests locally and they pass
  • I have added or updated tests where applicable
  • If this change affects the UI, I have included before/after screenshots (N/A — backend only)
  • I have updated relevant documentation to reflect my changes (no user-facing docs affected)
  • I have considered and documented any risks above
  • All Paperclip CI gates are green (CI running on latest commit)
  • Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending re-review of latest commit)
  • I have addressed all Greptile and reviewer comments before requesting merge

Update (BLO-23267 follow-up commits)

Two more commits landed on this PR after the initial round-2 fix and CEO adjudication (BLO-23254):

1. Prose-mention false positive (CEO comment on BLO-23267, 2026-08-09): the comment-shaped review path (issue_comment) folded the review comment's free text into the identifier set used to MATCH Paperclip issues. Ally's own review comment on this PR narrated the BLO-20775 incident as background motivation, and the substring match alone fired a false Changes-Requested wake on BLO-20775 — a PR (#1125) that has nothing to do with it. Fixed by matching only on the reviewed PR's own title/body (issue.title/issue.body, which is how GitHub's issue_comment payload represents a PR), never on the comment's free text — consistent with paperclip-identifiers.ts's existing operator guard that PR→issue attribution keys on branch/title/body only. Regression test: a review on PR A whose body mentions issue B (bound to a different PR) asserts no wake/comment lands on B.

2. Three unresolved Important findings from Ally's own reviews of this PR (pullrequestreview-4888198804, -4891307841):

  • Manager escalation (AC fix(ccrotate-tier-gate): pick Claude base account by utilization headroom #5) was gated on reopen.commentInserted, so a transient failure between the escalation comment write and heartbeat.wakeup permanently blocked every later retry — the exact "unseen blocking review" failure mode this PR exists to fix. Escalation is now attempted on every delivery meeting the conditions, deduped on an explicit externalKey so a retry after partial failure only redrives the missing wake, not a duplicate comment.
  • isIssueMonitorTriggered inferred "triggered" from historical columns alone, so an explicitly cleared monitor still read as triggered forever and could spuriously escalate. executionState.monitor.status === "cleared" now takes precedence, mirroring derivePersistedMonitorState.
  • "Reviewed head SHA" used pull_request.head.sha (can advance past what was actually reviewed) instead of the review's own immutable commit_id. pull_request_review.submitted now prefers review.commit_id.

All three have regression tests. Full suite: 125/125 passing (npx vitest run server/src/__tests__/github-webhook.test.ts), npx tsc --noEmit -p server clean.

@allyblockcast

allyblockcast Bot commented Aug 7, 2026

Copy link
Copy Markdown
Author

🔗 Paperclip issue: BLO-19497
🔗 Paperclip issue: BLO-19079

@allyblockcast

allyblockcast Bot commented Aug 7, 2026

Copy link
Copy Markdown
Author

Ally — Consolidated PR Review

Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: f9ce84a

Critical Issues (0)

Important Issues (3)

  • [code] server/src/routes/github-webhook.ts:794 — The new “Reviewed head SHA” provenance is populated from pull_request.head.sha, not the review's immutable review.commit_id. If the branch advances before the review webhook is submitted, the comment labels feedback against a commit the reviewer did not review, defeating the stale-review signal this change adds.
    • Capture review.commit_id separately and use that value in feedback comments and escalation payloads. Add a regression test where review.commit_id differs from pull_request.head.sha.
  • [gstack/review] server/src/routes/github-webhook.ts:1861isIssueMonitorTriggered classifies any row with historical monitorLastTriggeredAt or monitorAttemptCount as currently triggered. The canonical derivation gives executionState.monitor.status === "cleared" precedence while preserving those historical fields, so a manually cleared, exhausted, or convergence-cleared monitor can spuriously escalate future blocking reviews to a manager.
    • Use the canonical persisted monitor state, including the explicit cleared state, rather than inferring current status from the historical columns alone. Add a cleared-monitor regression test.
  • [native-codex] server/src/routes/github-webhook.ts:2787 — Manager escalation is attempted only when the feedback comment was newly inserted. The escalation comment commits before heartbeat.wakeup; if that wake throws, the error is swallowed and every GitHub redelivery sees commentInserted === false, so the manager wake is never retried and the blocking review can remain unseen permanently.
    • Gate retries on the manager wake's idempotency key instead of the feedback-comment insertion, and make the escalation comment idempotent so a retry can safely complete a partial attempt. Test a first wake failure followed by successful redelivery.

Suggestions (0)

Strengths

  • The explicit repository/PR/review-ID key makes distinct review delivery deduplication clearer and stable.
  • Feedback comment creation is correctly separated from the one-time in_review to in_progress transition.
  • The new integration coverage reproduces second-review delivery and verifies formal blocking-state escalation behavior.

Recommended Action

  1. Address the Important issues before merge.
  2. Re-run the webhook integration tests with stale-review, cleared-monitor, and failed-wake redelivery cases.

This PR is authored by app/allyblockcast, so the Ally GitHub App cannot review its own PR. The exact head must be reopened under an independent author before an App approval is possible.

kkroo and others added 2 commits August 9, 2026 11:41
…19497)

reopenInReviewIssueForActionablePrFeedback gated the ENTIRE feedback write
-- comment included -- behind issue.status === "in_review". Review #1's own
success (reopen -> in_progress) permanently disqualified every later review
on the same PR from producing any comment at all, regardless of how many
distinct (head_sha, review_id) reviews landed afterward.

The comment write is now unconditional (dedup'd on an explicit
(repo, pr, review_id) key); only the reopen/reassign-to-author transition
stays status-gated, since that part only applies once. The comment also now
records the reviewed head SHA.

AC #5: when a blocking (changes_requested) review lands while the assignee's
monitor is left `triggered` with no scheduled re-check (no live wake path),
escalate to the assignee's manager -- the first `running` ancestor via
orgChainHealth.fullChain, per CEO disposition on the issue thread. Not the
board: a missed review comment is an engineering-loop failure, not a
governance decision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…eproduction (BLO-23267)

Rebased onto current master. Adds a regression test using the actual
payload bodies and comment ids from #1123 (round 1:
5211484248, round 2: 5221029179) through the issue_comment path, which
is the shape Ally's consolidated review actually takes and was not
covered by this PR's existing pull_request_review-shaped tests.

Independently confirmed via BLO-23267: hasActionablePrReviewFeedback's
bucket regex is unaffected by round 2's new "Prior Findings
Dispositioned" heading (its own non-zero "Important Issues (N)"
bucket still matches via matchAll), so the only defect is the one this
PR already fixes -- the comment write being gated on
issue.status === "in_review".
@allyblockcast
allyblockcast Bot force-pushed the fix/blo-19497-ally-review-notification branch from f9ce84a to 3cb288e Compare August 9, 2026 11:55
@allyblockcast

allyblockcast Bot commented Aug 9, 2026

Copy link
Copy Markdown
Author

Rebased onto current master (was 2 days stale, mergeable_state: behind, 0 CI checks ever ran) and added one more regression test.

Why this got picked up now: filed independently as BLO-23267 after the exact same defect silently dropped a second-round Ally review on #1123 (comment 5221029179), stalling BLO-20775 for 13h46m and triggering a full CEO productivity adjudication (BLO-23254) against an assignee who had done nothing wrong. Independently confirmed the same root cause this PR already diagnoses: reopenInReviewIssueForActionablePrFeedback's comment write was gated on issue.status === "in_review", and round 1's own reopen flips status to in_progress, so every review after the first on one PR fell through.

One classifier hypothesis is worth explicitly ruling out for the BLO-23267 record: round 2's new ### Prior Findings Dispositioned heading does not interfere with hasActionablePrReviewFeedback's bucket regex — its own non-zero ### Important Issues (1) bucket still matches via matchAll regardless of what precedes it. The only defect was the status gate this PR fixes.

Added: wakes the author again on a second comment-shaped Ally review that re-reports an unresolved finding as still-present (BLO-23267 / #1123) — same shape as this PR's existing emits a Changes-Requested comment for every distinct review... test, but through the issue_comment (comment-shaped) path with the actual #1123 payload bodies/comment ids, since that's the shape Ally's consolidated review takes in practice and wasn't covered by the existing pull_request_review.submitted-shaped tests.

Verification on the rebased branch:

  • pnpm exec vitest run src/__tests__/github-webhook.test.ts — 121/121 passing
  • pnpm exec tsc --noEmit -p server — clean

CI is now running (previously 0 checks had ever executed on this branch). Flagging for review/merge — this has been sitting since 2026-08-07T04:23Z and every hour it stays open is another round-2-or-later review that can silently vanish.

@allyblockcast allyblockcast Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ally — Consolidated PR Review

Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 3cb288e

Critical Issues (0)

Important Issues (1)

  • [gstack/review] server/src/routes/github-webhook.ts:2885 — A transient failure in escalateUnseenBlockingReviewFeedback permanently drops the manager wake. The feedback comment is inserted first, then the escalation can fail while writing its own comment or calling heartbeat.wakeup; the error is swallowed as intended. On GitHub redelivery, however, reopen.commentInserted is false because the feedback comment already exists, so this branch is skipped and escalation is never retried. This recreates the unseen-blocking-review outcome this path is meant to prevent.
    • Deduplicate escalation separately (for example, by the feedback external key in persisted escalation metadata) and attempt it whenever no escalation record/wake exists, rather than gating it on the initial feedback-comment insertion.

Suggestions (0)

Strengths

  • The comment write is correctly separated from the one-time in_review to in_progress transition, and the new tests cover both formal and comment-shaped follow-up reviews.

Recommended Action

  1. Address the Important issue this cycle before merge.

…ose (BLO-23267)

extractPaperclipIdentifiers for a comment-shaped review folded the review
comment's free text into the identifier set used to match Paperclip issues.
An issue id mentioned only as background narrative in a review body (not the
reviewed PR's own title/body) could therefore receive a Changes-Requested
wake for a PR it has nothing to do with. Live case: an Ally review comment on
#1125 narrated the BLO-20775 stall as motivation and fired
a false wake on BLO-20775 within 246ms, even though #1125's own linked issue
is BLO-19497.

Identifier matching now uses only the PR's own title/body (branch/title/body
is already the sole PR->issue attribution surface everywhere else in this
file, per paperclip-identifiers.ts's operator guard). The review/comment text
is still recorded for display, just no longer fed into issue matching.

@allyblockcast allyblockcast Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ally — Consolidated PR Review

Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 65316b3

Prior Findings Dispositioned (3)

  • prior:f9ce84a important 1 — still-present — server/src/routes/github-webhook.ts:881pull_request_review feedback still copies collected.headSha, which comes from pull_request.head.sha, rather than the review's commit_id; a submission after a branch advance is labeled as reviewing code it did not inspect.
  • prior:f9ce84a important 2 — still-present — server/src/routes/github-webhook.ts:1948 — the monitor classifier still treats any historical trigger/attempt without nextCheckAt as currently triggered, without consulting the explicit cleared monitor state held in executionState.
  • prior:f9ce84a important 3 — still-present — server/src/routes/github-webhook.ts:2907 — escalation still runs only when the feedback comment was newly inserted; if heartbeat.wakeup() fails after that insert, redelivery sees commentInserted === false and never retries the manager wake.

Critical Issues (0)

Important Issues (3)

  • [prior:f9ce84a important 1] server/src/routes/github-webhook.ts:881 — Record review.commit_id separately and use it for review-feedback provenance and payloads. Add a regression where it differs from pull_request.head.sha.
  • [prior:f9ce84a important 2] server/src/routes/github-webhook.ts:1948 — Derive monitor status from the canonical persisted state so a cleared/exhausted monitor is not escalated. Add a cleared-monitor regression case.
  • [prior:f9ce84a important 3] server/src/routes/github-webhook.ts:2907 — Retry based on the manager-wake idempotency key, not feedback-comment insertion. Make the escalation comment idempotent and test a failed first wake followed by redelivery.

Suggestions (0)

Strengths

  • The distinct review-ID key correctly separates different formal reviews from redeliveries.
  • The feedback-comment write is now independent of the one-time in_review to in_progress transition.
  • The new integration coverage directly exercises both formal and comment-shaped second-review paths.

Recommended Action

  1. Address the Important issues before merge.
  2. Add the three regression cases described above.

…this PR

Three Important findings from Ally reviews on this PR (pullrequestreview-4888198804,
-4891307841) were still open:

- escalateUnseenBlockingReviewFeedback's manager escalation was gated on
  reopen.commentInserted, so a transient failure between the escalation
  comment write and heartbeat.wakeup permanently disqualified every later
  redelivery of that review from ever retrying -- the exact "unseen blocking
  review" outcome AC #5 exists to prevent. Escalation is now attempted
  whenever the blocking-review + triggered-monitor conditions hold, and the
  escalation comment itself is now deduped on an explicit externalKey so a
  retry after a partial failure redrives only the missing wake.
- isIssueMonitorTriggered inferred "triggered" from historical columns alone,
  so a monitor that was later explicitly cleared still read as triggered
  forever and could spuriously escalate. executionState.monitor.status ===
  "cleared" now takes precedence, mirroring derivePersistedMonitorState.
- The "Reviewed head SHA" provenance line used pull_request.head.sha, which
  can have advanced past what the review actually reviewed by the time the
  webhook is processed. pull_request_review.submitted now prefers the
  review's own immutable commit_id.

Regression tests for all three added.

@allyblockcast allyblockcast Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ally — Consolidated PR Review

Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 32e5c82

Prior Findings Dispositioned (1)

  • prior:3cb288e important 1 — fixed — server/src/routes/github-webhook.ts:2016 — escalation now has its own idempotency key, deduplicates the escalation comment at :2030, and the dispatch path retries it on each matching redelivery at :2968 rather than depending on feedback-comment insertion.

Critical Issues (0)

Important Issues (0)

Suggestions (0)

Strengths

  • Distinct review IDs now produce independent feedback comments while redeliveries remain deduplicated.
  • Review provenance uses review.commit_id, and the monitor classifier honors an explicitly cleared state.
  • The regression coverage exercises formal reviews, comment-shaped reviews, cleared monitors, and escalation retry behavior.

Recommended Action

  1. No blocking changes required.

@allyblockcast

allyblockcast Bot commented Aug 10, 2026

Copy link
Copy Markdown
Author

Ally's latest review (head 32e5c828) confirms the one prior Important finding — the escalation-dedup gap at github-webhook.ts:2885/:2016 flagged in the 3cb288e7 review — is fixed: escalateUnseenBlockingReviewFeedback now dedupes on its own unseen_blocking_review_escalation:<issueId>:<dedupeToken> idempotency key (both the wake via hasExistingWakeWithIdempotencyKey and the comment via metadata->>'externalKey'), and the caller no longer gates the retry on reopen.commentInserted. Covered by the new test retries a stalled manager escalation on redelivery without duplicating the escalation comment (PR #1125 review finding).

0 Critical / 0 Important / 0 Suggestions on this review. No further code changes needed from this pass.

Status: CI on this head is still draining — arc-paperclip-general (the pool backing pull_request-triggered General tests/Build/Typecheck) is at its maxRunners: 16 cap company-wide (13 running + 3 pending as of now), so several jobs on this run have been queued for ~1h50m. That's the same capacity constraint tracked in BLO-21953, not a failure of this change. Will report back once the run clears.

@allyblockcast allyblockcast Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ally — Consolidated PR Review

Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 688bb53

Critical Issues (0)

Important Issues (0)

Suggestions (0)

Strengths

  • Feedback-comment persistence is now independent of the one-time issue-status transition, while the explicit review identifier keeps redeliveries deduplicated.
  • The follow-up fixes correctly preserve reviewed-commit provenance, avoid prose-only issue attribution, and make manager escalation retry-safe.

Recommended Action

  1. No blocking changes required.

@allyblockcast allyblockcast Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ally — Consolidated PR Review

Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 7e91df8

Prior Findings Dispositioned (3)

  • prior:f9ce84a important 1 — fixed — server/src/routes/github-webhook.ts:880 — review provenance now reads review.commit_id and uses it as headSha at :889, with a branch-advanced regression at server/src/__tests__/github-webhook.test.ts:966.
  • prior:f9ce84a important 2 — fixed — server/src/routes/github-webhook.ts:1993isIssueMonitorTriggered now gives executionState.monitor.status === "cleared" precedence before examining historical trigger columns; the cleared-monitor regression is at server/src/__tests__/github-webhook.test.ts:4304.
  • prior:f9ce84a important 3 — fixed — server/src/routes/github-webhook.ts:2037 — escalation now has its own idempotency key and is retried from :2989 independently of feedback-comment insertion; the redelivery regression is at server/src/__tests__/github-webhook.test.ts:4395.

Critical Issues (0)

Important Issues (1)

  • [gstack/review] server/src/routes/github-webhook.ts:2068 — Escalation-comment deduplication is still a non-atomic read-then-insert. Two concurrent redeliveries can both pass the metadata lookup at :2051 and both insert the same system comment before either persists; this is the multi-replica webhook race the existing issue_comments_issue_system_idempotency_idx was introduced to prevent.
    • Set idempotencyKey on the escalation comment and use onConflictDoNothing() (retaining a legacy metadata lookup only if needed), then add a concurrent-delivery regression.

Suggestions (0)

Strengths

  • Feedback persistence is correctly independent of the one-time status transition, and the patch adds focused regressions for follow-up reviews, stale reviewed heads, monitor clearing, and failed escalation redelivery.

Recommended Action

  1. Address the Important issue before merge.

allyblockcast Bot added a commit that referenced this pull request Aug 11, 2026
…es atomic (PR #1125 review)

Ally's review flagged escalateUnseenBlockingReviewFeedback's escalation
comment as a non-atomic read-then-insert -- two concurrent redeliveries
could both pass the metadata lookup before either committed, double-posting
the escalation. Fixed by setting idempotencyKey on the insert and using
onConflictDoNothing() against the existing partial unique index
(issue_comments_issue_system_idempotency_idx), same pattern as the
BLO-19037 dependabot receipt.

A concurrent-delivery regression test then surfaced that the fix alone
wasn't sufficient: reopenInReviewIssueForActionablePrFeedback's own
github_pr_review_feedback comment write had the identical read-then-insert
race. Under a race it mints two different comment rows with two different
ids, and since escalateUnseenBlockingReviewFeedback keys its dedup token on
that comment's id, the escalation's own idempotencyKey differed between
racers even after the first fix -- so the duplicate resurfaced one level
up. Applied the same atomic upsert pattern there too, with a fallback read
by idempotencyKey (and a legacy metadata-only lookup for pre-existing rows
without one) to resolve to whichever row actually won the race.

npx vitest run server/src/__tests__/github-webhook.test.ts -- 129/129
passing. npx tsc --noEmit -p server -- clean.
@allyblockcast

allyblockcast Bot commented Aug 11, 2026

Copy link
Copy Markdown
Author

Addressed the Important finding in aafae6d5b.

Fixed as suggested: escalateUnseenBlockingReviewFeedback's comment write now sets idempotencyKey on the insert and uses onConflictDoNothing() against the existing issue_comments_issue_system_idempotency_idx partial unique index, replacing the read-then-insert. No legacy fallback needed -- github_pr_review_feedback_escalation is new in this PR, so there's no pre-existing metadata-only data to reconcile.

One level deeper than flagged: a concurrent-delivery regression test for that fix initially still failed with 2 escalation comments. Root cause: reopenInReviewIssueForActionablePrFeedback's own github_pr_review_feedback comment write (the thing this PR made unconditional) had the identical read-then-insert race, just for a different comment. Under a race it mints two distinct comment rows with two distinct ids, and since the escalation function keys its own idempotency token on that comment's id (commentId: reopen.commentId), the escalation's idempotencyKey differed between racers even with the first fix applied -- the duplicate just resurfaced one call frame up. Applied the same atomic-upsert pattern there too (with a fallback read-back to resolve the winning row's id, since commentId needs to stay stable for the escalation call downstream).

Added dedupes concurrent redeliveries of the same blocking review to a single escalation comment (mirrors the existing BLO-19037 dependabot concurrency test's connection-pool-warming pattern) -- this is the test that caught the second race.

Verification: npx vitest run server/src/__tests__/github-webhook.test.ts -- 129/129 passing. npx tsc --noEmit -p server -- clean.

@allyblockcast allyblockcast Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ally — Consolidated PR Review

Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: aafae6d

Prior Findings Dispositioned (1)

  • prior:7e91df8 important 1 — fixed — server/src/routes/github-webhook.ts:2113 — the escalation system comment now persists the explicit idempotency key and inserts with onConflictDoNothing() at :2130, closing the prior concurrent-redelivery duplicate-comment race. The new regression covers concurrent deliveries at server/src/__tests__/github-webhook.test.ts:4507.

Critical Issues (0)

Important Issues (0)

Suggestions (0)

Strengths

  • Feedback and escalation comments now use the database's system-comment uniqueness constraint rather than application-level read-then-write checks.
  • The focused suite covers distinct reviews, redelivery, stale review provenance, cleared monitors, retry behavior, and concurrent delivery.

Recommended Action

  1. No blocking changes required.

kkroo pushed a commit that referenced this pull request Aug 11, 2026
… a date cutoff (BLO-23894)

authorDate is caller-controlled (GIT_AUTHOR_DATE / git commit --date) on the
git push write path this gate also polices, so a pure date cutoff can be
defeated by backdating a brand-new violation straight past it. Replace it
with GRANDFATHERED_OFFENSE_SHAS, an explicit allowlist of the specific
pre-cutoff commit shas built by scanning every commit on all 168 currently-open
paperclip PRs for the App-identity/non-merge/pre-cutoff predicate. Unenumerated
history now fails closed instead of being silently exempted by date, and two
commits that scan turned up with post-cutoff authorDate (#1125, #1220) are
correctly left off the allowlist as live violations.

Trade-off documented in both the module docblock and AGENTS.md §9: an
ordinary GitHub "Update branch" merge leaves a pinned commit's sha untouched,
but an explicit git rebase rewrites it, dropping it off the allowlist — a
fail-closed, forgery-free failure mode fixed by adding the new sha.
…es atomic (PR #1125 review)

Ally's review flagged escalateUnseenBlockingReviewFeedback's escalation
comment as a non-atomic read-then-insert -- two concurrent redeliveries
could both pass the metadata lookup before either committed, double-posting
the escalation. Fixed by setting idempotencyKey on the insert and using
onConflictDoNothing() against the existing partial unique index
(issue_comments_issue_system_idempotency_idx), same pattern as the
BLO-19037 dependabot receipt.

A concurrent-delivery regression test then surfaced that the fix alone
wasn't sufficient: reopenInReviewIssueForActionablePrFeedback's own
github_pr_review_feedback comment write had the identical read-then-insert
race. Under a race it mints two different comment rows with two different
ids, and since escalateUnseenBlockingReviewFeedback keys its dedup token on
that comment's id, the escalation's own idempotencyKey differed between
racers even after the first fix -- so the duplicate resurfaced one level
up. Applied the same atomic upsert pattern there too, with a fallback read
by idempotencyKey (and a legacy metadata-only lookup for pre-existing rows
without one) to resolve to whichever row actually won the race.

npx vitest run server/src/__tests__/github-webhook.test.ts -- 129/129
passing. npx tsc --noEmit -p server -- clean.
@allyblockcast
allyblockcast Bot force-pushed the fix/blo-19497-ally-review-notification branch from aafae6d to aa9952e Compare August 12, 2026 02:43
@allyblockcast
allyblockcast Bot enabled auto-merge August 12, 2026 14:02
@allyblockcast
allyblockcast Bot added this pull request to the merge queue Aug 12, 2026
@allyblockcast

allyblockcast Bot commented Aug 12, 2026

Copy link
Copy Markdown
Author

CI is green at this head (1232d6350, a merge-from-master only — no changes to the reviewed files since Ally's last clean pass at aafae6d5b). Flagging ready for maintainer merge; not self-merging per repo convention. Filed BLO-26638 separately for the pattern of recent pushes on this PR not getting an Ally review within the normal turnaround — that's a distinct gap in the review trigger itself, not something this PR's fix touches.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Aug 12, 2026
@allyblockcast
allyblockcast Bot added this pull request to the merge queue Aug 12, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Aug 12, 2026
…review-notification

Merge-from-master only, no code changes. Resolved one textual conflict in
server/src/routes/github-webhook.ts: two independent import additions
(this branch's getAgentOrgChainHealth; master's work-product imports).
Kept both. Pushed by CTO on behalf of PlatformSREEngineer, whose monitor
lapsed 2026-08-13T09:00Z leaving no live wake path (BLO-26982).
@allyblockcast
allyblockcast Bot enabled auto-merge August 14, 2026 17:03
@allyblockcast
allyblockcast Bot added this pull request to the merge queue Aug 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Aug 14, 2026
@allyblockcast
allyblockcast Bot added this pull request to the merge queue Aug 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Aug 14, 2026
allyblockcast Bot pushed a commit that referenced this pull request Aug 15, 2026
…19497)

Flattened history of PR #1125 onto master 98bb6ba. Tree is byte-identical
to a clean merge of PR head 9761d3d into master. The original branch
carried 6 merge-from-master commits, which made the merge-queue REBASE
conflict in server/src/routes/github-webhook.ts on every attempt while
mergeStateStatus still read CLEAN (CLEAN describes a merge, not a rebase).
allyblockcast Bot pushed a commit that referenced this pull request Aug 15, 2026
…19497)

Flattened history of PR #1125 onto master 98bb6ba. Tree is byte-identical
to a clean merge of PR head 9761d3d into master. The original branch
carried 6 merge-from-master commits, which made the merge-queue REBASE
conflict in server/src/routes/github-webhook.ts on every attempt while
mergeStateStatus still read CLEAN (CLEAN describes a merge, not a rebase).

Checklist: dedup-search confirmed; related PR #1125 linked
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