Skip to content

Add review bounty claim saturation checks#841

Open
jakerated-r wants to merge 5 commits into
ramimbo:mainfrom
jakerated-r:codex-b799-797-review-claim-saturation-cycle137
Open

Add review bounty claim saturation checks#841
jakerated-r wants to merge 5 commits into
ramimbo:mainfrom
jakerated-r:codex-b799-797-review-claim-saturation-cycle137

Conversation

@jakerated-r
Copy link
Copy Markdown
Contributor

@jakerated-r jakerated-r commented Jun 3, 2026

Summary

  • Adds active review-bounty claim-thread awareness to scripts/review_bounty_candidates.py.
  • Joins read-only /claim comments from a live bounty issue into the reviewer candidate report.
  • Classifies PRs as already_claimed_current_head, already_claimed_on_bounty_issue, claimed_by_pr_comment, or claimed_stale_head_or_base when the active bounty thread already contains relevant evidence.
  • Keeps fixture input deterministic and adds live --bounty-issue mode using public gh api --paginate --slurp issue-comment reads.

Bounty #799
Source report: #797

Why this matches #797

#797 asks the review candidate helper to stop relying only on PR review objects and to read active review-bounty issue comments so reviewers can avoid duplicate or stale review claims. This PR implements that focused first slice in the existing helper without posting claims, mutating issues, editing labels, or touching payment state.

Verification

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py -q -> 8 passed
  • uv run --extra dev pytest -q -> 751 passed, 1 Starlette/httpx deprecation warning
  • uv run --extra dev ruff format --check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> 2 files already formatted
  • uv run --extra dev ruff check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> All checks passed
  • uv run --extra dev mypy scripts/review_bounty_candidates.py -> Success
  • git diff --check -> clean

Live read-only smoke

Ran:

uv run --extra dev python scripts/review_bounty_candidates.py \
  --repo ramimbo/mergework \
  --bounty-issue 654 \
  --reviewer jakerated-r \
  --format json

Observed current public claim-thread signal joined into the report:

summary {'already_claimed_current_head': 12, 'already_claimed_on_bounty_issue': 1, 'candidate_for_fresh_review': 1, 'needs_info': 16, 'pull_requests': 30}
PR 839 already_claimed_current_head bounty_claim_count=2
PR 837 already_claimed_current_head bounty_claim_count=2
PR 835 already_claimed_current_head bounty_claim_count=5

Safety

Read-only GitHub public reads only. No automatic claim submission, issue editing, labels, acceptance decisions, payments, admin-token APIs, private data, secrets, or wallet material.

Summary by CodeRabbit

  • New Features

    • PR classification considers bounty-claim evidence mined from issue comments; reports show per-PR claim counts and summaries
    • CLI option to load a bounty issue’s comments for live analysis (incompatible with --input); live loading paginates API results
    • Text and Markdown reports append per-PR claim links (up to two) as a claim suffix
  • Bug Fixes

    • Improved validation of external issue-search responses to avoid unexpected data shapes
  • Tests

    • Added tests for claim parsing, SHA-matching variants (case/abbrev), and paginated live comment retrieval

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 28ba6ac6-9c83-4c9a-a26a-275f8f8852c4

📥 Commits

Reviewing files that changed from the base of the PR and between 6811c5c and 53c5393.

📒 Files selected for processing (3)
  • scripts/proposed_work_triage.py
  • scripts/review_bounty_candidates.py
  • tests/test_review_bounty_candidates.py

📝 Walkthrough

Walkthrough

Adds extraction of structured bounty-claim evidence from issue comments, indexes claims by PR, passes claims into PR classification (new claim-driven states and metadata), appends claim links in text/markdown reports, supports live paginated GH comment loading via CLI, and adds unit/integration tests.

Changes

Bounty Claim Evidence and Classification

