Skip to content

bug(review): Trigger's idempotency check treats a dead Running row as up-to-date, blocking re-review after the reviewer terminal is killed #342

@neversettle17-101

Description

@neversettle17-101

Bug

If a reviewer pass is killed mid-run (e.g. the user closes/cancels the reviewer's terminal directly instead of letting it finish), retrying review for the same commit returns "Review is already up to date for this commit." even though no review actually completed.

Analyzed against: a8a3056
Confidence: High — traced exact code path

Root Cause

Engine.Trigger (backend/internal/review/review.go:189-193) decides idempotency purely from row existence + status, with no liveness check:

if existing, ok, err := e.store.GetReviewRunBySessionAndSHA(ctx, workerID, targetSHA); err != nil {
    return TriggerResult{}, err
} else if ok && existing.Status != domain.ReviewRunFailed {
    return TriggerResult{Run: existing, ReviewerHandleID: review.ReviewerHandleID, Created: false}, nil
}

Any non-Failed row for (session, targetSHA) — including one still Running — short-circuits with Created: false, which the frontend renders as "Review is already up to date" (frontend/src/renderer/components/SessionInspector.tsx:208).

Nothing transitions a Running row to Failed/Complete when the underlying reviewer process dies outside of Submit(). Submit (review.go:278-317) only fires when the reviewer agent itself reports a verdict. Killing the terminal bypasses that entirely, so the row stays Running forever. The only place that checks actual liveness (e.launcher.Alive, review.go:247) is in the "reuse a live pane" branch further down — which is never reached because the idempotency check above already returned.

Fix

In the idempotency check, when existing.Status == domain.ReviewRunRunning, call e.launcher.Alive(ctx, review.ReviewerHandleID) before short-circuiting. If the handle is dead, mark the run Failed (reuse the existing failRun pattern) and fall through to spawn a fresh review instead of returning the stale row.

Impact

A worker session can get permanently stuck unable to re-review a commit once a reviewer pass is killed mid-run, with no workaround short of pushing a new commit.

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions