Skip to content

[BUG]: Bus Factor metric on Contributors page always evaluates to 0 (UNKNOWN) due to property mismatch #230

Description

@Dotify71

Bug Description

On the Contributors page (/contributors), the Bus Factor Risk metric card always evaluates to Bus Factor: 0 with risk level UNKNOWN and subtitle 0 contributors own over 50% of total commits. Knowledge distribution is heavily skewed., regardless of the organization analyzed.

This is caused by a property name mismatch between model.contributors and computeBusFactor:

  • computeBusFactor in src/services/analytics.js expects contributor objects to have a .contributions property:
    const total = contributors.reduce((s, c) => s + c.contributions, 0)
  • However, in buildAnalyticalModel (src/services/analytics.js), aggregate contributor objects in model.contributors store their commit counts under .totalContribs:
    contributorMap[c.login] = {
      login: c.login,
      totalContribs: 0,
      ...
    }
  • When ContributorsPage.jsx passes scopedContributors (from model.contributors) into computeBusFactor(scopedContributors), c.contributions is undefined.
  • As a result, 0 + undefined results in NaN. Since !NaN evaluates to true, if (!total) immediately triggers and returns { factor: 0, risk: 'unknown' } on every run.

Steps to Reproduce

  1. Open OrgExplorer and analyze any organization (e.g. AOSSIE-Org).
  2. Navigate to the Contributors page (/contributors).
  3. Look at the Bus Factor Risk card at the top left.
  4. Note that it displays Bus Factor: 0 and UNKNOWN instead of calculating the contributor concentration.

Logs and Screenshots

Observed behavior in the UI:

  • Title: Bus Factor: 0
  • Badge: UNKNOWN
  • Subtitle: 0 contributors own over 50% of total commits. Knowledge distribution is heavily skewed.
  • Risk Level: UNKNOWN
  • Progress bar: 25%

Proposed fix in src/services/analytics.js:

export function computeBusFactor(contributors = []) {
  if (!contributors.length) return { factor: 0, risk: 'unknown' }
  const getCount = c => (typeof c === 'number' ? c : (c.contributions ?? c.totalContribs ?? 0))
  const total = contributors.reduce((s, c) => s + getCount(c), 0)
  if (!total) return { factor: 0, risk: 'unknown' }
  let cum = 0
  for (let i = 0; i < contributors.length; i++) {
    cum += getCount(contributors[i])
    if (cum / total > 0.5) {
      const f = i + 1
      return { factor: f, risk: f <= 1 ? 'critical' : f <= 2 ? 'high' : 'healthy' }
    }
  }
  return { factor: contributors.length, risk: 'healthy' }
}

Environment Details

  • OS: macOS / Linux / Windows
  • Browser: Chrome / Firefox / Safari
  • Application version: 1.0.0 (main branch)

Impact

High - Major feature is broken

Code of Conduct

  • I have joined the Discord server and will post updates there
  • I have searched existing issues to avoid duplicates

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions