Skip to content

Validate report script source arguments#832

Open
vondutchi wants to merge 3 commits into
ramimbo:mainfrom
vondutchi:codex/report-source-validation-807
Open

Validate report script source arguments#832
vondutchi wants to merge 3 commits into
ramimbo:mainfrom
vondutchi:codex/report-source-validation-807

Conversation

@vondutchi
Copy link
Copy Markdown
Contributor

@vondutchi vondutchi commented Jun 2, 2026

Bounty #761
Source issue: #807

Summary

  • reject empty or whitespace-only --input / --repo source values in proposed-work triage, claim inventory, and PR queue health
  • choose fixture/live source mode by explicit argument presence instead of truthiness
  • add focused regression tests for each script

Evidence

#807 reproduced raw tracebacks or malformed gh invocations for empty source arguments across the remaining report helpers.

Verification

  • /tmp/mergework-py312-venv/bin/python -m pytest tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py
  • /tmp/mergework-py312-venv/bin/python scripts/docs_smoke.py
  • /tmp/mergework-py312-venv/bin/python -m ruff check scripts/proposed_work_triage.py scripts/claim_inventory.py scripts/pr_queue_health.py tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py
  • /tmp/mergework-py312-venv/bin/python -m ruff format --check scripts/proposed_work_triage.py scripts/claim_inventory.py scripts/pr_queue_health.py tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py
  • git diff --check

No changes to review candidate or submission quality source validation, no report scoring rewrite, no GitHub mutation, treasury, payout, wallet, private data, secret, bridge, exchange, off-ramp, cash-out, or price behavior.

Summary by CodeRabbit

  • Bug Fixes

    • CLI now rejects empty, whitespace-only, or values with leading/trailing whitespace for input and repository options, returning a clear parse error and non-zero exit instead of silently proceeding.
    • Offline fixture input is validated as JSON object; non-object fixtures now raise an error.
  • Tests

    • Added parameterized tests asserting argument/fixture validation triggers the expected error (exit code 2 or ValueError), emits no traceback, and produces no stdout.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Three CLI scripts gain a shared _require_non_empty_arg() validator that rejects empty or whitespace-only --input/--repo values. Each script's main() now explicitly checks args.input is not None and validates the chosen argument before loading fixture or live data. Parametrized tests were added.

Changes

CLI Argument Validation Pattern

Layer / File(s) Summary
Validation helper implementation
scripts/claim_inventory.py, scripts/pr_queue_health.py, scripts/proposed_work_triage.py
New _require_non_empty_arg() function added to each script to validate CLI option strings are non-empty after stripping and to reject values with surrounding whitespace via parser.error().
Main function CLI branch updates
scripts/claim_inventory.py, scripts/pr_queue_health.py, scripts/proposed_work_triage.py
Each main() now checks args.input is not None explicitly; when --input is present it is validated then used to load fixtures (_load_input), otherwise --repo is validated then used to load live inventory/queue/issues.
Parametrized CLI validation tests
tests/test_claim_inventory.py, tests/test_pr_queue_health.py, tests/test_proposed_work_triage.py
Each test file adds pytest-based parametrized tests covering empty/whitespace --input and --repo cases asserting exit code 2, the specific parser error in stderr, no Traceback in stderr, and empty stdout. tests/test_proposed_work_triage.py also adds an offline-fixture JSON shape validation test.

Possibly related issues

Possibly related PRs

  • ramimbo/mergework#582: Touches claim_inventory.py and its tests; related to the claim_inventory changes here.
  • ramimbo/mergework#763: Introduced proposed_work_triage; this PR modifies the same entrypoint behavior and validation.
🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Bounty Pr Focus ⚠️ Warning PR targets correct scope but doesn't address review comment: _load_input() still raises ValueError instead of routing fixture errors through parser.error() in proposed_work_triage.py. Modify _load_input() to accept parser and use parser.error() for fixture validation failures; update test expectations from ValueError to SystemExit(2).
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Validate report script source arguments' directly names the changed surface and summarizes the main change across the affected scripts.
Description check ✅ Passed The description includes a bounty reference, summary of changes, evidence of the issue, and verification steps run; it meets the template requirements with all critical sections addressed.
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 PR modifies only code/test files with CLI validation logic. No documentation, README, or public artifacts are changed; no investment, pricing, cash-out, or payout claims are introduced.

✏️ 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.

@vondutchi vondutchi force-pushed the codex/report-source-validation-807 branch from 3e8e146 to bbba6bd Compare June 2, 2026 16:45
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: 23a049ba-5072-4912-a927-0a0f5458b295

📥 Commits

Reviewing files that changed from the base of the PR and between 8f19756 and 3e8e146.

📒 Files selected for processing (6)
  • scripts/claim_inventory.py
  • scripts/pr_queue_health.py
  • scripts/proposed_work_triage.py
  • tests/test_claim_inventory.py
  • tests/test_pr_queue_health.py
  • tests/test_proposed_work_triage.py

Comment thread tests/test_claim_inventory.py
Comment thread tests/test_pr_queue_health.py
Comment thread tests/test_proposed_work_triage.py
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: 2

♻️ Duplicate comments (3)
tests/test_claim_inventory.py (1)

291-311: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add the missing --repo "" regression case.

The parametrization includes ["--repo", " "] (whitespace) but omits ["--repo", ""] (empty string). Both boundary conditions should be tested to prove the validation rejects empty and whitespace-only values.

Add: (["--repo", ""], "--repo must be a non-empty value")

As per coding guidelines, Add or update tests for changed behavior and Focus on whether tests prove the changed behavior and include negative, replay, boundary, or regression cases where relevant.

tests/test_pr_queue_health.py (1)

107-127: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cover the empty-string --repo case too.

The test matrix exercises ["--repo", " "] but not ["--repo", ""]. Since this change validates empty and whitespace-only source values, add (["--repo", ""], "--repo must be a non-empty value") to prove both invalid forms are rejected.

As per coding guidelines, Add or update tests for changed behavior and Focus on whether tests prove the changed behavior and include negative, replay, boundary, or regression cases where relevant.

tests/test_proposed_work_triage.py (1)

406-427: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add the explicit empty --repo assertion.

This regression test covers ["--input", ""] and ["--input", " "] and ["--repo", " "], but omits ["--repo", ""]. Add (["--repo", ""], "--repo must be a non-empty value") to exercise the empty-string boundary.

As per coding guidelines, Add or update tests for changed behavior and Focus on whether tests prove the changed behavior and 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: 3172a354-140a-4ecc-b8b8-dacfa087cb78

📥 Commits

Reviewing files that changed from the base of the PR and between 3e8e146 and bbba6bd.

📒 Files selected for processing (6)
  • scripts/claim_inventory.py
  • scripts/pr_queue_health.py
  • scripts/proposed_work_triage.py
  • tests/test_claim_inventory.py
  • tests/test_pr_queue_health.py
  • tests/test_proposed_work_triage.py

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

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

♻️ Duplicate comments (3)
tests/test_claim_inventory.py (1)

291-311: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add the missing --repo "" regression case.

The parametrization includes ["--repo", " "] (whitespace) but omits ["--repo", ""] (empty string). Both boundary conditions should be tested to prove the validation rejects empty and whitespace-only values.

Add: (["--repo", ""], "--repo must be a non-empty value")

As per coding guidelines, Add or update tests for changed behavior and Focus on whether tests prove the changed behavior and include negative, replay, boundary, or regression cases where relevant.

tests/test_pr_queue_health.py (1)

107-127: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cover the empty-string --repo case too.

The test matrix exercises ["--repo", " "] but not ["--repo", ""]. Since this change validates empty and whitespace-only source values, add (["--repo", ""], "--repo must be a non-empty value") to prove both invalid forms are rejected.

