Skip to content

Unify live GitHub collection safety-cap policy across report scripts#1165

Open
yanyishuai wants to merge 1 commit into
ramimbo:mainfrom
yanyishuai:bounty-1141-gh-collection-caps
Open

Unify live GitHub collection safety-cap policy across report scripts#1165
yanyishuai wants to merge 1 commit into
ramimbo:mainfrom
yanyishuai:bounty-1141-gh-collection-caps

Conversation

@yanyishuai

@yanyishuai yanyishuai commented Jun 28, 2026

Copy link
Copy Markdown

Summary

Implements proposed work for #1141.

  • Add scripts/gh_collection_caps.py documenting the shared live-collection cap policy (200 PRs / 200 issues).
  • Normalize --limit usage and saturation handling across pr_queue_health.py,
    eview_bounty_candidates.py, check_live_bounty_closing_refs.py, and submission_quality_gate.py.
  • Live reports fail fast on saturation; submission preflight keeps warn-only behavior with aligned cap values/messages.
  • Add ests/test_gh_collection_caps.py and update queue-health regression expectations.

Test plan

  • Module imports cleanly
  • pytest tests/test_gh_collection_caps.py tests/test_pr_queue_health.py tests/test_submission_quality_gate.py

Closes #1141

Summary by CodeRabbit

  • New Features

    • Added shared safeguards for live GitHub data collection, with consistent size limits and clearer saturation warnings.
    • Improved live PR, issue, and bounty checks to handle large result sets more predictably.
  • Bug Fixes

    • Reduced the risk of incomplete or misleading results when GitHub lists reach collection limits.
    • Kept report output, CLI behavior, and exit codes unchanged.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yanyishuai, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: edd02614-3e6d-437a-947f-df248fe4363a

📥 Commits

Reviewing files that changed from the base of the PR and between 2bf1f78 and 8a834b9.

📒 Files selected for processing (5)
  • scripts/check_live_bounty_closing_refs.py
  • scripts/pr_queue_health.py
  • scripts/review_bounty_candidates.py
  • scripts/submission_quality_gate.py
  • tests/test_pr_queue_health.py
📝 Walkthrough BelowCap: len(items) < cap

[*] --> AtOrAboveCap: len(items) >= cap
BelowCap --> ReturnNone
AtOrAboveCap --> FailMode: mode == FAIL_ON_SATURATION
AtOrAboveCap --> WarnMode: mode == WARN_ON_SATURATION
FailMode --> RaiseRuntimeError: saturation_message(warn_only=False)
WarnMode --> ReturnMessage: saturation_message(warn_only=True)

</diagram>
</layer>
<layer id="pr_queue_adoption" title="pr_queue_health adoption and test updates" depends_on="caps_module">
<summary>Replaces local GH timeout/cap constants and manual `len >= cap` checks in `load_live_queue` with imports of shared utilities; adds `_run_gh_json` alias for test compatibility; updates cap-wording assertions from 201 to 200.</summary>
<ranges>
range_1f5ba6feee52
range_d0d7954284a5
range_125b12e2cd43
range_6e77cf8ac71d
range_7dccc8c7206e
range_a9d13e44a6e4
range_b124f1a18502
</ranges>
</layer>
<layer id="closing_refs_adoption" title="check_live_bounty_closing_refs adoption" depends_on="caps_module">
<summary>Replaces local urllib/timeout/cap definitions with shared imports; `_load_pull_requests` uses `gh_list_limit` + `check_collection_saturation`; `load_live_data` uses `load_public_bounty_list`; analysis and CLI behavior unchanged.</summary>
<ranges>
range_d285d6c1619e
range_6413fe20ba5b
range_b72fa490a3a6
range_e3f7869a35d6
range_e78a74c94724
range_112cfc9aff6f
range_ddc036c6c2c0
range_d922d953b9e5
</ranges>
</layer>
<layer id="review_candidates_adoption" title="review_bounty_candidates adoption" depends_on="caps_module">
<summary>Replaces local `_run_gh_json`, `GH_TIMEOUT_SECONDS`, `GH_PR_SAFETY_CAP`, and `DIRTY_MERGE_STATES` definitions with shared imports; `load_live_candidates` uses `gh_list_limit` and `check_collection_saturation`; classification and CLI unchanged.</summary>
<ranges>
range_7a1b73711240
range_f02448a08210
range_62defe052801
range_9c2342855576
</ranges>
</layer>
<layer id="quality_gate_adoption" title="submission_quality_gate adoption" depends_on="caps_module">
<summary>Replaces local `GH_PR_SAFETY_CAP`/`GH_ISSUE_SAFETY_CAP` literals with imported defaults; `_load_live_context` uses `gh_list_limit` and `check_collection_saturation` with `WARN_ON_SATURATION` mode and a custom bounty-discovery detail string.</summary>
<ranges>
range_ef227972365b
range_8661fb28848d
</ranges>
</layer>
</cohort>
<unassigned_ranges>
</unassigned_ranges>
review_stack_artifact_end-->

