Skip to content

feat: say which GitHub account each commit on a pull request landed under - #582

Merged
omartelo merged 1 commit into
mainfrom
feat/commit-authorship-on-pr
Sep 10, 2026
Merged

omartelo merged 1 commit into
mainfrom
feat/commit-authorship-on-pr

Conversation

@omartelo

Copy link
Copy Markdown
Collaborator

Closes #576.

A project's gh account governs what lich asks gh. It has never governed the push, which still rides the remote's ssh key and signs with the global user.email. A pull request could therefore be read by one account and its commits land under another, with no error anywhere, and the Version Control pane refused to say so because comparing the two strings is a false-positive farm.

Which of the two routes, and why

The issue asked for both to be measured first.

gh api user/emails is out. Measured against both authenticated accounts on this machine: gh's own login requests gist, read:org, repo and no user scope, so the call is refused. The refusal is HTTP 404 Not Found, indistinguishable from a genuine not-found by status alone. Only gh's stderr names the missing scope, and stderr never reaches lich's UI. The pane could not tell a refusal from a match, which is the question the issue raised.

GitHub had already answered. gh pr view --json commits is a call lich already makes, and it carries the account GitHub resolved each commit's author email to, checked against the verified addresses of every account. Equality becomes set membership on GitHub's side, and it is exact. Measured on torvalds/linux:

author email account GitHub resolved
astellman@stellman-greene.com andrewstellman
mic@digikod.net l0kod
dongli.zhang@oracle.com none

Vanity domains, org aliases and noreply forms all resolve. "" is an answer too: the email belongs to no account.

toCommits was throwing that away. firstNonEmpty(Login, Name) folded the login into the git author name, so a commit GitHub could not attribute rendered exactly like one it could.

What changed

  • PRCommit keeps Login, Name and Email apart instead of collapsing them, and PRDetail gains AuthorLogin (the author without the fallback to a display name, so a PR whose author gh reports without a login cannot read as every commit landing elsewhere).
  • frontend/src/lib/pulls/commit-authors.ts builds the reading; the Commits tab renders it.
  • No new gh call, no new scope, no heuristic.

Verified in the running app

Driven through a headless window against cli/cli, all three states:

PR What the tab shows
#1 1 commit is linked to no GitHub account: vilmibm@github.com.
#14355 no line; the row reads @williammartin committed 9/4/2026
#13506 3 commits landed under @Copilot, not @kilasuit.

A false alarm found on the way and fixed: a web-flow merge commit carries no author at all, and was being counted as unattributed. Nobody's identity is wrong there, so it is left alone.

What this still does not cover

All three are written into docs/ceilings.md.

  • Nothing reads before a push. The resolution does not exist until GitHub has the commit, so a branch can be built entirely under the wrong identity and only say so once its pull request is open. The window is after the push and before the merge.
  • The signature is a second identity this compares nothing about: a commit signed by a key the account does not list reads as clean.
  • The comparison is against whoever opened the PR, the only identity the payload already carries. A collaborative branch you are merely reviewing (a teammate's commit, a Copilot-authored PR) therefore reads as commits under another account. The statement is true and the tone is factual rather than an alarm, but it does speak where nothing is wrong. Narrowing it to your pull requests means resolving which account lich runs gh as, and vcs.account only answers that when the project has named one.

Test plan

  • gofmt -l . clean, go vet ./... clean
  • go test ./... green
  • cd frontend && pnpm test green (1764 tests)
  • cd frontend && pnpm build succeeds
  • Three live states confirmed in the running app, per the table above
  • Reviewer: open the Commits tab of one of your own PRs and confirm it stays quiet

Two pre-existing problems found while running the gate

Neither is from this branch and neither is fixed here.

  • pnpm exec biome ci . exits 1 on main — 17 a11y warnings plus one assist info, and zero errors. Confirmed by running biome against a detached worktree of HEAD: same exit. The local gate in CLAUDE.md asks for exit 0, so it cannot pass as written.
  • The frontend suite flakes 1 run in 10 of the full suite under load, in use-history-search.test.tsx on one failure and use-closed-projects.test.tsx on another. Same jsdom starvation shape as the render-budget work: a different file each time, green alone and green on re-run.

…nder

A project's gh account governs what lich asks gh; it has never governed
the push, which still signs with the global user.email. So a pull request
could be read by one account and its commits land under another, with no
error anywhere, and the Version Control pane refused to compare the two
because comparing the strings is a false-positive farm.

The answer was already in the payload. gh pr view --json commits carries
the account GitHub itself resolved each author email to, checked against
the verified addresses of every account, so noreply forms, vanity domains
and org aliases all resolve correctly. toCommits threw it away: folding
the login into the git name made a commit GitHub could not attribute read
exactly like one it could.

Keep the two apart, carry the author email for the unattributed case, and
compare each commit against the account that opened the pull request. The
Commits tab names the account a commit landed under, marks one linked to
no account, and heads the list with a line when they are not all the pull
request author's, while the branch can still be fixed.

Nothing reads before a push, where GitHub has resolved nothing yet:
gh api user/emails would answer there, but it needs the user scope that
gh's own login does not request, and its refusal is a 404 no different
from any other not-found. Both limits are in docs/ceilings.md.
@omartelo
omartelo force-pushed the feat/commit-authorship-on-pr branch from ff973da to b5f4d10 Compare September 10, 2026 18:22
@omartelo
omartelo merged commit 5476a1e into main Sep 10, 2026
7 checks passed
@omartelo
omartelo deleted the feat/commit-authorship-on-pr branch September 10, 2026 18:30
@omartelo omartelo mentioned this pull request Sep 11, 2026
4 of 5 tasks
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.

Nothing compares a project's gh account with the identity its commits land under

1 participant