Layer / File(s) Summary
Claim parsing & normalization
scripts/review_bounty_candidates.py
Adds re and compiled patterns; implements comment-normalizers, _first_match, _claim_evidence_type, _claim_from_comment, extract_bounty_claims, and related helpers to normalize comments and build/deduplicate structured claims.
Claim indexing & summaries
scripts/review_bounty_candidates.py
Adds _claims_by_pr, _claim_summaries, and _claim_matches_head to aggregate claims by PR and match head SHA prefixes.
PR classification with bounty claim state
scripts/review_bounty_candidates.py
Updates _classify_pr signature to accept claims_by_pr; partitions claims by head/base/current/stale/PR-comment evidence; sets new bounty-claim-driven state/reason cases and adds bounty_claim_count and bounty_claims.
Analysis pass and report formatting
scripts/review_bounty_candidates.py
analyze_candidates builds and passes claims_by_pr; format_text_report and format_markdown_report append per-PR claim suffixes (up to two claim links).
Live GH API pagination and CLI option
scripts/review_bounty_candidates.py
Adds _run_gh_api_paginated_array and load_bounty_claim_comments to fetch and normalize paginated issue comments; load_live_candidates(..., bounty_issue=...) returns bounty_claim_comments; CLI adds --bounty-issue and rejects --input.
Unit and integration tests
tests/test_review_bounty_candidates.py
Adds tests for claim-derived PR states (current/stale/PR-comment), SHA matching (uppercase/abbrev), and live paginated comment loading via mocked subprocess.run, asserting claim counts and authors.

Proposed Work Triage

Layer / File(s) Summary
_gh_issue_search response validation
scripts/proposed_work_triage.py
Capture _run_gh output into data, validate it's a list of dicts, accumulate into issues, and raise RuntimeError on unexpected shapes.

Possibly related issues

  • ramimbo/mergework#797: Matches feature work to extract and classify bounty-claim evidence from issue comments and augment PR classification.

Possibly related PRs

  • ramimbo/mergework#743: Prior PR that extended review candidate classification/reporting; this change builds on the same area.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add review bounty claim saturation checks' accurately and concretely describes the main change: adding bounty claim awareness and classification logic to the review candidate script.
Description check ✅ Passed The description is comprehensive and complete. It covers the summary, evidence (with related bounty/issue), test evidence with verification results, and MRWK tracking. All required template sections are present and filled with substantive detail.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Mergework Public Artifact Hygiene ✅ Passed No investment, price, cash-out, fabricated payout claims found. Code is read-only bounty claim parsing. NON_LIVE_CONFUSION_RE is a validation guardrail, not a claim.
Bounty Pr Focus ✅ Passed All stated Bounty #799 changes present: 12 new functions, 3 tests, 4 state classifications, bounty_claims fields added. No unrelated scope creep; read-only API usage verified.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ce2d8b74-1045-4074-bc03-d497de3bbead

📥 Commits

Reviewing files that changed from the base of the PR and between c504500 and f8cad37.

📒 Files selected for processing (2)
  • scripts/review_bounty_candidates.py
  • tests/test_review_bounty_candidates.py

Comment thread scripts/review_bounty_candidates.py
Comment thread tests/test_review_bounty_candidates.py
Comment thread tests/test_review_bounty_candidates.py
Copy link
Copy Markdown
Contributor

@Zejia Zejia left a comment

Choose a reason for hiding this comment

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

I think this needs one correctness fix before merge.

The new claim saturation logic accepts 7-40 character SHAs in HEAD_SHA_RE, but _classify_pr() only treats a claim as current-head when claim["head_sha"] == headRefOid exactly. That means common abbreviated or uppercase current-head SHAs are parsed successfully, then fail the current-head match and get weaker/stale classification.

Direct reproduction on current head f8cad3798db475f94c1a9e5cc0acf01ed965f11e:

  • Claim body with Head SHA: f8cad3798db4 -> state already_claimed_on_bounty_issue, not already_claimed_current_head.
  • Claim body with uppercase full SHA F8CAD3798DB475F94C1A9E5CC0ACF01ED965F11E -> state already_claimed_on_bounty_issue, not already_claimed_current_head.
  • Claim body with lowercase full SHA f8cad3798db475f94c1a9e5cc0acf01ed965f11e -> state already_claimed_current_head.