## Walkthrough

Adds `scripts/gh_collection_caps.py` with shared constants (`DEFAULT_GH_PR_LIST_CAP`, `DEFAULT_GH_ISSUE_LIST_CAP`), saturation mode strings, and three helpers (`gh_list_limit`, `saturation_message`, `check_collection_saturation`). Four existing report scripts (`pr_queue_health`, `check_live_bounty_closing_refs`, `review_bounty_candidates`, `submission_quality_gate`) replace their per-script cap constants and manual saturation checks with imports from this new module.

## Changes

**Safety-cap policy extraction and adoption**

| Layer / File(s) | Summary |
|---|---|
| **`gh_collection_caps` module and tests** <br> `scripts/gh_collection_caps.py`, `tests/test_gh_collection_caps.py` | New module defines `DEFAULT_GH_PR_LIST_CAP`/`DEFAULT_GH_ISSUE_LIST_CAP` (both 200), `FAIL_ON_SATURATION`/`WARN_ON_SATURATION` mode strings, and three helpers: `gh_list_limit` (returns stringified cap for `--limit`), `saturation_message` (formats context-aware error/warning text), and `check_collection_saturation` (raises `RuntimeError` or returns message at/above cap). Three tests cover below-cap pass, at-cap fail, and warn-mode return. |
| **`pr_queue_health` adoption + test updates** <br> `scripts/pr_queue_health.py`, `tests/test_pr_queue_health.py` | Removes local timeout/cap constants; `load_live_queue` uses `run_gh_json_list`/`run_gh_json_object`, `gh_list_limit`, and `check_collection_saturation`; adds `_run_gh_json` alias for test compatibility. Cap-wording assertions updated from "201" to "200". |
| **`check_live_bounty_closing_refs` adoption** <br> `scripts/check_live_bounty_closing_refs.py` | Removes local `urllib`/timeout/cap code; `_load_pull_requests` uses `gh_list_limit` + `check_collection_saturation`; `load_live_data` delegates to `load_public_bounty_list`. Analysis, formatting, and CLI unchanged. |
| **`review_bounty_candidates` adoption** <br> `scripts/review_bounty_candidates.py` | Removes local `_run_gh_json`, `GH_TIMEOUT_SECONDS`, `GH_PR_SAFETY_CAP`, and `DIRTY_MERGE_STATES` definitions; replaces with shared imports. `load_live_candidates` uses `gh_list_limit`/`check_collection_saturation`. Note: `DIRTY_MERGE_STATES` is removed from this file but still referenced by `_classify_pr`—it must now come from the shared import. |
| **`submission_quality_gate` adoption** <br> `scripts/submission_quality_gate.py` | Replaces local cap literals (101/201) with `DEFAULT_GH_PR_LIST_CAP`/`DEFAULT_GH_ISSUE_LIST_CAP` (both 200); `_load_live_context` uses `gh_list_limit` and `check_collection_saturation` in `WARN_ON_SATURATION` mode with a custom bounty-discovery detail string. |

