Skip to content

fix(mirror): resolve solved_by_pr from the effective (most-recent) close#189

Open
JSONbored wants to merge 1 commit into
entrius:testfrom
JSONbored:fix/solved-by-pr-frozen-closedat
Open

fix(mirror): resolve solved_by_pr from the effective (most-recent) close#189
JSONbored wants to merge 1 commit into
entrius:testfrom
JSONbored:fix/solved-by-pr-frozen-closedat

Conversation

@JSONbored

Copy link
Copy Markdown
Contributor

Summary

  • issues.solved_by_pr is resolved from the issue's effective (most-recent) close instead of the frozen issue.closedAt.
  • Fixes the NOT_PLANNED → reopen → COMPLETED-by-PR case, where both the ClosedEvent.closer path and the closing-references fallback currently return null for a genuinely solved issue.
  • New effectiveClosedAt helper derives the current close time from the latest CLOSED_EVENT; both selectClosingPrFromTimeline and selectClosingPrFromClosingRefs use it. No schema change, no new query fields (both paths already fetch the close timeline).

Root cause

GitHub freezes issue.closedAt at the first time the issue entered the closed state and does not advance it on a re-close. Both resolution sites in github-fetcher.service.ts compare against issue.closedAt:

  • selectClosingPrFromTimeline requires ev.createdAt === closedAt, so it matches the original NOT_PLANNED ClosedEvent (whose closer is null) and skips the later COMPLETED event whose closer is the merged PR → null.
  • selectClosingPrFromClosingRefs filters mergedAt <= closedAt, so the solver PR (merged at the re-close time, after the frozen closedAt) is rejected → null.

This is the unhandled re-close case inside the anchors added by #123 (the closedAt anchor, added precisely to attribute reopen-reclose cycles to the current closer) and #169 (the mergedAt <= closedAt gate). Both assume closedAt reflects the current close; the fix restores that assumption by deriving the effective close from the timeline.

Proof — real instances in tracked repositories

All currently CLOSED/COMPLETED, solved by a merged same-repo PR, currently stored with solved_by_pr = NULL:

Repository Issue Solver PR issue.closedAt (frozen, NOT_PLANNED) COMPLETED re-close
entrius/gittensor #1289 #1290 (base test) 2026-05-22T20:38:34Z 2026-05-29T22:22:18Z
entrius/gittensor #1334 #1335 2026-05-22T07:53:33Z 2026-05-26T18:37:10Z
entrius/allways #176 #191 2026-05-08T23:04:04Z 2026-05-08T23:37:54Z
touchpilot/touchpilot #151 #152 2026-06-02T12:32:50Z 2026-06-04T16:42:48Z
touchpilot/touchpilot #64 #65 2026-05-22T17:06:25Z 2026-05-28T13:32:12Z

With the fix, entrius/gittensor#1289 resolves to 1290 (was null).

The fix preserves every other case

  • Single COMPLETED close by a merged PR → unchanged (the latest CLOSED_EVENT is that close).
  • Currently NOT_PLANNED issue with an earlier COMPLETED+PR close (closed → reopened → closed NOT_PLANNED) → still null: the latest CLOSED_EVENT is the NOT_PLANNED one, so no false attribution.
  • Also corrects the ordinary 1-second closedAt vs ClosedEvent.createdAt skew on single closes, which previously resolved only via the fallback.

Related Issues

Fixes #188

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Other (describe below)

Testing

  • npm run build in packages/das passes
  • npm run lint passes
  • npm run format:check passes
  • git diff --check clean
  • Traced selectClosingPr against the live timelines of all five instances above: returns the solver PR where it previously returned null, and returns null for the currently-NOT_PLANNED re-close case.

Checklist

  • I have read the Contributing Guide
  • Code builds without errors
  • New and existing behavior verified (see Testing)
  • Documentation updated (the fetchIssueClosingPr docstring now reflects the effective-close anchor)
  • No unnecessary dependencies added

GitHub freezes issue.closedAt at the first close, so both selectClosingPr
paths mis-resolve a NOT_PLANNED -> reopen -> COMPLETED-by-PR issue: the
timeline anchor matches the first (NOT_PLANNED, closer=null) event and the
fallback rejects the solver PR (merged after the frozen closedAt). Derive the
effective close time from the most-recent CLOSED_EVENT and use it at both
sites. solved_by_pr now resolves to the real solver; a currently-NOT_PLANNED
issue still resolves to null.
@xiao-xiao-mao xiao-xiao-mao Bot added the bug Something isn't working label Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] solved_by_pr is null for issues closed NOT_PLANNED, reopened, then solved by a merged PR (closer resolution anchors on the frozen issue.closedAt)

1 participant