As per coding guidelines, Add or update tests for changed behavior and Focus on whether tests prove the changed behavior and include negative, replay, boundary, or regression cases where relevant.

tests/test_proposed_work_triage.py (1)

406-427: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add the explicit empty --repo assertion.

This regression test covers ["--input", ""] and ["--input", " "] and ["--repo", " "], but omits ["--repo", ""]. Add (["--repo", ""], "--repo must be a non-empty value") to exercise the empty-string boundary.

As per coding guidelines, Add or update tests for changed behavior and Focus on whether tests prove the changed behavior and 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: 3172a354-140a-4ecc-b8b8-dacfa087cb78

📥 Commits

Reviewing files that changed from the base of the PR and between 3e8e146 and bbba6bd.

📒 Files selected for processing (6)
  • scripts/claim_inventory.py
  • scripts/pr_queue_health.py
  • scripts/proposed_work_triage.py
  • tests/test_claim_inventory.py
  • tests/test_pr_queue_health.py
  • tests/test_proposed_work_triage.py
🛑 Comments failed to post (2)
tests/test_proposed_work_triage.py (2)

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

Remove redundant import statement.

pytest is already imported at line 8. This redundant import inside the function is unnecessary and unconventional.


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

Remove redundant import statement.

pytest is already imported at line 8. This redundant import inside the function is unnecessary and unconventional.

Copy link
Copy Markdown
Contributor

@keilogic keilogic left a comment

Choose a reason for hiding this comment

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

Thanks, this looks good. I did not find a current-head blocker.

The three report scripts now stop empty and whitespace-only --input / --repo source values at argparse with bounded errors, and the explicit args.input is not None checks preserve the offline/live branch selection.

I also checked the explicit --repo "" boundary CodeRabbit called out for all three scripts. Each exits with code 2, reports the expected --repo must be a non-empty value error, and does not traceback. Adding those exact cases to the parametrized tests would make the regression matrix cleaner, and the two redundant local pytest imports in tests/test_proposed_work_triage.py could be tidied, but neither is a runtime blocker for this patch.

Validation I ran:

  • python -m pytest tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py -q -> 52 passed
  • python scripts/docs_smoke.py -> docs smoke ok
  • python -m ruff check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> passed
  • python -m ruff format --check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> passed
  • Direct probes for --input "", --input " ", --repo "", and --repo " " across all three scripts -> bounded argparse errors, no tracebacks
  • git diff --check origin/main...HEAD -> passed
  • git merge-tree --write-tree origin/main HEAD -> clean

One note on type checking: targeted mypy over the three scripts still reports an existing no-any-return at the unchanged _gh_issue_search() return path in scripts/proposed_work_triage.py; I did not treat that as introduced by this PR.

Copy link
Copy Markdown
Contributor

@gshaowei6 gshaowei6 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 bbba6bdd9e501af2f0f647ac74766d1b517c4dc9 against origin/main 8f197562f3e6fe5d1a61a57456c36eda4309b0d1.

I think this needs one more pass. The new _require_non_empty_arg() helpers validate with value.strip(), but they return the original untrimmed value. That leaves padded, non-empty source arguments outside the bounded validation path and still lets them fall into raw downstream tracebacks.

Direct probes on this head:

  • python scripts/claim_inventory.py --repo " ramimbo/mergework " reaches gh issue list with the padded repo and raises a raw RuntimeError/GraphQL repository error.
  • python scripts/pr_queue_health.py --repo " ramimbo/mergework " reaches gh pr list with the padded repo and raises a raw RuntimeError/GraphQL repository error.
  • python scripts/proposed_work_triage.py --repo " ramimbo/mergework " reaches the live GitHub search path and raises the raw repository resolution error.
  • python scripts/claim_inventory.py --input " tests/fixtures/missing.json " reaches _load_input() and raises a raw FileNotFoundError for the space-padded path.
  • python scripts/pr_queue_health.py --input " tests/fixtures/missing.json " does the same.

