-
Notifications
You must be signed in to change notification settings - Fork 0
fix(review): count review rounds by commit, not review state #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
380616e
b7d93e8
55c52d2
02b2ac2
791e9a6
a0fc644
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,13 +65,46 @@ jobs: | |
| PR_NUMBER=${{ github.event.pull_request.number }} | ||
| REPO=${{ github.repository }} | ||
|
|
||
| CYCLE=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/reviews" \ | ||
| --paginate | jq -s '[.[][] | select(.user.type == "Bot" and (.state == "CHANGES_REQUESTED" or .state == "APPROVED"))] | length') | ||
| # Count distinct commits already reviewed, never review state: the org ruleset | ||
| # sets dismiss_stale_reviews_on_push, so a push flips a prior APPROVED to | ||
| # DISMISSED and a state filter stops matching it. Inline comments each create | ||
| # their own COMMENTED review sharing the round's commit_id, so unique commit_id | ||
| # == round count, +/-1 when a push lands mid-round and splits it across two SHAs. | ||
| # Coupled to the reviewer's login: if that ever changes the count silently drops | ||
| # to 0 and every round looks like the first, hence the warning below. | ||
| CYCLE_JQ='[.[][] | select(.user.login == "claude[bot]") | .commit_id] | unique | length' | ||
| # Only consulted when CYCLE is 0; see the warning below. Kept in its own variable | ||
| # so tests/review-cycle-test.sh can assert it against the fixtures. | ||
| DRIFT_JQ='any(.[][]; .user.type == "Bot")' | ||
| # Never fail the review over the cycle number; degrade to 1, but say so. gh | ||
| # writes its error body to stdout, so an unguarded pipe into jq aborts the step | ||
| # under `bash -e` and skips the failure-notification step below. | ||
| if ! REVIEWS=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/reviews" --paginate); then | ||
| echo "::warning::Could not read prior reviews; treating this as review cycle 1." | ||
| REVIEWS='' | ||
| fi | ||
| CYCLE=$(printf '%s' "$REVIEWS" | jq -s "$CYCLE_JQ" 2>/dev/null) || CYCLE='' | ||
| if [ -z "$CYCLE" ]; then | ||
| echo "::warning::Could not parse prior reviews; treating this as review cycle 1." | ||
| CYCLE=0 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: the degrade-to-1 fallbacks put the reviewer in a state the prompt explicitly says cannot happen. The annotation covers the human reading the run log afterward; nothing tells the model. Keeping the two signals independent would close it — e.g. emit a sentinel ( This round is a live instance of that combination, from a different cause: per
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Declining for this PR, but keeping the structural point. The supporting claim is wrong: this repo's The real half — |
||
| elif [ "$CYCLE" -eq 0 ] && printf '%s' "$REVIEWS" \ | ||
| | jq -e -s "$DRIFT_JQ" >/dev/null 2>&1; then | ||
| # claude[bot] is the only bot that submits reviews across the org (598 of 598 | ||
| # sampled), so bot reviews that the login filter did not count mean the | ||
| # reviewer's identity moved and the counter has silently pinned at 1. | ||
| echo "::warning::Bot reviews exist but none matched the reviewer login; the review cycle counter is stale." | ||
| fi | ||
| echo "review_cycle=$((CYCLE + 1))" >> $GITHUB_OUTPUT | ||
|
|
||
| THREADS=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/comments" \ | ||
| --paginate | jq -s -r ' | ||
| add | sort_by(.created_at) | | ||
| # Same guard as the counter above: unguarded `gh api | jq` aborts the step, and a | ||
| # failure here *skips* the review step, so the notify step's failure check never | ||
| # fires and the PR gets no review and no explanation. | ||
| if ! COMMENTS=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/comments" --paginate); then | ||
| echo "::warning::Could not read prior review comments; reviewing without them." | ||
| COMMENTS='' | ||
| fi | ||
| THREADS=$(printf '%s' "$COMMENTS" | jq -s -r ' | ||
| (add // []) | sort_by(.created_at) | | ||
| if length == 0 then "No prior review comments." | ||
| else .[] | | ||
| "---", | ||
|
|
@@ -82,7 +115,7 @@ jobs: | |
| "", | ||
| .body | ||
| end | ||
| ') | ||
| ') || THREADS='No prior review comments.' | ||
|
|
||
| DELIMITER="REVIEW_CONTEXT_$(openssl rand -hex 16)" | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,20 @@ | ||||||||||||||||||
| name: Tests | ||||||||||||||||||
|
|
||||||||||||||||||
| on: | ||||||||||||||||||
| pull_request: | ||||||||||||||||||
| push: | ||||||||||||||||||
| branches: [main] | ||||||||||||||||||
|
|
||||||||||||||||||
| permissions: | ||||||||||||||||||
| contents: read | ||||||||||||||||||
|
|
||||||||||||||||||
| jobs: | ||||||||||||||||||
| test: | ||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||
| steps: | ||||||||||||||||||
|
Comment on lines
+12
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. super nit: no
Suggested change
|
||||||||||||||||||
| - uses: actions/checkout@v6.0.2 | ||||||||||||||||||
| with: | ||||||||||||||||||
| fetch-depth: 1 | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Review cycle counter | ||||||||||||||||||
| run: tests/review-cycle-test.sh | ||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super nit: the
+/-1note covers the mid-round push split, but the opposite-sign case in the same family isn't listed: rounds that share a SHA collapse into one. This workflow triggers onready_for_reviewandreopened, neither of which moves the head SHA, and a manual re-run of the job doesn't either — sodraft → review → ready_for_review → reviewcounts as one round and the ladder stays put. Unlike the split case it isn't bounded at 1: N reviews against a single SHA count as 1, not N-1 too many.In practice re-review is push-driven so the exposure is small, which is why this is worth a clause here (and in the limits list at
tests/review-cycle-test.sh:66-70) rather than a fix — it reads as an oversight otherwise, since the trigger list at the top of this file makes both same-SHA events reachable. (not blocking)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Declining, because I think collapsing is the correct semantics rather than a limitation to document.
The counter feeds a de-escalation ladder whose purpose is to detect "the author pushed changes and I am re-checking evolving code." A review against an unchanged head SHA is not another iteration of that loop — the code is byte-identical, so there is nothing new to de-escalate about.
Counting same-SHA events would also be exploitable in the direction that matters.
ready_for_reviewandreopeneddo not move the head SHA, so toggling draft five times would walk the reviewer toCycle 5+: Blocking issues only. Do not leave any nits.without a line of code changing. The split case errs toward reviewing more; this one would err toward silence. I would rather keep the counter tied to distinct reviewed code than to distinct review invocations.