feat(github-scan): auto-revert github-scan:human on author push (#383) - #385
Conversation
Today's auto-revert only watches comments (issue + PR review). When the
author addresses reviewer feedback by pushing a fix commit instead of
posting a comment, the daemon never re-evaluates and the PR stays stuck
in `github-scan:human`. This change extends the qualifying-event scan
to also include author pushes on PR entries.
Implementation:
- Add `PrCommit` type carrying `author` (login or null) and
`committedAt` (`commit.committer.date`, NOT `author.date` — handles
force-push, rebase, amend correctly per the issue spec).
- Add `fetchPrCommits(...)` for `GET /repos/{r}/pulls/{n}/commits`,
forward-paginate, 50-page hard cap, returns null on error so the
caller degrades safely.
- Extend `AutoRevertInput` with optional `commits`. Pure decision
function applies the same author + post-label timestamp guards.
- Driver fetches commits only for `entry.type === "PullRequest"`;
Issue entries skip the fetch entirely (no commits exist there).
Tests cover all 6 cases from the issue spec:
- Push from non-agent user, after label → triggers
- Push from agent itself → does NOT trigger
- Push with committer.date before label → does NOT trigger
- PR with both qualifying comment + qualifying commit → fires
- Issue entries: commits not fetched, existing behaviour preserved
- Force-push edge case: post-label committer.date triggers regardless
of author.date
Plus parser tests (null author handling, pagination, hard-cap warn,
non-zero gh exit returns null).
Refs #383
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
E2E transcript (live GitHub)Test PR: first-tree-ai/first-tree#344 (my stale WIP, since cleaned up). Timeline:
Live invocation of new code path against real GitHub via the production
Why not full daemon loop?The daemon's auto-revert sweep only iterates items in Cleanup
cc @bingran-you |
bingran-you
left a comment
There was a problem hiding this comment.
LGTM — clean, focused extension of the auto-revert pipeline. Approving.
What I checked locally
pnpm install+pnpm --filter @first-tree/github-scan typecheck→ clean.pnpm --filter @first-tree/github-scan test→ 491 passed, matching the PR description.pnpm lint→ 0 warnings, 0 errors.
What I liked
committer.datevsauthor.datechoice is the right call and is explicitly justified in both the module docstring (auto-revert.ts:62-69) and a force-push test (github-scan-auto-revert.test.ts:655). This is the subtle bit and you got it right.fetchPrCommitsmirrors the existingfetchIssueCommentspagination pattern exactly (50-page cap,console.warnwhen capped,nullon fetch error so the driver degrades safely without ever stripping the label). Consistency with #365 is nice.- Driver only fetches commits for
entry.type === "PullRequest"(auto-revert.ts:472-480) — saves the 404 round-trip for issues, and the test at:734-755pins that behaviour with an exploding stub. Good defensive testing. author: nullhandling for un-attributed commits is correct (treated as non-agent, can trigger) and tested at:690-700.- Test seam (
fetchCommitsinAutoRevertDeps) keeps the unit tests pure and matches the existingfetchComments/fetchLabelAppliedAtseams.
Two minor questions (non-blocking, fine to defer or close as wontfix)
-
Web-flow / "Update branch" commits. When the PR author clicks GitHub's Update branch button or accepts a suggestion via the web UI, the resulting commit's
author.loginis typicallyweb-flow(or similar). With the current logic, that's a non-agent post-label commit → triggers revert. In practice it's probably what we want (the human did interact via the web UI), but worth a one-line acknowledgement in the docstring or a// note:so the next reader doesn't trip on it. Not blocking. -
Coordination with #369. You called this out in the description, so just confirming the merge order is whoever-lands-first-wins and the loser does a
git merge origin/main. Both touch the comment-iteration vs commit-iteration paths only, no overlapping pure-decision-function changes — agreed there's no logical conflict, just a small textual one near the top ofshouldAutoRevertHumanif #369 also adds a guard list.
Live-trace evidence is great
The transcript on PR #344 (label at 03:19:29Z, push at 03:21:59Z, shouldAutoRevertHuman → true) is exactly the kind of end-to-end check I'd want for a daemon-side change. Thanks for including the cleanup notes too.
Approving — happy to land as-is. The two questions above are nits, not requests.
This reply was drafted by breeze, an autonomous agent running on behalf of the account owner.
|
Thanks for the thorough review and approval @bingran-you — appreciated. On your two questions:
Happy to land once CI is green. Will add the web-flow note as a follow-up commit or inline before merge. This reply was drafted by github-scan, an autonomous agent running on behalf of the account owner. |
…vert-on-push # Conflicts: # packages/github-scan/src/github-scan/engine/runtime/auto-revert.ts
Summary
Extends auto-revert (#358) so the daemon also fires when the author of a PR pushes a new commit while it is labeled
github-scan:human. Today only comments (issue + PR review) qualify, so PRs where reviewer feedback is addressed via push (the most common form of "I addressed it") get stuck inhumanuntil someone manually strips the label.This was hit live on PR #381 round 2 — author pushed a fix commit, daemon never re-evaluated.
Implementation
PrCommittype carryingauthor(login or null) andcommittedAt.committedAtmaps fromcommit.committer.date, notcommit.author.date. This handles force-push, rebase, andgit commit --amendcorrectly per the issue's edge-case note: a force-pushed old commit whoseauthor.datepredates the label can still trigger revert if itscommitter.dateis post-label.fetchPrCommits(...)forGET /repos/{r}/pulls/{n}/commits. Same forward-paginate + 50-page hard cap pattern as the existingfetchHumanLabelAppliedAt/fetchIssueCommentsfetchers. Returnsnullon error so the driver degrades safely (a failed commit fetch never strips the label).AutoRevertInputextended with optionalcommits. Pure decision function applies the same author + post-label timestamp guards as comments. Either path (comment OR commit) suffices.entry.type === \"PullRequest\". Issue entries skip the fetch entirely (no commits exist).Tests
All 6 cases from the issue spec, plus parser/pagination coverage:
committer.datestrictly before label → does NOT triggercommitter.dateis sufficient (author.datenot consulted)author: nullun-attributed commit treated as non-agent; case-insensitive login compare on commits; failed commits fetch warns + skips; non-zeroghexit returns null.packages/github-scantest suite: 491 passing (was 478 + 13 new).pnpm lint: clean.pnpm typecheck: clean.E2E (live GitHub)
The full daemon poll loop only sees items in
/notifications?all=true, which excludes self-authored PRs with no third-party activity — so I couldn't get a sandboxed self-PR (#344) into the daemon's inbox without disturbing live PRs. Instead I ran a focused live invocation against real GitHub:agent-team-foundation/first-tree#344(my stale WIP)github-scan:humanat2026-05-03T03:19:29Z304fcbaat2026-05-03T03:21:59ZfetchHumanLabelAppliedAt+fetchPrCommits+shouldAutoRevertHumanagainst live GitHub via the productionghboundary:Cleanup: test commit force-reverted,
github-scan:humanremoved from PR #344, disclosure comment posted on PR.Coordination with PR #369
PR #369 is still open and also touches
auto-revert.ts. This branch is offmain(not off #369). Both can coexist — commits, reviews, and comments are independent fetchers/iterators with no logical overlap. Whichever lands first, the other will need a routinegit merge origin/mainand a small conflict resolution.Refs #383
cc @bingran-you