That is a real saturation problem because the parser advertises support for short SHA evidence, and short SHAs are common in review/claim comments. I would normalize case and compare using prefix semantics when the parsed SHA is shorter than the current full head, then add regression coverage for abbreviated and uppercase current-head claims.

Validation I ran:

  • python -m pytest tests/test_review_bounty_candidates.py -q -> 8 passed
  • python -m ruff check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • python -m ruff format --check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> 2 files already formatted
  • python -m mypy scripts/review_bounty_candidates.py -> success
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree 8a714b117b099657796936d27842d486555f65d9
  • Hosted Quality/readiness/docs/image and CodeRabbit checks are passing

No private data, secrets, wallet material, issue mutation, label mutation, payment action, treasury mutation, exchange, bridge, cash-out, or price behavior was used.

@jakerated-r
Copy link
Copy Markdown
Contributor Author

Thanks, that was a real correctness issue. Fixed in c416855f8356b0c1f96f2c55fd3e9503c3eb8899.

What changed:

  • Added _claim_matches_head() so parsed claim SHAs are compared case-insensitively against the PR head.
  • Treats abbreviated parsed claim SHAs as current-head evidence when the full headRefOid starts with that parsed prefix.
  • Added regression coverage proving both uppercase full SHAs and abbreviated current-head SHAs classify as already_claimed_current_head.
  • Tightened the paginated gh api --paginate --slurp test to assert the issues/654/comments endpoint and flatten two pages of claim comments.

Validation on the updated branch:

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py -q -> 9 passed.
  • Direct reproduction now returns already_claimed_current_head for short, uppercase, and lowercase current-head claim SHA bodies.
  • uv run --extra dev ruff format --check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed.
  • uv run --extra dev ruff check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed.
  • uv run --extra dev mypy scripts/review_bounty_candidates.py -> success.
  • uv run --extra dev pytest -q -> 752 passed, 1 existing Starlette/httpx warning.
  • git diff --check origin/main...HEAD -> clean.
  • git merge-tree --write-tree origin/main HEAD -> clean tree 469b72ad6e8c679489611ed81d689d4c2f52b006.

Hosted Quality and CodeRabbit are rerunning on the new head now.

@jakerated-r
Copy link
Copy Markdown
Contributor Author

Follow-up on the reviewer-fix head c416855f8356b0c1f96f2c55fd3e9503c3eb8899:

  • Hosted Quality/readiness/docs/image check is now SUCCESS.
  • CodeRabbit is now SUCCESS.
  • GitHub mergeStateStatus is back to CLEAN.
  • Local validation from the fix comment still stands: focused review-candidate tests 9 passed, full suite 752 passed, Ruff format/check, mypy script, diff check, direct short/uppercase/lowercase SHA reproduction, and clean merge-tree 469b72ad6e8c679489611ed81d689d4c2f52b006.

This should be ready for re-review on the SHA-normalization blocker.

Copy link
Copy Markdown
Contributor

@prettyboyvic prettyboyvic left a comment

Choose a reason for hiding this comment

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

Thanks for fixing the abbreviated/uppercase SHA comparison from the previous head. I found one remaining current-head blocker in the live claim-thread path.

When a PR has a stale claim on the active bounty issue and then receives a new head, the --bounty-issue report still suppresses it as already claimed instead of surfacing that the claim is stale and the new head needs review. That is the core case this helper is meant to make visible for review-bounty work.

Reproduction on current head c416855f8356b0c1f96f2c55fd3e9503c3eb8899 against current origin/main c504500cbe0b8c0acae692b27521ed778339d16e:

python scripts/review_bounty_candidates.py \
  --repo ramimbo/mergework \
  --bounty-issue 654 \
  --reviewer prettyboyvic \
  --format json