That is still the same source-argument validation family as #807. I would either return the stripped value from the helper or reject values whose stripped form differs, then add coverage for padded non-empty --repo / --input cases so these scripts fail through argparse instead of raw tracebacks.

Validation I ran:

  • With TMP/TEMP pointed inside the worktree: python -m pytest tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py -q -> 52 passed.
  • python -m ruff check scripts/proposed_work_triage.py scripts/claim_inventory.py scripts/pr_queue_health.py tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py -> passed.
  • python -m ruff format --check ... -> 6 files already formatted.
  • 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 cfd9b3d305cdf66804502d0c3c6ed72180a6044a.
  • Hosted Quality, readiness, docs, and image checks and CodeRabbit are passing.

I also tried mypy on the three touched scripts; it still reports scripts/proposed_work_triage.py:397: Returning Any from function declared to return list[dict[str, Any]]. The raw traceback path above is the blocker for me.

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 (1)
scripts/proposed_work_triage.py (1)

545-546: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate offline fixture shape before calling analyze_proposed_work().

This branch now accepts any JSON value. A fixture like [] or "x" will parse successfully here and then crash with an AttributeError once analyze_proposed_work() does data.get(...). The other two report scripts already reject non-object fixtures up front, so this should do the same and add a regression test for it.

Proposed fix
+def _load_input(path: str) -> dict[str, Any]:
+    data = json.loads(Path(path).read_text(encoding="utf-8"))
+    if not isinstance(data, dict):
+        raise ValueError("proposed-work input must be a JSON object")
+    return data
+
+
 def main(argv: list[str] | None = None) -> int:
@@
     if args.input is not None:
         if args.payment_bounty_issue:
             parser.error("--payment-bounty-issue is only valid in live --repo mode")
