fix: greenlight gate fails closed on repos missing the Agent label #375

Merged
joshtronic merged 1 commit from fix/claimable-fail-closed-agent-label into master 2026-07-11 02:35:53 +00:00
Collaborator

The bug

forgejo_find_claimable gates the claimable-issue grind with the API query issues?state=open&labels=Agent. But Forgejo ignores a labels= filter that names a label the repo doesn't have — it returns every open issue instead of none. So a repo that was never given the Agent label had no gate: the grind claimed every open, unassigned ticket and built it.

Confirmed by direct API test: on sharktankdb.com (no Agent label), issues?labels=Agent returned an unlabeled issue — identical to the unfiltered query.

Impact

sharktankdb.com — the newest repo, onboarded without the Agent label — had two unlabeled tickets claimed straight off; one merged before it was caught. Audited all 11 bot repos: only sharktankdb was missing the label; the other 10 gated correctly.

The fix

Re-verify the Agent label client-side in the jq filter (index("Agent") != null), so the gate fails closed no matter what the API returns. A repo missing the label now does no issue work (safe no-op) rather than working everything. The API filter stays as an optimization.

Test

bin/test-forgejo.sh — Agent-label requirement, unassigned/assigned-to-reviewer/assigned-to-other rules, Status/Blocked exclusion, oldest-first ordering, and the core regression: a no-Agent-label repo yields nothing claimable.

make test green; shellcheck clean.

Follow-up (not in this PR)

Onboarding (bin/validate-repo.sh) doesn't check for the Agent label, which is how sharktankdb slipped through. Worth adding to the checklist so a missing label is flagged at onboard — but with this fix a missing label is now safe (silent no-op), not dangerous.

## The bug `forgejo_find_claimable` gates the claimable-issue grind with the API query `issues?state=open&labels=Agent`. But **Forgejo ignores a `labels=` filter that names a label the repo doesn't have** — it returns *every* open issue instead of none. So a repo that was never given the `Agent` label had **no gate**: the grind claimed every open, unassigned ticket and built it. Confirmed by direct API test: on sharktankdb.com (no `Agent` label), `issues?labels=Agent` returned an unlabeled issue — identical to the unfiltered query. ## Impact sharktankdb.com — the newest repo, onboarded without the `Agent` label — had two unlabeled tickets claimed straight off; one merged before it was caught. Audited all 11 bot repos: **only sharktankdb was missing the label**; the other 10 gated correctly. ## The fix Re-verify the `Agent` label **client-side** in the jq filter (`index("Agent") != null`), so the gate fails **closed** no matter what the API returns. A repo missing the label now does *no* issue work (safe no-op) rather than working everything. The API filter stays as an optimization. ## Test `bin/test-forgejo.sh` — Agent-label requirement, unassigned/assigned-to-reviewer/assigned-to-other rules, Status/Blocked exclusion, oldest-first ordering, and the core regression: a no-Agent-label repo yields nothing claimable. `make test` green; shellcheck clean. ## Follow-up (not in this PR) Onboarding (`bin/validate-repo.sh`) doesn't check for the `Agent` label, which is how sharktankdb slipped through. Worth adding to the checklist so a missing label is flagged at onboard — but with this fix a missing label is now safe (silent no-op), not dangerous.
fix: greenlight gate fails closed on repos missing the Agent label
All checks were successful
Lint / check-sync (pull_request) Successful in 6s
Lint / check-sync (push) Successful in 4s
d30bb1ee8b
forgejo_find_claimable relied on the API query labels=Agent to gate the
claimable-issue grind. But Forgejo IGNORES a labels filter that names a label
the repo doesn't have -- it returns every open issue instead of none. So a repo
that was never given the Agent label (a fresh onboard) had NO gate: the grind
claimed every open, unassigned ticket and built it.

This bit sharktankdb.com (the newest repo, onboarded without the Agent label):
two unlabeled tickets got claimed and one merged before it was caught. All 10
other repos have the label, so they were unaffected.

Fix: re-verify the Agent label client-side in the jq filter, so the gate fails
CLOSED regardless of whether the API honored the filter. A repo missing the
label now does no issue work (safe no-op) instead of working everything.

Test: bin/test-forgejo.sh -- covers the label requirement, assignee/blocked
rules, ordering, and the core regression (no-Agent-label repo -> nothing
claimable).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YUVfbfUWdUwifGJ2TvkP
Author
Collaborator

🤖 Review — APPROVE (automated)

CI for d30bb1ee: success

Small, focused fix: adds a client-side Agent-label re-check to forgejo_find_claimable's jq filter so the gate fails closed when Forgejo ignores the labels=Agent API filter, plus a new unit-test script. CI green.

  • lib/forgejo.sh — the added and (([.labels[].name] | index("Agent")) != null) correctly drops any issue lacking the Agent label; empty labels yields []index null → dropped. Redundant-but-harmless for repos that already gate correctly at the API. Behavior for existing (labeled) repos is unchanged. Sound.
  • bin/test-forgejo.sh — verified the assertions against the fixture logic:
    • reviewer=josh → 1 4 7 (Agent+unassigned #1/#7, Agent+assigned-to-reviewer #4; drops unlabeled #2, other-label #3, assigned-to-other #5, blocked #6). ✔
    • oldest-first 7 1 4 matches created_at. ✔
    • reviewer="" → 1 7 (only unassigned). ✔
    • no-Agent-label repo → [], the core regression. ✔
    • jq-absent skip guard exits 0. ✔
  • Overriding _fj after sourcing is a clean way to stub the API; it doesn't exercise URL construction, but that's outside this fix's scope and the filter logic is what matters here.
  • Scope, honest checklist (every claim maps to the diff), tests added, shellcheck/make test reported green and CI confirms success. No security concerns.

Follow-up noted by the author (onboarding label check in validate-repo.sh) is correctly left out of this PR. Nothing blocking.


Independent review by the harness on claude-opus-4-8 (effort: high). The human reviewer is requested once Igor has reviewed; a human still merges.

### 🤖 Review — `APPROVE` _(automated)_ CI for `d30bb1ee`: **success** Small, focused fix: adds a client-side `Agent`-label re-check to `forgejo_find_claimable`'s jq filter so the gate fails closed when Forgejo ignores the `labels=Agent` API filter, plus a new unit-test script. CI green. - **lib/forgejo.sh** — the added `and (([.labels[].name] | index("Agent")) != null)` correctly drops any issue lacking the `Agent` label; empty `labels` yields `[]` → `index` null → dropped. Redundant-but-harmless for repos that already gate correctly at the API. Behavior for existing (labeled) repos is unchanged. Sound. - **bin/test-forgejo.sh** — verified the assertions against the fixture logic: - reviewer=josh → `1 4 7` (Agent+unassigned #1/#7, Agent+assigned-to-reviewer #4; drops unlabeled #2, other-label #3, assigned-to-other #5, blocked #6). ✔ - oldest-first `7 1 4` matches `created_at`. ✔ - reviewer="" → `1 7` (only unassigned). ✔ - no-Agent-label repo → `[]`, the core regression. ✔ - jq-absent skip guard exits 0. ✔ - Overriding `_fj` after sourcing is a clean way to stub the API; it doesn't exercise URL construction, but that's outside this fix's scope and the filter logic is what matters here. - Scope, honest checklist (every claim maps to the diff), tests added, shellcheck/`make test` reported green and CI confirms `success`. No security concerns. Follow-up noted by the author (onboarding label check in `validate-repo.sh`) is correctly left out of this PR. Nothing blocking. --- <sub>Independent review by the harness on `claude-opus-4-8` (effort: high). The human reviewer is requested once Igor has reviewed; a human still merges.</sub> <!-- review sha=d30bb1ee8bdceab2e94bddb875322b50a6e925a5 verdict=APPROVE ci=success -->
igor added spent time 2026-07-11 02:35:39 +00:00
23 seconds
joshtronic approved these changes 2026-07-11 02:35:50 +00:00
joshtronic deleted branch fix/claimable-fail-closed-agent-label 2026-07-11 02:35:53 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
2 participants
Notifications
Total time spent: 23 seconds
igor
23 seconds
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
joshtronic/igor!375
No description provided.