File size: 1,942 Bytes
50841a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
45
46
47
48
49
/**
 * "Fix these first" prioritization. Turns the week's bug reports into a
 * ranked action list so a team knows what to do next, and a program owner
 * can see where effort matters most across all domains.
 *
 * Priority score per issue = pages affected × severity weight × people
 * reach. Each factor is something we actually measure:
 *   - pages affected: how widespread (one fix often clears many pages)
 *   - severity: Critical/High/Medium/Low from axe impact + frequency
 *   - reach: the most-affected disability group's population prevalence
 *     (from the WCAG→FPC mapping), so issues hurting more people rank up.
 */

const SEVERITY_WEIGHT = { Critical: 4, High: 3, Medium: 2, Low: 1 };

/** Priority score for one bug report (higher = fix sooner). */
export function priorityScore(bug) {
  const pages = bug.frequency?.pages_affected ?? 0;
  const sev = SEVERITY_WEIGHT[bug.severity] ?? 1;
  // Reach: max prevalence among affected groups (0..1); default small so
  // unmapped issues still rank by pages × severity.
  const reach = bug.impact?.groups?.length
    ? Math.max(...bug.impact.groups.map((g) => g.prevalence ?? 0))
    : 0.05;
  return Math.round(pages * sev * (1 + reach) * 100) / 100;
}

/** Rank a domain's bugs into a "fix these first" list (top `n`). */
export function rankBugs(bugs, n = 10) {
  return bugs
    .map((b) => ({ ...b, priority: priorityScore(b) }))
    .sort((a, b) => b.priority - a.priority)
    .slice(0, n);
}

/**
 * Fleet-wide worst offenders: flatten ranked bugs across all domains into
 * a single ordered list, tagged with their domain.
 */
export function fleetWorstOffenders(perDomain, n = 20) {
  const all = [];
  for (const { target, bugs } of perDomain) {
    for (const b of bugs) {
      all.push({ domain: target.domain, key: target.key, week: b._week, ...b, priority: priorityScore(b) });
    }
  }
  return all.sort((a, b) => b.priority - a.priority).slice(0, n);
}