## Possibly related issues

- **ramimbo/mergework#978**: Adds shared GitHub list safety-cap handling for live collection—same code-pattern goal as this PR, applied to a different script.

## Possibly related PRs

- [ramimbo/mergework#324](https://github.com/ramimbo/mergework/pull/324): Introduced `pr_queue_health.py`; this PR refactors its cap logic to use the new shared module.
- [ramimbo/mergework#325](https://github.com/ramimbo/mergework/pull/325): Introduced `submission_quality_gate.py`; this PR replaces its hardcoded cap constants with shared imports.
- [ramimbo/mergework#1021](https://github.com/ramimbo/mergework/pull/1021): Initial implementation of `check_live_bounty_closing_refs.py` including the per-script safety-cap code now being replaced.

</details>

<!-- walkthrough_end -->
<!-- pre_merge_checks_walkthrough_start -->

<details>
<summary>🚥 Pre-merge checks | ✅ 4 | ❌ 2</summary>

### ❌ Failed checks (2 warnings)

|         Check name         | Status     | Explanation                                                                                                                                       | Resolution                                                                                                                    |
| :------------------------: | :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------- |
|      Description check     | ⚠️ Warning | The description covers summary and test plan, but it omits required Evidence and MRWK sections and leaves the template checklist mostly unfilled. | Add the missing Evidence bullets, complete the Test Evidence checklist, and include the MRWK related bounty or issue section. |
| Out of Scope Changes check | ⚠️ Warning | The review_bounty_candidates changes include a sys.path tweak and a DIRTY_MERGE_STATES removal, which are unrelated to the cap-policy objective.  | Remove or justify the unrelated import-path change and restore any missing merge-state definition or import before merging.   |

<details>
<summary>✅ Passed checks (4 passed)</summary>

|             Check name            | Status   | Explanation                                                                                                                                                   |
| :-------------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|            Title check            | ✅ Passed | The title is short and accurately names the changed surface: shared GitHub collection safety-cap policy across report scripts.                                |
|        Linked Issues check        | ✅ Passed | The PR aligns the listed scripts to a shared 200-item cap policy, adds saturation handling, and includes regression tests for the new rule.                   |
| Mergework Public Artifact Hygiene | ✅ Passed | Touched files are scripts/tests only; PR description has no investment, price, cash-out, or private-security claims.                                          |
|          Bounty Pr Focus          | ✅ Passed | PASS: The commit only touches the bounty-report scripts and matching tests named in `#1141`, and the shared helper enforces the stated 200/200 live-cap policy. |

</details>

</details>

<!-- pre_merge_checks_walkthrough_end -->
<!-- tips_start -->

---

Thanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ramimbo/mergework&utm_content=1165)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>


<sub>Comment `@coderabbitai help` to get the list of available commands.</sub>

<!-- tips_end -->

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 99e997bf-9ef0-4f4e-956b-343a96c32fa9

📥 Commits

Reviewing files that changed from the base of the PR and between 3bc87d2 and 2bf1f78.

📒 Files selected for processing (7)
  • scripts/check_live_bounty_closing_refs.py
  • scripts/gh_collection_caps.py
  • scripts/pr_queue_health.py
  • scripts/review_bounty_candidates.py
  • scripts/submission_quality_gate.py
  • tests/test_gh_collection_caps.py
  • tests/test_pr_queue_health.py

Comment on lines +162 to +165
def load_live_data(repo: str, api_host: str, state: str, pr_numbers: list[int]) -> dict[str, Any]:
return {
"bounties": load_public_bounty_list(api_host, query="status=open&limit=200"),
"pull_requests": _load_pull_requests(repo, state, pr_numbers),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Filter the public bounty query by repo.

analyze_closing_refs() only matches on issue numbers, but Line 164 now loads every open bounty from the public API. GitHub issue numbers are repo-scoped, so an open bounty #123 in another repo can collide with this repo’s #123 and trigger a false violation; the global 200-row cap can also crowd out this repo’s own bounties.

Suggested fix
 def load_live_data(repo: str, api_host: str, state: str, pr_numbers: list[int]) -> dict[str, Any]:
     return {
-        "bounties": load_public_bounty_list(api_host, query="status=open&limit=200"),
+        "bounties": load_public_bounty_list(
+            api_host,
+            query=f"status=open&limit=200&repo={repo}",
+        ),
         "pull_requests": _load_pull_requests(repo, state, pr_numbers),
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def load_live_data(repo: str, api_host: str, state: str, pr_numbers: list[int]) -> dict[str, Any]:
return {
"bounties": load_public_bounty_list(api_host, query="status=open&limit=200"),
"pull_requests": _load_pull_requests(repo, state, pr_numbers),
def load_live_data(repo: str, api_host: str, state: str, pr_numbers: list[int]) -> dict[str, Any]:
return {
"bounties": load_public_bounty_list(
api_host,
query=f"status=open&limit=200&repo={repo}",
),
"pull_requests": _load_pull_requests(repo, state, pr_numbers),

Comment thread scripts/gh_collection_caps.py Outdated
Comment on lines +47 to +60
mode: str = FAIL_ON_SATURATION,
issue_warn_detail: str | None = None,
) -> str | None:
if len(items) < cap:
return None
message = saturation_message(
collection=collection,
cap=cap,
warn_only=(mode == WARN_ON_SATURATION),
issue_warn_detail=issue_warn_detail,
)
if mode == FAIL_ON_SATURATION:
raise RuntimeError(message)
return message

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject unsupported saturation modes explicitly.

Any value other than "fail" skips the exception path here. A typo silently downgrades fail-fast callers into warn-only behavior and can let saturated gh output be treated as trustworthy. Validate mode up front and raise ValueError for unknown values.

Proposed fix
 def check_collection_saturation(
     items: list[Any],
     *,
     cap: int,
     collection: str,
     mode: str = FAIL_ON_SATURATION,
     issue_warn_detail: str | None = None,
 ) -> str | None:
+    if mode not in {FAIL_ON_SATURATION, WARN_ON_SATURATION}:
+        raise ValueError(f"unsupported saturation mode: {mode}")
     if len(items) < cap:
         return None
     message = saturation_message(
         collection=collection,
         cap=cap,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mode: str = FAIL_ON_SATURATION,
issue_warn_detail: str | None = None,
) -> str | None:
if len(items) < cap:
return None
message = saturation_message(
collection=collection,
cap=cap,
warn_only=(mode == WARN_ON_SATURATION),
issue_warn_detail=issue_warn_detail,
)
if mode == FAIL_ON_SATURATION:
raise RuntimeError(message)
return message
mode: str = FAIL_ON_SATURATION,
issue_warn_detail: str | None = None,
) -> str | None:
if mode not in {FAIL_ON_SATURATION, WARN_ON_SATURATION}:
raise ValueError(f"unsupported saturation mode: {mode}")
if len(items) < cap:
return None
message = saturation_message(
collection=collection,
cap=cap,
warn_only=(mode == WARN_ON_SATURATION),
issue_warn_detail=issue_warn_detail,
)
if mode == FAIL_ON_SATURATION:
raise RuntimeError(message)
return message

Comment thread scripts/review_bounty_candidates.py
Comment thread tests/test_gh_collection_caps.py Outdated
Comment on lines +8 to +25
def test_check_collection_saturation_passes_below_cap() -> None:
caps.check_collection_saturation([1, 2], cap=3, collection="pr")


def test_check_collection_saturation_fails_at_cap() -> None:
with pytest.raises(RuntimeError, match="pr list reached the 2 item safety cap"):
caps.check_collection_saturation([1, 2], cap=2, collection="pr")


def test_check_collection_saturation_warn_mode_returns_message() -> None:
message = caps.check_collection_saturation(
[1, 2],
cap=2,
collection="issue",
mode=caps.WARN_ON_SATURATION,
)
assert message is not None
assert "referenced-issue checks may be incomplete" in message

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Cover the full helper contract in the regression tests.

The new suite never asserts the below-cap None return, and it does not exercise the issue_warn_detail override that scripts/submission_quality_gate.py:682-688 now depends on. A regression in either branch would still pass here.

Proposed test additions
 def test_check_collection_saturation_passes_below_cap() -> None:
-    caps.check_collection_saturation([1, 2], cap=3, collection="pr")
+    assert caps.check_collection_saturation([1, 2], cap=3, collection="pr") is None
@@
 def test_check_collection_saturation_warn_mode_returns_message() -> None:
     message = caps.check_collection_saturation(
         [1, 2],
         cap=2,
         collection="issue",
         mode=caps.WARN_ON_SATURATION,
     )
     assert message is not None
     assert "referenced-issue checks may be incomplete" in message
+
+
+def test_check_collection_saturation_warn_mode_uses_custom_issue_detail() -> None:
+    message = caps.check_collection_saturation(
+        [1, 2],
+        cap=2,
+        collection="issue",
+        mode=caps.WARN_ON_SATURATION,
+        issue_warn_detail="bounty discovery may be incomplete",
+    )
+    assert (
+        message
+        == "gh issue list reached the 2 item safety cap; "
+        "bounty discovery may be incomplete"
+    )
As per coding guidelines, "Add or update tests for changed behavior"; as per path instructions, "Focus on whether tests prove the changed behavior and include negative, replay, boundary, or regression cases where relevant."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_check_collection_saturation_passes_below_cap() -> None:
caps.check_collection_saturation([1, 2], cap=3, collection="pr")
def test_check_collection_saturation_fails_at_cap() -> None:
with pytest.raises(RuntimeError, match="pr list reached the 2 item safety cap"):
caps.check_collection_saturation([1, 2], cap=2, collection="pr")
def test_check_collection_saturation_warn_mode_returns_message() -> None:
message = caps.check_collection_saturation(
[1, 2],
cap=2,
collection="issue",
mode=caps.WARN_ON_SATURATION,
)
assert message is not None
assert "referenced-issue checks may be incomplete" in message
def test_check_collection_saturation_passes_below_cap() -> None:
assert caps.check_collection_saturation([1, 2], cap=3, collection="pr") is None
def test_check_collection_saturation_fails_at_cap() -> None:
with pytest.raises(RuntimeError, match="pr list reached the 2 item safety cap"):
caps.check_collection_saturation([1, 2], cap=2, collection="pr")
def test_check_collection_saturation_warn_mode_returns_message() -> None:
message = caps.check_collection_saturation(
[1, 2],
cap=2,
collection="issue",
mode=caps.WARN_ON_SATURATION,
)
assert message is not None
assert "referenced-issue checks may be incomplete" in message
def test_check_collection_saturation_warn_mode_uses_custom_issue_detail() -> None:
message = caps.check_collection_saturation(
[1, 2],
cap=2,
collection="issue",
mode=caps.WARN_ON_SATURATION,
issue_warn_detail="bounty discovery may be incomplete",
)
assert (
message
== "gh issue list reached the 2 item safety cap; "
"bounty discovery may be incomplete"
)

Sources: Coding guidelines, Path instructions

Comment thread tests/test_pr_queue_health.py Outdated
Comment on lines +503 to +548
def test_pr_queue_health_fails_fast_when_issue_fetch_hits_cap(monkeypatch) -> None:
def fake_run(args, **kwargs):
if args[:3] == ["gh", "pr", "list"]:
stdout = "[]"
elif args[:3] == ["gh", "issue", "list"]:
stdout = json.dumps(
[
{"number": number, "title": "MRWK bounty: many", "state": "OPEN"}
for number in range(1, 202)
]
)
else:
raise AssertionError(args)
return subprocess.CompletedProcess(args=args, returncode=0, stdout=stdout, stderr="")
monkeypatch.setattr(pr_queue_health.subprocess, "run", fake_run)
with pytest.raises(RuntimeError, match="issue list reached the 200 item safety cap"):
pr_queue_health.load_live_queue("ramimbo/mergework")
def test_pr_queue_health_fails_fast_when_pr_fetch_hits_cap(monkeypatch) -> None:
def fake_run(args, **kwargs):
if args[:3] == ["gh", "pr", "list"]:
stdout = json.dumps(
[
{
"number": number,
"title": "Open PR",
"body": "Refs #1",
"labels": [],
"mergeStateStatus": "clean",
}
for number in range(1, 202)
]
)
elif args[:3] == ["gh", "issue", "list"]:
stdout = "[]"
else:
raise AssertionError(args)
return subprocess.CompletedProcess(args=args, returncode=0, stdout=stdout, stderr="")
monkeypatch.setattr(pr_queue_health.subprocess, "run", fake_run)
with pytest.raises(RuntimeError, match="pr list reached the 200 item safety cap"):
pr_queue_health.load_live_queue("ramimbo/mergework")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Assert the requested gh --limit in these saturation regressions.

Both fakes always return 201 rows, so these tests only prove the updated error wording. They would still pass if load_live_queue() stopped sending --limit 200, which is part of this change. Capture the command args and assert the list call used --limit 200, or make the fake honor the requested limit so the boundary wiring is actually covered. As per path instructions, "Do not request docstrings. Focus on whether tests prove the changed behavior and include negative, replay, boundary, or regression cases where relevant."

🧰 Tools
🪛 ast-grep (0.44.0)

[info] 507-512: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
[
{"number": number, "title": "MRWK bounty: many", "state": "OPEN"}
for number in range(1, 202)
]
)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 526-537: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
[
{
"number": number,
"title": "Open PR",
"body": "Refs #1",
"labels": [],
"mergeStateStatus": "clean",
}
for number in range(1, 202)
]
)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

Source: Path instructions

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed current head 2bf1f7822ac5d120404ba867f2402fecd7da98b2.

This branch is not merge-ready because the required CI gate fails before the suite can run. In CI run 28320025428, pytest collection reports three import errors:

  • tests/test_check_live_bounty_closing_refs.py -> ModuleNotFoundError: No module named 'scripts.gh_cli'
  • tests/test_pr_queue_health.py -> ModuleNotFoundError: No module named 'scripts.gh_cli'
  • tests/test_review_bounty_candidates.py -> ModuleNotFoundError: No module named 'scripts.gh_cli'

The PR introduces scripts/gh_collection_caps.py and updates multiple report scripts to import shared helpers, but the scripts.gh_cli module they now depend on is not part of this branch. A clean checkout therefore cannot collect tests.

Please include the missing shared gh_cli helper or avoid the dependency on it in this PR.

Scope checked: CI log, current PR metadata, CodeRabbit status, and changed-file list only. No wallet, treasury, payout, private data, credentials, or external mutation paths were exercised.

@yanyishuai yanyishuai force-pushed the bounty-1141-gh-collection-caps branch from 2bf1f78 to 8a834b9 Compare June 30, 2026 14:12

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed current head 8a834b9200fe1d3b312af181f2733969b4bbd25c.

This is still not merge-ready. The PR body says it adds scripts/gh_collection_caps.py and tests/test_gh_collection_caps.py, but the current diff contains neither file; the scripts continue to carry local collection cap constants/policy. That means the shared cap-policy abstraction described by #1141 is not actually implemented yet. The hosted quality/readiness check is also failing.

Please add the shared policy module and targeted tests, wire the scripts to that shared module, and reduce the large line-ending/no-op rewrite so the reviewable diff is limited to the intended behavior.

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.

Proposed work: unify live GitHub collection safety-cap policy across report scripts

2 participants