The row for this PR is:

  • headRefOid: c416855f8356b0c1f96f2c55fd3e9503c3eb8899
  • prior claim head_sha: f8cad3798db475f94c1a9e5cc0acf01ed965f11e
  • current_head_human_reviews: 0
  • latest_human_review.commit: f8cad3798db475f94c1a9e5cc0acf01ed965f11e
  • mergeStateStatus: clean
  • actual state emitted: already_claimed_on_bounty_issue
  • reason emitted: active bounty issue already references this PR

That means the helper would tell reviewers not to look at the current fixed head of #841 even though the only human review/claim evidence is for the old head. I think a clean PR with bounty claims whose parsed head_sha does not match the current headRefOid should remain eligible for follow-up review or be classified explicitly as stale-head/base evidence, rather than being treated as saturated just because the bounty issue mentions the PR.

The same live row also shows bounty_claim_count=2 for one Zejia claim comment: one pr_review claim from the PR review URL and one pr_reference claim from the same issue comment's "PR #841" text. That duplication is less severe than the stale-head suppression, but it makes the count and rendered claim links misleading.

Validation I ran:

  • python -m pytest tests/test_review_bounty_candidates.py -q -> 9 passed in 0.27s
  • python scripts/review_bounty_candidates.py --repo ramimbo/mergework --bounty-issue 654 --reviewer prettyboyvic --format markdown -> live report reproduced the stale-claim suppression for #841
  • python -m ruff check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • python -m ruff format --check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> 2 files already formatted
  • python -m mypy scripts/review_bounty_candidates.py -> passed
  • python scripts/docs_smoke.py -> docs smoke ok
  • python -m py_compile scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree 469b72ad6e8c679489611ed81d689d4c2f52b006

GitHub state checked before review: mergeStateStatus=CLEAN; hosted Quality, readiness, docs, and image checks successful; CodeRabbit successful.

No private data, wallet material, payout execution, treasury mutation, exchange, bridge, cash-out, or price behavior was used.

@jakerated-r
Copy link
Copy Markdown
Contributor Author

Thanks, this was a valid blocker. Addressed in 1d452b7cd5c0df7e4c811700b5e61db5816f25c9.

What changed:

  • Stale-head or base-only bounty issue evidence no longer suppresses a clean newer PR head as already_claimed_on_bounty_issue.
  • A clean PR whose only claim evidence points to an older head remains reviewable as candidate_for_fresh_review, with reason active bounty issue only has stale-head/base claim evidence.
  • A single bounty issue comment now counts only once per PR, so a review URL plus bare PR #841 text in the same claim comment no longer creates duplicate claim rows.

Regression proof:

  • Exact stale-head reproduction fixture now emits candidate_for_fresh_review, reason active bounty issue only has stale-head/base claim evidence, and bounty_claim_count=1.
  • Live post-push check for Add review bounty claim saturation checks #841 shows head 1d452b7cd5c0df7e4c811700b5e61db5816f25c9, prior Zejia claim on f8cad3798db475f94c1a9e5cc0acf01ed965f11e, prior prettyboyvic claim on c416855f8356b0c1f96f2c55fd3e9503c3eb8899, and current_head_human_reviews=0.

Validation run locally:

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py -q -> 9 passed
  • uv run --extra dev pytest -q -> 752 passed, 1 warning
  • uv run --extra dev ruff check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • uv run --extra dev ruff format --check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> 2 files already formatted
  • uv run --extra dev mypy scripts/review_bounty_candidates.py -> success
  • python3 scripts/docs_smoke.py -> docs smoke ok
  • python3 -m py_compile scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • git diff --check -> clean
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree 469b72ad6e8c679489611ed81d689d4c2f52b006

Hosted status checked after push:

  • Quality, readiness, docs, and image checks -> SUCCESS
  • CodeRabbit -> still PENDING during the polling window

No private data, secrets, wallet material, payout execution, treasury mutation, exchange, bridge, cash-out, or price behavior was used.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/review_bounty_candidates.py (1)

188-205: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid reusing one body-level SHA across every PR in a multi-PR claim comment.

Line 203 and Line 204 parse the first head_sha/base_sha from the entire comment, but extract_bounty_claims() can emit multiple claims from that same body. A single /claim comment that lists PR #11 and `PR `#12 with different SHAs will currently stamp both records with the first SHA it finds, which can misclassify the later PR as already_claimed_current_head or claimed_stale_head_or_base.

If multi-PR comments are allowed, the SHA/base parsing needs to be scoped per PR reference. If they are not, the safer fallback here is to only attach head_sha/base_sha when the comment resolves to exactly one PR; otherwise leave them unset so the claim stays unqualified instead of being attributed to the wrong PR.

Also applies to: 208-246

tests/test_review_bounty_candidates.py (1)

194-318: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a base-only claim case; that new branch is still unproven.

The production change now has dedicated base_claims handling, but this test only covers stale-head-only and stale-head-plus-base inputs. If base_claims stopped populating entirely, these assertions would still pass because PR #12 already trips the stale-head path. Please add a fixture with base_sha and no head_sha and assert the clean/dirty outcomes for that branch.

As per coding guidelines, "Add or update tests for changed behavior" and, for tests/**/*.py, include "negative, replay, boundary, or regression cases where relevant."


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 207bb64b-1ebd-4325-81b5-40005a99183a

📥 Commits

Reviewing files that changed from the base of the PR and between c416855 and 1d452b7.

📒 Files selected for processing (2)
  • scripts/review_bounty_candidates.py
  • tests/test_review_bounty_candidates.py

Copy link
Copy Markdown
Contributor

@caozhengming caozhengming left a comment

Choose a reason for hiding this comment

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

Requesting changes on current head 1d452b7cd5c0df7e4c811700b5e61db5816f25c9.

I rechecked the latest fix for stale bounty-claim handling. The previous stale-head suppression issue is addressed, and the branch is otherwise healthy, but there is still one correctness blocker in the new claim extraction path.

extract_bounty_claims() can emit more than one claim from a single bounty issue comment: one per PR URL or bare PR #... reference. Each emitted claim then calls _claim_from_comment(), which reads head_sha and base_sha from the entire comment body using the first regex match. That means a multi-PR /claim comment with one Head SHA: line, or multiple PR sections with different SHAs, will stamp every extracted PR claim with the first body-level SHA. Downstream classification can then mark the wrong PR as already_claimed_current_head or claimed_stale_head_or_base.

This matters for the exact saturation workflow this helper is trying to protect: the active review-bounty issue comments are not guaranteed to be one PR per comment, and a wrong SHA attribution can suppress a clean current head from review or incorrectly classify it as already saturated. A safer behavior would be to attach head_sha/base_sha only when the comment resolves to exactly one PR, or to parse SHA evidence from a PR-scoped fragment. Otherwise, leave those fields unset so the claim is treated as unqualified rather than attributed to the wrong PR.

Validation I ran on this head:

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py -q -> 9 passed
  • ruff check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • ruff format --check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> 2 files already formatted
  • mypy scripts/review_bounty_candidates.py -> success
  • python scripts/docs_smoke.py -> docs smoke ok
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree 7044f1225cdb6f07f40ac45544b6af180757ed77
  • GitHub reports mergeStateStatus=CLEAN; hosted Quality/readiness/docs/image and CodeRabbit are success on this head

No private data, wallet material, payout execution, treasury mutation, exchange, bridge, cash-out, or price behavior was used.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/review_bounty_candidates.py (2)

225-242: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the strongest evidence type per PR before deduping.

seen is keyed only by (pull_request, comment_key), so the first /pull/<n> URL in a comment wins even if a later link for the same PR is #issuecomment-... or #pullrequestreview-.... That silently downgrades evidence_type and can flip classification from claimed_by_pr_comment to already_claimed_on_bounty_issue.

Proposed fix
 def extract_bounty_claims(comments: list[dict[str, Any]]) -> list[dict[str, Any]]:
     claims: list[dict[str, Any]] = []
     seen: set[tuple[int, str | None]] = set()
