Skip to content

fix(agent-actions): never approve a repeat unlinked-issue offender's PR it is closing - #6695

Closed
jaytbarimbao-collab wants to merge 1 commit into
JSONbored:mainfrom
jaytbarimbao-collab:fix-agent-actions-approve-close-coherence
Closed

fix(agent-actions): never approve a repeat unlinked-issue offender's PR it is closing#6695
jaytbarimbao-collab wants to merge 1 commit into
JSONbored:mainfrom
jaytbarimbao-collab:fix-agent-actions-approve-close-coherence

Conversation

@jaytbarimbao-collab

Copy link
Copy Markdown
Contributor

Bug (self-found, no issue)

planAgentMaintenanceActions (src/settings/agent-actions.ts) documents that it returns a coherent disposition set — its contract comment: "never both merge and close", and the approve guard's own comment: approving "a PR we're about to close is incoherent (and a stale approval strands the PR if it later goes green)."

The approve guard excludes two of the three close paths that can coexist with a review-good PR — !linkedIssueCloseInFlight and !isConflict — but omits the third: a confirmed repeat unlinked-issue offender, unlinkedIssueMatchViolated (which fires its own one-shot close).

Triggering input

A green, gate-passing, not-yet-approved PR from a confirmed repeat unlinked-issue offender, with both approve and close autonomy acting:

  • conclusion: "success"reviewGood === true
  • autonomy: { approve: "auto", close: "auto" }
  • unlinkedIssueMatchClose set, mergeableState: "clean", reviewDecision unset

Result: the plan is ["approve", "close"] — the bot approves the very PR it is closing as a repeat violation, and leaves a stale approval behind.

heldForManualReview does not catch this: its unlinked term is input.unlinkedIssueMatchClose !== undefined && !acting("close"), which is deliberately false exactly when close is acting — the scenario here.

Fix

Add !unlinkedIssueMatchViolated to the approve guard — the same term the sibling close paths already carry (lines 1092 and 1128–1134). The one place that checked !linkedIssueCloseInFlight but forgot !unlinkedIssueMatchViolated is now consistent, so a repeat offender's PR gets a single close and no approval.

Every other approve / merge / close / hold disposition is unchanged.

Test

Adds a regression test to the "unlinked-issue-match CLOSE" suite asserting the plan contains close and not approve for the triggering input. Verified it fails on the current code (plan is ["approve","close"]) and passes with the fix.

  • Full agent-actions suite: 287/287 pass.
  • src/settings/agent-actions.ts: statements/lines 100%, and the changed guard line's new branch is covered on both outcomes (repeat-offender → approve suppressed; normal → approve proceeds), so the patch is fully covered.

…PR it is closing

planAgentMaintenanceActions guarantees a coherent disposition set ("never
both merge and close"). The approve guard excluded the linked-issue and
conflict close paths (!linkedIssueCloseInFlight, !isConflict) but omitted the
third close path that can coexist with a review-good PR: a confirmed repeat
unlinked-issue offender (unlinkedIssueMatchViolated).

So a green, clean, not-yet-approved PR from a confirmed repeat offender, with
both approve and close autonomy acting, was planned as an incoherent
["approve", "close"] pair — the bot approves the very PR it closes as a
repeat violation, and leaves a stale approval behind. heldForManualReview
does not catch this: its unlinked term is gated on !acting("close"), which is
false precisely when close is acting.

Add !unlinkedIssueMatchViolated to the approve guard, matching the sibling
close paths (lines 1092, 1128-1134) that already carry it. Now the plan is a
single close. Every other approve/close/merge disposition is unchanged.

Adds a regression test asserting the plan contains close and not approve for
this input.
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

1 similar comment
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.65%. Comparing base (c4f31f0) to head (d882948).
⚠️ Report is 12 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6695      +/-   ##
==========================================
- Coverage   93.65%   93.65%   -0.01%     
==========================================
  Files         682      682              
  Lines       68118    68112       -6     
  Branches    18711    18708       -3     
==========================================
- Hits        63795    63788       -7     
  Misses       3347     3347              
- Partials      976      977       +1     
Flag Coverage Δ
shard-1 43.89% <0.00%> (-0.01%) ⬇️
shard-2 36.97% <100.00%> (+<0.01%) ⬆️
shard-3 32.45% <0.00%> (-0.01%) ⬇️
shard-4 34.23% <0.00%> (-0.01%) ⬇️
shard-5 31.38% <0.00%> (+<0.01%) ⬆️
shard-6 45.74% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/settings/agent-actions.ts 97.95% <100.00%> (ø)

... and 3 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 16, 2026
@loopover-orb

loopover-orb Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Caution

🛑 LoopOver review result - reject/close recommended

Review updated: 2026-07-16 19:50:48 UTC

2 files · 1 AI reviewer · 2 blockers · CI green · clean

🛑 Suggested Action - Reject/Close

Review summary
This is a narrow, well-targeted one-line guard fix: adds `!unlinkedIssueMatchViolated` to the approve guard in `planAgentMaintenanceActions`, matching the same exclusion already present in the sibling close paths (cited at lines 1092, 1128-1134). The fix is consistent with the function's documented contract of never emitting both approve and close, and the accompanying regression test constructs the exact triggering scenario (green, clean, not-yet-approved, repeat offender, both approve/close autonomy acting) and asserts close-without-approve. The PR description explicitly states the test fails on pre-fix code, which is a credible verification of the bug's reachability.

Nits — 4 non-blocking
  • The added block comment in agent-actions.ts is fairly verbose for a one-line guard change; could be trimmed to the essential rationale.
  • No issue link is mentioned in the PR description despite being a 'self-found, no issue' fix — per repo convention this should ideally be tied to an authorized issue or explicitly called out as maintainer-authorized.
  • Consider a short changelog/comment reference back to this PR number once merged, since the existing comments already cite feat(mcp): add gittensory_explain_gate_disposition tool (#2234) #4220 and feat(agent): maintainer write-actions layer (request-changes/approve/merge/close/label) #778 for historical context.
  • If other guards in this file follow the same three-exclusion pattern (linkedIssueCloseInFlight, isConflict, unlinkedIssueMatchViolated), a small shared helper could reduce the risk of this same omission recurring elsewhere — noted as a future refactor, not required now.

Why this is blocked

  • No linked issue detected — If this PR is intended to solve an issue, link it explicitly in the PR body.
  • Maintainer requires a linked issue — Link the relevant issue (for example Closes #123) before opening the PR.
📋 Copy for AI agents — paste into your coding agent
Fix the following blocker(s) from this PR review:

1. No linked issue detected — If this PR is intended to solve an issue, link it explicitly in the PR body.

2. Maintainer requires a linked issue — Link the relevant issue (for example `Closes #123`) before opening the PR.

Decision drivers

  • ❌ Code review — 2 blockers (1 reviewer)
  • ❌ Gate result — Blocking (Repo-configured hard blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ⚠️ Missing No linked issue or no-issue rationale found.
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (no linked issue context).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 158 registered-repo PR(s), 83 merged, 4 issue(s).
Contributor context ✅ Confirmed Gittensor contributor jaytbarimbao-collab; Gittensor profile; 158 PR(s), 4 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Review context
  • Author: jaytbarimbao-collab
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Rust
  • Official Gittensor activity: 158 PR(s), 4 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Explain no-issue PR.
  • Then work through the remaining 2 steps in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb

loopover-orb Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

LoopOver is closing this pull request on the maintainer's behalf (No linked issue detected; Maintainer requires a linked issue). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed.

@loopover-orb loopover-orb Bot closed this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant