Skip to content

Add an unfiltered people stats table - #513

Closed
conrad-vanl wants to merge 3 commits into
mainfrom
cursor/people-stats-table-d342
Closed

Add an unfiltered people stats table#513
conrad-vanl wants to merge 3 commits into
mainfrom
cursor/people-stats-table-d342

Conversation

@conrad-vanl

@conrad-vanl conrad-vanl commented Aug 26, 2026

Copy link
Copy Markdown
Member

The homepage leaderboard is team: engineering only. This adds /people, a table of every person in config.yml, with the same date-range controls as the rest of Bug Board and click-to-sort columns.

Why

We needed a roster view that is not filtered the way / is, and that can sort by merged PRs, reviews, Cursor credit, and regression blame for a chosen window.

Scope

  • /people shell plus /partials/people/table
  • People link in the header menu
  • Columns: PRs merged, PRs reviewed, Agent PRs, Agent share, regressions authored, regressions approved
  • σ vs every row on this table, including known zeros for people with no GitHub login
  • Default sort: PRs merged descending. Sort token is one query param (-prs_merged, person, …)
  • Date presets 7 / 30 / 90. Changing the window keeps the current sort
  • Cursor credit is split out of the bulk merged-PR lists (author.login == "cursor"). No extra GitHub search. No Claude/Copilot columns
  • Live collect_regression_attributions(window) via a new tally_regressions_by_login helper. The homepage 30-day cache is not used here
  • The table partial returns within 20s so Heroku's 30s router does not 503. Slow regression blame is marked unavailable; a refresh can pick it up from cache

Tradeoffs

  • Reviewed cells are plain text. A reviewed-by: search is a broader set than the APPROVED-only count we show
  • A failed GitHub or Linear load is a notice plus , not a measured zero, so it does not enter σ. People with a blank GitHub login stay known zeros
  • Merged-PR links reuse the existing person-page search (is:closed is:pr author:…). That under-matches Cursor-credited PRs. Changing it would change another page
  • _person_metrics is unchanged. The table consumes the new tally helper; migrating the person page is follow-up

Blast radius

  • templates/partials/time_window_controls.html can take extra_query hidden fields. Index and person pages omit it and keep current behavior
  • format_stdev_tooltip takes an optional cohort label. Default remains "eng"
  • github.py is unchanged

To test