+    evidence_rank = {"pr_reference": 0, "pr_review": 1, "pr_comment": 2}
     for comment_index, comment in enumerate(comments):
         body = str(comment.get("body") or "")
         if "/claim" not in body.lower():
             continue
         comment_url = _comment_url(comment)
         comment_key = comment_url or f"comment-{comment_index}"
@@
-        for match in PR_URL_RE.finditer(body):
+        best_url_match_by_pr: dict[int, tuple[str, str]] = {}
+        for match in PR_URL_RE.finditer(body):
             pull_request = int(match.group("number"))
             evidence_url = match.group(0)
             evidence_type = _claim_evidence_type(match.group("fragment"), body)
+            current = best_url_match_by_pr.get(pull_request)
+            if current is None or evidence_rank[evidence_type] > evidence_rank[current[1]]:
+                best_url_match_by_pr[pull_request] = (evidence_url, evidence_type)
+
+        for pull_request, (evidence_url, evidence_type) in best_url_match_by_pr.items():
             url_key = (pull_request, comment_key)
             if url_key in seen:
                 continue
             seen.add(url_key)
             claims.append(

476-484: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Filter missing URLs before truncating markdown claim links.

This slices bounty_claims before dropping entries without url. If the first two claim summaries are URL-less, the markdown report omits later valid claim links for the same PR, while the text report still shows them.

Proposed fix
-            claim_links = [
-                f"[claim]({claim['url']})"
-                for claim in bounty_claims[:2]
-                if isinstance(claim, dict) and claim.get("url")
-            ]
+            claim_links = [
+                f"[claim]({claim['url']})"
+                for claim in bounty_claims
+                if isinstance(claim, dict) and claim.get("url")
+            ][:2]

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 17374b33-d8ca-4eab-a7b8-942936870480

📥 Commits

Reviewing files that changed from the base of the PR and between 1d452b7 and 6811c5c.

📒 Files selected for processing (2)
  • scripts/review_bounty_candidates.py
  • tests/test_review_bounty_candidates.py

@jakerated-r
Copy link
Copy Markdown
Contributor Author

Thanks, this is a valid correctness issue. Addressed in 6811c5cf3b71a748492fed0dd9e49f4cc2deda9c.

What changed:

  • extract_bounty_claims() now scopes body-level Head SHA / Base SHA evidence only when a bounty issue comment resolves to exactly one PR.
  • If a /claim comment references multiple PRs, the emitted claims keep head_sha=None and base_sha=None instead of stamping every PR with the first SHA found in the body.
  • This preserves the conservative fallback you suggested: multi-PR comments stay unqualified rather than incorrectly marking a different PR as current-head or stale-head/base evidence.
  • Added regression coverage for base-only claims and multi-PR claim comments with body-level SHA evidence.

Direct reproduction after the patch:

  • Multi-PR claim body with PR #18, PR #999, and Head SHA: <current head> now emits the #18 claim with head_sha=None and base_sha=None.
  • The same regression keeps one-PR comments unchanged, so current-head, stale-head, and base-only evidence still classify through the intended branches.

Validation run locally:

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py -q -> 9 passed
  • uv run --extra dev pytest -q -> 752 passed, 1 warning
  • uv run --extra dev ruff check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • uv run --extra dev ruff format --check scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> 2 files already formatted
  • uv run --extra dev mypy scripts/review_bounty_candidates.py -> success
  • python3 scripts/docs_smoke.py -> docs smoke ok
  • python3 -m py_compile scripts/review_bounty_candidates.py tests/test_review_bounty_candidates.py -> passed
  • git diff --check -> clean
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean

Hosted status checked after push:

  • PR head: 6811c5cf3b71a748492fed0dd9e49f4cc2deda9c
  • Quality, readiness, docs, and image checks -> SUCCESS
  • CodeRabbit -> still PENDING through the polling window

No private data, secrets, wallet material, payout execution, treasury mutation, exchange, bridge, cash-out, or price behavior was used.

@jakerated-r
Copy link
Copy Markdown
Contributor Author

Update after the hosted queue finished: current head 6811c5cf3b71a748492fed0dd9e49f4cc2deda9c now has mergeStateStatus=CLEAN, Quality, readiness, docs, and image checks=SUCCESS, and CodeRabbit=SUCCESS.

@ramimbo ramimbo added the mrwk:needs-info More information needed label Jun 3, 2026
@ramimbo
Copy link
Copy Markdown
Owner

ramimbo commented Jun 3, 2026

Maintainer queue status: marked needs-info. A newer head landed after the prior human changes-requested review, so this needs current-head human review confirming the claim-thread SHA attribution issues are resolved before merge/payment.

…-claim-saturation-cycle137

# Conflicts:
#	scripts/review_bounty_candidates.py
@jakerated-r
Copy link
Copy Markdown
Contributor Author

Mergeability update for current head 53c539347f2397ba1be7a8ceeaab25c7e25b07b5:

  • Merged current origin/main into this PR branch to clear the dirty/conflicted state after upstream PRs landed.
  • Resolved the scripts/review_bounty_candidates.py overlap by preserving both the existing bounty-claim SHA attribution fixes and upstream source-argument validation.
  • Added a small type-safety guard in scripts/proposed_work_triage.py after the upstream merge exposed a mypy Any return.

Local verification:

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py tests/test_proposed_work_triage.py -q -> 34 passed
  • uv run --extra dev pytest -q -> 793 passed, 1 warning
  • uv run --extra dev mypy app scripts -> success
  • uv run --extra dev ruff check . -> success
  • python3 scripts/docs_smoke.py -> docs smoke ok
  • git diff --check -> clean

Hosted status at the time of this comment: Quality/readiness/docs/image is SUCCESS; GitHub reports the branch as MERGEABLE; CodeRabbit is still pending.

@jakerated-r
Copy link
Copy Markdown
Contributor Author

Follow-up on current head 53c539347f2397ba1be7a8ceeaab25c7e25b07b5 after the merge-sync push:

  • Hosted Quality/readiness/docs/image is now SUCCESS.
  • CodeRabbit is now SUCCESS.
  • GitHub reports the branch as MERGEABLE with mergeStateStatus=CLEAN.

The local verification from the merge-sync remains:

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py tests/test_proposed_work_triage.py -q -> 34 passed
  • uv run --extra dev pytest -q -> 793 passed, 1 warning
  • uv run --extra dev mypy app scripts -> success
  • uv run --extra dev ruff check . -> success
  • python3 scripts/docs_smoke.py -> docs smoke ok
  • git diff --check -> clean

Ready for current-head human review on the SHA-attribution fixes.

Copy link
Copy Markdown

@heickerv1001-dev heickerv1001-dev left a comment

Choose a reason for hiding this comment

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

Current-head review for 53c539347f2397ba1be7a8ceeaab25c7e25b07b5.

I reviewed the latest merge-sync head after the earlier stale-claim and multi-PR SHA-attribution blockers. I do not see a remaining blocker in the claim-thread classification path.

Evidence checked:

  • GitHub PR metadata now reports mergeable=true, mergeable_state=clean on head 53c539347f2397ba1be7a8ceeaab25c7e25b07b5.
  • Hosted Quality, readiness, docs, and image checks check-run completed with conclusion=success for the same head.
  • Commit status API reports CodeRabbit=success for the same head.
  • Inspected the changed surfaces: scripts/review_bounty_candidates.py, scripts/proposed_work_triage.py, and tests/test_review_bounty_candidates.py.
  • Verified the script still loads with the new CLI option: python scripts/review_bounty_candidates.py --help shows --bounty-issue and exits 0.
  • py_compile passes for scripts/review_bounty_candidates.py, scripts/proposed_work_triage.py, and tests/test_review_bounty_candidates.py.
  • Ran direct function-level reproductions for the previously reported edge cases:
    • abbreviated current-head claim SHA is classified as already_claimed_current_head;
    • uppercase current-head claim SHA is classified as already_claimed_current_head;
    • clean PR with stale-head claim remains candidate_for_fresh_review;
    • clean PR with base-only claim remains candidate_for_fresh_review;
    • dirty PR with base-only/stale evidence is still held as claimed_stale_head_or_base;
    • multi-PR claim comments no longer stamp the body-level Head SHA / Base SHA onto every extracted PR claim; the multi-PR claim remains unqualified with head_sha=None and base_sha=None.

Local command evidence from the direct reproduction:

{
  "abbrev_current_head": "already_claimed_current_head",
  "uppercase_current_head": "already_claimed_current_head",
  "clean_stale_head_followup": "candidate_for_fresh_review",
  "clean_base_only_followup": "candidate_for_fresh_review",
  "multi_pr_sha_unqualified": {
    "state": "already_claimed_on_bounty_issue",
    "head_sha": null,
    "base_sha": null
  },
  "dirty_base_only_blocked": "claimed_stale_head_or_base"
}

I could not run the repository pytest suite in this local sandbox because this runtime does not have pytest installed, so I did not rely on that. The focused direct reproductions above cover the current-head maintainer ask: confirming the previously reported SHA attribution issues are resolved on the latest head.

No private data, secrets, wallet material, payout execution, treasury mutation, exchange, bridge, cash-out, or price behavior was used.

Copy link
Copy Markdown

@xiefuzheng713-alt xiefuzheng713-alt left a comment

Choose a reason for hiding this comment

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

Reviewed current head 53c539347f2397ba1be7a8ceeaab25c7e25b07b5 as a non-author current-head review.

I did not find a remaining code blocker in the claim-thread saturation logic on this head. The earlier SHA-prefix/case, stale-head suppression, base-only, and multi-PR body-level SHA attribution issues are covered by the current test suite and by the live read-only smoke path. Caveat: the PR still has the mrwk:needs-info label, so this review is only a current-head technical review; maintainers still need to decide whether that label is satisfied.

Evidence checked:

  • inspected scripts/review_bounty_candidates.py, scripts/proposed_work_triage.py, and tests/test_review_bounty_candidates.py;
  • confirmed the CLI exposes --bounty-issue only for live --repo mode and still supports deterministic fixture mode;
  • confirmed tests cover abbreviated/uppercase current-head claim SHAs, stale-head claims on clean PRs, base-only claim handling, multi-PR claim comments that must not inherit body-level SHAs, and markdown claim-link rendering;
  • live read-only smoke against bounty issue #838 succeeded: review_bounty_candidates.py --repo ramimbo/mergework --bounty-issue 838 --reviewer xiefuzheng713-alt --format json returned 31 PR rows and classified PR #841 as needs_info because of the existing label, while keeping my already-reviewed PRs out of fresh-review states;
  • no GitHub mutation, issue edit, label edit, bounty creation, payout, proof, wallet, treasury, or ledger path is invoked by the script.

Validation I ran:

  • uv run --extra dev pytest tests/test_review_bounty_candidates.py tests/test_proposed_work_triage.py -q -> 34 passed
  • uv run --extra dev pytest -q -> 793 passed, 1 warning
  • uv run --extra dev ruff check scripts/review_bounty_candidates.py scripts/proposed_work_triage.py tests/test_review_bounty_candidates.py tests/test_proposed_work_triage.py -> passed
  • uv run --extra dev ruff format --check scripts/review_bounty_candidates.py scripts/proposed_work_triage.py tests/test_review_bounty_candidates.py tests/test_proposed_work_triage.py -> 4 files already formatted
  • uv run --extra dev mypy scripts/review_bounty_candidates.py scripts/proposed_work_triage.py -> success
  • uv run --extra dev python scripts/docs_smoke.py -> docs smoke ok
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree 219e2d15ebbaee640179da345760ae761c47c6e2

GitHub state checked: mergeStateStatus=CLEAN; hosted Quality/readiness/docs/image and CodeRabbit checks are successful on this head. No private data, secrets, wallet material, payout execution, treasury mutation, ledger mutation, exchange, bridge, cash-out, MRWK price behavior, or issue mutation was used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mrwk:needs-info More information needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants