Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/services/recommendation-outcomes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,11 @@ function pullRequestOutcomeState(
if (hasChangesRequestedReview(pr)) return "rejected";
if (hasPositiveOpenPullRequestSignal(pr)) return "improved";
}
if (createdAt >= actionAt || updatedAt > actionAt) return "accepted";
// A PR that already merged before the action cannot be a positive outcome of it. Without this guard a
// pre-action merge that merely receives a later updatedAt bump (e.g. a comment) would fall through to
// "accepted" -- mirror the "merged" branch's own >= actionAt discipline so it stays stale/ignored.
const mergedBeforeAction = Number.isFinite(mergedAt) && mergedAt < actionAt;
if (!mergedBeforeAction && (createdAt >= actionAt || updatedAt > actionAt)) return "accepted";
if (actionAgeMs >= staleAfterMs) return "stale";
return "ignored";
}
Expand Down
18 changes: 18 additions & 0 deletions test/unit/recommendation-outcomes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,24 @@ describe("recommendation outcome feedback", () => {
}),
).toMatchObject({ outcomeState: "stale", outcomeTargetType: "pull_request" });

// A pre-action merge that merely receives a later updatedAt bump (e.g. a comment) must not be
// credited as the positive "accepted" outcome of the recommendation.
expect(
classifyRecommendationOutcome({
...base,
action: action(run, 2, { targetRepoFullName: "owner/old-merged", targetPullNumber: 62 }),
pullRequests: [
prRecord(62, "owner/old-merged", {
state: "merged",
mergedAt: "2026-04-01T00:00:00.000Z",
createdAt: "2026-03-01T00:00:00.000Z",
updatedAt: "2026-05-10T00:00:00.000Z",
}),
],
issues: [],
}),
).toMatchObject({ outcomeState: "stale", outcomeTargetType: "pull_request" });

expect(
classifyRecommendationOutcome({
...base,
Expand Down