Add an unfiltered people stats table - #513
Conversation
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]>
There was a problem hiding this comment.
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
/peopleand/partials/people/tableendpoints pluspeople_table.pyto 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.
| <th | ||
| {% if header.numeric %}class="numeric"{% endif %} | ||
| aria-sort="{{ header.aria_sort }}" | ||
| > | ||
| <a href="{{ url_for('people', **header.sort_query) }}">{{ header.label }}</a> | ||
| </th> |
|
@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]>
There was a problem hiding this comment.
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),
)
|
@conrad-vanl I took a smaller pass at the visibility problem in #514: |
The homepage leaderboard is
team: engineeringonly. This adds/people, a table of every person inconfig.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
/peopleshell plus/partials/people/table-prs_merged,person, …)author.login == "cursor"). No extra GitHub search. No Claude/Copilot columnscollect_regression_attributions(window)via a newtally_regressions_by_loginhelper. The homepage 30-day cache is not used hereTradeoffs
reviewed-by:search is a broader set than the APPROVED-only count we show—, not a measured zero, so it does not enter σ. People with a blank GitHub login stay known zerosis:closed is:pr author:…). That under-matches Cursor-credited PRs. Changing it would change another page_person_metricsis unchanged. The table consumes the new tally helper; migrating the person page is follow-upBlast radius
templates/partials/time_window_controls.htmlcan takeextra_queryhidden fields. Index and person pages omit it and keep current behaviorformat_stdev_tooltiptakes an optionalcohortlabel. Default remains"eng"github.pyis unchangedTo test
Review app (wait for SHA
41f7818to 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 1Without API keys, Casey, Justin Isenhart, and Tyler Vance show
0. Everyone else shows—.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=7and 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_querychange. No hiddensortfield.Posted by Cursor on behalf of @conrad
To show artifacts inline, enable in settings.