-        input_path = Path(_require_non_empty_arg(parser, "--input", args.input))
-        data = json.loads(input_path.read_text(encoding="utf-8"))
+        data = _load_input(_require_non_empty_arg(parser, "--input", args.input))
     else:
         repo = _require_non_empty_arg(parser, "--repo", args.repo)
         data = load_live_issues(
As per coding guidelines, `Add or update tests for changed behavior`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0b56b234-0012-4339-bce3-e23c35ed2ae2

📥 Commits

Reviewing files that changed from the base of the PR and between bbba6bd and 22db26d.

📒 Files selected for processing (6)
  • scripts/claim_inventory.py
  • scripts/pr_queue_health.py
  • scripts/proposed_work_triage.py
  • tests/test_claim_inventory.py
  • tests/test_pr_queue_health.py
  • tests/test_proposed_work_triage.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 more small fix on the current head.

The earlier padded --repo / --input issue is fixed: I verified the three report scripts now reject leading/trailing whitespace through argparse. However, scripts/proposed_work_triage.py still parses any JSON value from --input and then passes it to analyze_proposed_work(), which expects an object. A non-object fixture therefore still produces a raw traceback instead of a bounded CLI/input validation error.

Direct repros on head 22db26d27276e38571e72c8f6d3786b114c5f8cd:

  • printf '[]' > "$tmp"; python scripts/proposed_work_triage.py --input "$tmp" --format json -> AttributeError: 'list' object has no attribute 'get'
  • printf '"x"' > "$tmp"; python scripts/proposed_work_triage.py --input "$tmp" --format json -> AttributeError: 'str' object has no attribute 'get'

A valid object fixture still works:

  • printf '{"issues": [], "bounties": []}' > "$tmp"; python scripts/proposed_work_triage.py --input "$tmp" --format json -> exits 0 and emits the expected empty report shape.

Suggested fix: add a _load_input() path for proposed_work_triage.py like the other report scripts and reject non-object JSON before calling analyze_proposed_work(), with regression coverage for at least one non-object fixture.

Validation I ran:

  • python -m pytest tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py -q -> 61 passed
  • python scripts/docs_smoke.py -> docs smoke ok
  • python -m ruff check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> passed
  • python -m ruff format --check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> 6 files already formatted
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree 5b2a0872c1412e9cc61708642209045faf37fd15
  • Hosted Quality/readiness/docs/image and CodeRabbit checks are passing

Targeted mypy over the three touched scripts still reports the existing scripts/proposed_work_triage.py:397 no-any-return; I did not treat that as introduced by this PR. 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7d06dba8-b58a-4e49-98bb-db28df0a0f57

📥 Commits

Reviewing files that changed from the base of the PR and between 22db26d and 4d48326.

📒 Files selected for processing (2)
  • scripts/proposed_work_triage.py
  • tests/test_proposed_work_triage.py

Comment on lines +523 to +527
def _load_input(path: str) -> dict[str, Any]:
data = json.loads(Path(path).read_text(encoding="utf-8"))
if not isinstance(data, dict):
raise ValueError("proposed-work input must be a JSON object")
return data
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Report invalid offline fixtures through parser.error().

A non-object --input fixture still escapes as ValueError here, so the CLI prints a traceback instead of the same SystemExit(2)/usage error path used for the new empty-source validation. Please route fixture read/parse/shape failures through parser.error(...) as well.

Proposed fix
-def _load_input(path: str) -> dict[str, Any]:
-    data = json.loads(Path(path).read_text(encoding="utf-8"))
-    if not isinstance(data, dict):
-        raise ValueError("proposed-work input must be a JSON object")
+def _load_input(parser: argparse.ArgumentParser, path: str) -> dict[str, Any]:
+    try:
+        data = json.loads(Path(path).read_text(encoding="utf-8"))
+    except OSError as exc:
+        parser.error(f"--input could not be read: {exc}")
+    except json.JSONDecodeError as exc:
+        parser.error(f"--input must contain valid JSON: {exc.msg}")
+    if not isinstance(data, dict):
+        parser.error("--input must be a JSON object")
     return data
@@
-        data = _load_input(_require_non_empty_arg(parser, "--input", args.input))
+        data = _load_input(parser, _require_non_empty_arg(parser, "--input", args.input))

Also applies to: 549-552

Copy link
Copy Markdown
Contributor

@gshaowei6 gshaowei6 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 4d483268ee645cccecd0f4557241319926282d15 against origin/main 8f197562f3e6fe5d1a61a57456c36eda4309b0d1.

I think this still needs one more pass. The prior blank/padded source-argument blockers are fixed: direct CLI probes for empty, whitespace-only, and leading/trailing-space --input / --repo values now exit through argparse with code 2 and no traceback across scripts/claim_inventory.py, scripts/pr_queue_health.py, and scripts/proposed_work_triage.py.

The remaining blocker is the new proposed-work offline fixture shape path. scripts/proposed_work_triage.py now rejects non-object JSON before analyze_proposed_work(), but _load_input() raises a raw ValueError. When the script is invoked as a real CLI, that still prints a Python traceback instead of the bounded CLI/input validation error requested for this validation hardening work.

Direct probes on this head using the project .venv:

  • printf '[]' > "$tmp"; .venv/Scripts/python.exe scripts/proposed_work_triage.py --input "$tmp" --format json -> exits 1 with Traceback, ending at _load_input() with ValueError: proposed-work input must be a JSON object.
  • printf '"x"' > "$tmp"; .venv/Scripts/python.exe scripts/proposed_work_triage.py --input "$tmp" --format json -> same traceback path.
  • printf '{"issues": [], "bounties": []}' > "$tmp"; .venv/Scripts/python.exe scripts/proposed_work_triage.py --input "$tmp" --format json -> exits 0 and emits the expected empty report JSON.

This is a current-head follow-up to the previous 22db26d... review, not the same finding repeated unchanged. That earlier head crashed later with AttributeError after passing a non-object fixture into analyze_proposed_work(). This head moved the check earlier, but the user-facing CLI behavior is still a raw traceback.

I would route the non-object fixture error through parser.error(...) (or pass the parser into the loader and use the same bounded error path) and update test_proposed_work_triage_rejects_non_object_offline_fixture so it expects SystemExit(2), empty stdout, and no traceback. A subprocess/entrypoint regression would also catch this exact gap.

Validation I ran:

  • .venv/Scripts/python.exe -m pytest tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py -q -> 62 passed
  • .venv/Scripts/python.exe -m ruff check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> passed
  • .venv/Scripts/python.exe -m ruff format --check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> 6 files already formatted
  • .venv/Scripts/python.exe scripts/docs_smoke.py -> docs smoke ok
  • git diff --check origin/main...HEAD -> clean
  • git merge-tree --write-tree origin/main HEAD -> clean tree f66442c60c844b7b81019b562650e65e55bf3c4c
  • Hosted Quality, readiness, docs, and image checks and CodeRabbit status are successful on the current head

Targeted mypy over the three touched scripts still reports the existing scripts/proposed_work_triage.py:397 no-any-return; I did not treat that as introduced by this PR. No private data, wallet material, payout execution, treasury mutation, exchange, bridge, cash-out, or price behavior was used.

@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

Current-head blocker still reproduces on 4d48326: a non-object offline fixture for proposed-work triage still exits through a Python traceback instead of a bounded CLI/input error.\n\nRepro:\n\nsh\nprintf '[]' > ""\npython scripts/proposed_work_triage.py --input "" --format json\n\n\nObserved: exit 1 with ValueError: proposed-work input must be a JSON object and a traceback. Please route that path through argparse/bounded CLI error handling and update the regression test to assert no traceback.\n\nBounty note: #761 is closed/paid with no effective award capacity, so this is not a live #761 payout path.

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 4d483268ee645cccecd0f4557241319926282d15 as a non-author.

The blank and padded --input / --repo guards are working, and the focused test suite passes. One current-head blocker still reproduces: the proposed-work offline fixture shape check raises a raw ValueError from _load_input(), so invoking the real CLI with a non-object fixture still exits through a traceback instead of the bounded argparse/input-error path this validation hardening is trying to provide.

Direct repro on this head:

printf '[]' > <tmp>
uv run --extra dev python scripts/proposed_work_triage.py --input <tmp> --format json
# exit 1 with Traceback ending at:
# ValueError: proposed-work input must be a JSON object

Suggested fix: route the non-object fixture error through parser.error(...) or catch ValueError around _load_input() and convert it to SystemExit(2). Please also update test_proposed_work_triage_rejects_non_object_offline_fixture to assert the CLI-shaped behavior: exit code 2, empty stdout, the expected bounded error message in stderr, and no Traceback.

Validation I ran:

  • uv run --extra dev pytest tests/test_proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py -q -> 62 passed.
  • direct non-object fixture CLI probe above -> exit 1 with traceback.
  • uv run --extra dev ruff check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> passed.
  • uv run --extra dev ruff format --check scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py tests/test_claim_inventory.py tests/test_pr_queue_health.py tests/test_proposed_work_triage.py -> 6 files already formatted.
  • uv run --extra dev mypy scripts/claim_inventory.py scripts/pr_queue_health.py scripts/proposed_work_triage.py -> existing scripts/proposed_work_triage.py:397 no-any-return only; I did not treat it as introduced by this PR.
  • git diff --check origin/main...HEAD -> clean.
  • git merge-tree --write-tree origin/main HEAD -> clean tree 182e48cacaec2094a3caaabea7dfb63b738b4797.

GitHub state checked before review: PR REST state reports mergeable=true, mergeable_state=clean; hosted Quality/readiness/docs/image and CodeRabbit statuses are success. No private data, secrets, wallet material, payout execution, treasury mutation, exchange, bridge, cash-out behavior, or MRWK price behavior 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.

6 participants