Review app (wait for SHA 41f7818 to deploy; the previous build 503'd the table partial at 30s):

Local fallback:

source venv/bin/activate
gunicorn app:app --bind 127.0.0.1:8000 --workers 1

Without API keys, Casey, Justin Isenhart, and Tyler Vance show 0. Everyone else shows .

ruff check .
ruff format --check .
mypy .
python -m unittest discover -s tests -p 'test_*.py'

Screenshots from local, no API keys:

People table default: 30d, sorted by PRs merged descending. Blank GitHub rows are 0; others are unavailable dashes.

Default /people. Tyler Vance, Justin Isenhart, and Casey are known zeros. Other rows are because credentials are missing.

People table sorted A-Z by name, URL has days=30 and sort=person

After clicking Person. URL is /people?days=30&sort=person.

People table on the 7d preset with sort still in the URL

7d pressed, URL has days=7 and a sort token. This shot was taken before a gunicorn reload, so numeric cells look like zeros across the board. After reload, blank-GitHub rows stay 0 and the rest become .

Mobile 390px people page with hamburger open to People, Apps, Projects, DAGs

390px viewport. Hamburger still has People. The table scrolls horizontally.

Homepage date controls with no hidden sort field

Index after the extra_query change. No hidden sort field.

Posted by Cursor on behalf of @conrad

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

cursoragent and others added 2 commits August 26, 2026 17:39
Ship /people with every configured engineer, windowed PR and regression
counts, Cursor agent credit, and column sort. Reviewed cells stay plain
text so the APPROVED-only count is not linked to a broader search.

Co-authored-by: Conrad VanLandingham <[email protected]>
Vulture only sees Python. Header, link, and team fields are used in
Jinja and as sort tie-breaks; read them in the builder so CI agrees.

Co-authored-by: Conrad VanLandingham <[email protected]>
@conrad-vanl
conrad-vanl marked this pull request as ready for review August 26, 2026 18:02
Copilot AI lite review requested due to automatic review settings August 26, 2026 18:02
@redreceipt
redreceipt temporarily deployed to bug-board-cursor-people-7op9xy August 26, 2026 18:02 Inactive

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new /people roster view to Bug Board that shows unfiltered per-person activity across a selectable time window, with sortable columns and regression attribution metrics, complementing the existing engineering-filtered homepage leaderboard.

Changes:

  • Adds /people and /partials/people/table endpoints plus people_table.py to build sortable, window-aware roster stats (merged PRs, reviews, agent credit, regressions).
  • Introduces regression tally helpers (RegressionRef, RegressionTally, tally_regressions_by_login) and extends stdev tooltips to support a cohort label.
  • Updates UI templates/nav and CSS to render the new table, preserve sort across date controls, and style σ badges; adds comprehensive unit tests.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
app.py Adds /people page and /partials/people/table partial route, wiring time window + sort parsing.
people_table.py New stats assembly layer (roster loading, bulk fetch, sort model, σ badges, links) backing the people table.
regressions.py Adds typed regression tally structures and a helper to compute per-login authored/approved counts within a window.
person_stats.py Extends format_stdev_tooltip to support a customizable cohort label (default unchanged).
templates/people.html New People page shell that loads the table partial client-side while preserving window + sort params.
templates/partials/people_table.html New partial rendering sortable table headers, metric cells, notes, and σ badges.
templates/partials/time_window_controls.html Adds support for passing through extra query params (e.g., sort) via hidden inputs.
templates/base.html Adds “People” to the header navigation menu.
static/styles.css Adds styling for people table layout + sort indicators and σ badge tones.
tests/test_people_table.py New unit tests for roster inclusion, sorting, availability/zero semantics, links, and σ tooltip cohort behavior.
tests/test_regressions.py Adds coverage ensuring regression tallies respect the inducing PR merged-at window and normalize logins/URLs.
tests/test_person_stats.py Updates tests for the new tooltip cohort parameter.
tests/test_navigation.py Adds navigation and routing assertions for /people and its partial.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +13 to +18
<th
{% if header.numeric %}class="numeric"{% endif %}
aria-sort="{{ header.aria_sort }}"
>
<a href="{{ url_for('people', **header.sort_query) }}">{{ header.label }}</a>
</th>
@redreceipt

Copy link
Copy Markdown
Member

@conrad-vanl review app didn't work. what is the problem you wanna solve here? just showing everyone without the need to export?

Live regression blame was blocking /partials/people/table until the
router returned 503. Wait at most 20s, keep whichever source finished,
and leave unfinished work running so a refresh can hit cache.

Co-authored-by: Conrad VanLandingham <[email protected]>
Copilot AI review requested due to automatic review settings August 26, 2026 21:19
@redreceipt
redreceipt temporarily deployed to bug-board-cursor-people-7op9xy August 26, 2026 21:19 Inactive

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

people_table.py:308

  • When sorting ascending on a numeric column, unavailable cells currently sort to the top because they use a magnitude of -inf. That makes ascending sorts look wrong (missing data should sort last regardless of direction). Adjust the row sort key to treat the sentinel -inf as +inf when direction is ASC.
        if order.key is ColumnKey.PERSON:
            return (0.0, name, self.person.team)
        magnitude, _name = self.cells[_COLUMN_INDEX[order.key]].sort_key
        return (magnitude, name, self.person.team)

people_table.py:557

  • format_stdev_tooltip(baseline, ...) is recomputed for every non-missing row in _stdev_badges, even though it’s identical for the whole column/window. This adds avoidable work (including repeated baseline/stdev calculations) for larger rosters; compute the tooltip once (lazily) and reuse it.
        badges.append(
            StdevBadge(
                label=format_stdev_label(z),
                tooltip=format_stdev_tooltip(baseline, cohort=STDEV_COHORT_LABEL),
                tone=stdev_tone(z),
            )

@redreceipt

Copy link
Copy Markdown
Member

@conrad-vanl I took a smaller pass at the visibility problem in #514: /team defaults to engineering, Show everyone opts into the full configured roster, raw activity metrics are sortable columns (PRs merged is first and the default sort), and CSV lives with the table. It removes the homepage leaderboard/score instead of creating a second people surface. Would this direction solve what you were aiming for here?

@redreceipt redreceipt closed this Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants