Skip to content

frontend: peer "gap" sign inverted for lower-is-better metrics (IC + Team dashboards) #1711

Description

@ktursunov

Problem

The peer "gap" (the ±% shown next to a metric = its distance from the peer/department median) has the wrong sign for lower-is-better metrics. It should be + when the value is above the median and when below. Instead the frontend flips the sign by higher_is_better, so for the 18 lower-is-better metrics (Meeting Hours, PR Cycle Time, PR Size, MTTR, Task Dev Time, …) a below-median value shows + and an above-median value shows . IC and Team dashboards both. The value and median are correct — only the derived sign is wrong.

Reproduce

  1. IC dashboard → a lower-is-better metric where the person is below the department median (e.g. Meeting Hours — fewer hours is better).
  2. Read the peer gap.

Expected: below median → −%. Actual: below median → +%.

Real example (Engineering / Meeting Hours, median ≈ 2.69 h): member at 2.45 h (below) shows +9%; member at 2.74 h (above) shows −2%.

Root cause

Gap is higher_is_better ? (value − median) : −(value − median) — the second branch negates the sign for every lower-is-better metric. The intended convention is direction-agnostic: gap = (value − median) / |median| everywhere, with good/bad color driven by higher_is_better (not by the sign).

Examples

Sign must track value vs median only. Direction changes the color, never the sign.

Metric Dir. Value Median vs median Current (wrong) Correct Color
PRs Merged higher-better 20 10 above +100% +100% green (good)
PRs Merged higher-better 5 10 below −50% −50% red (bad)
Meeting Hours lower-better 2.45 2.69 below +9% −9% green (good)
Meeting Hours lower-better 2.74 2.69 above −2% +2% red (bad)
PR Cycle Time lower-better 30 h 20 h above −50% +50% red (bad)

Higher-better metrics already read correctly; every lower-better metric is inverted. Note the last rows: a gap can be good (below median on meeting hours) and a + gap can be bad (above median on cycle time) — which is exactly why the sign must come from value−median and the color from direction, kept separate.

Fix checklist

Sign shown to the user (the visible bug):

Sign used as a "badness" ranking key — re-express via higher_is_better so the new sign doesn't break the pick/sort:

Single source of truth:

  • relativeGap() in lib/peers.ts#L134-L140 — currently higher_is_better ? (median − value) : (value − median) (opposite of the counters/heatmap flip → the app disagrees with itself). Make this the one direction-agnostic definition and route every site above through it.

Metadata

Metadata

Assignees

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions