File size: 1,633 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
 * Lifecycle detectors: stale need_details, stale defer, closed-externally.
 */

export function isStaleNeedDetails(issue, thresholdDays, now = new Date()) {
  const authorLogin = issue.author?.login;
  let lastAuthorActivity = issue.createdAt;
  for (const c of issue.comments ?? []) {
    if (c.author?.login === authorLogin) {
      if (new Date(c.createdAt).getTime() > new Date(lastAuthorActivity).getTime()) {
        lastAuthorActivity = c.createdAt;
      }
    }
  }
  const daysSilent = Math.floor(
    (now.getTime() - new Date(lastAuthorActivity).getTime()) / 86400_000
  );
  return {
    stale: daysSilent >= thresholdDays,
    daysSilent,
    lastAuthorActivity,
  };
}

export function isStaleDefer(meta, thresholdDays, now = new Date(), fallbackDate = null) {
  const classifiedAt = meta?.snapshot?.classified_at || fallbackDate;
  if (!classifiedAt) return { stale: false, daysInDefer: 0 };
  const daysInDefer = Math.floor((now.getTime() - new Date(classifiedAt).getTime()) / 86400_000);
  return { stale: daysInDefer >= thresholdDays, daysInDefer };
}

export function detectClosedExternally(issue, meta) {
  const issueState = String(issue.state ?? "").toUpperCase();
  const snapshotState = String(meta?.snapshot?.state ?? "open").toLowerCase();
  if (issueState !== "CLOSED") return { flagged: false };
  if (snapshotState === "closed") return { flagged: false };
  const stateReason = issue.stateReason ?? null;
  const out = { flagged: true, closedAt: issue.closedAt, stateReason };
  if (stateReason === "COMPLETED") {
    out.warningMessage = "possibly delivered by external work";
  }
  return out;
}