Skip to content

fix(review): require a genuinely open issue for the linked-issue block gate - #3514

Merged
JSONbored merged 1 commit into
claude/zealous-herschel-f6bfbafrom
fix/stale-linked-issue-gate
Jul 5, 2026
Merged

fix(review): require a genuinely open issue for the linked-issue block gate#3514
JSONbored merged 1 commit into
claude/zealous-herschel-f6bfbafrom
fix/stale-linked-issue-gate

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • Stacked on feat(review): hold PRs that solve an unlinked open issue #3513 (needs that PR's branch as its base — GitHub will retarget this to main automatically
    once feat(review): hold PRs that solve an unlinked open issue #3513 merges).
  • pr.linkedIssues is populated by a pure body-text regex match (extractLinkedIssueNumbersWithOverflow)
    that never checks whether the cited issue is actually open. A repo running linkedIssueGateMode: "block"
    (requires a linked issue to merge) could therefore be satisfied by a contributor citing an already-CLOSED
    or fabricated issue number — completely defeating the point of requiring a link.
  • missing_linked_issue now also fires when every one of a PR's citations resolves to confirmed-closed or
    confirmed-not-found, with live verification (src/review/linked-issue-hard-rules.ts's new
    resolveLinkedIssueHasOpenReference / hasVerifiableOpenLinkedIssueReference, mirroring the existing
    resolveLinkedIssueHardRule's fail-open/fail-closed discipline: a single ambiguous fetch error still
    fails open, only a fully-confirmed-dead set of citations trips the blocker).
  • Wired into every place that builds the gate's advisory input so none of them drift out of parity: the
    main webhook path, the cron re-gate sweep, the heavy re-review pass, and authorized PR actions
    (gate-override / panel retrigger) — via one shared resolver, resolveLinkedIssueAdvisoryContext in
    src/queue/processors.ts.
  • pr.linkedIssues itself is unchanged everywhere else it's used (duplicate-winner overlap, label
    propagation, scoring) — only the missing_linked_issue gate check gained the extra verification.
  • No linked issue: found and scoped directly with the repo owner while reviewing feat(review): hold PRs that solve an unlinked open issue #3513's design.

Scope

  • The PR title follows type(scope): short summary Conventional Commit format.
  • Focused, backend-only change (advisory/gate + processors.ts wiring + tests).
  • Follows CONTRIBUTING.md; no site//CNAME/VitePress changes.
  • No linked issue — explained above.

Validation

  • git diff --check
  • npm run actionlint — not run; no workflow files touched.
  • npm run typecheck (clean, in a fresh worktree built from this branch)
  • npm run test:coverage (full/unsharded) — not run locally; ran the full affected-file set instead
    (linked-issue-hard-rules.test.ts, rules.test.ts, agent-actions.test.ts, focus-manifest.test.ts,
    and the full queue.test.ts, 511 tests) in a clean npm ci worktree — all 1114 tests green, and
    100% branch coverage confirmed on every new/changed line via targeted --coverage.include runs
    against coverage-final.json. GitHub CI runs the full suite/gate on push.
  • npm run test:workers / npm run build:mcp / npm run test:mcp-pack — not run; nothing in those
    surfaces touched.
  • npm run ui:openapi:check / ui:lint / ui:typecheck / ui:build — not run; no OpenAPI schema or
    apps/gittensory-ui/** changes in this PR.
  • npm audit --audit-level=moderate — not run; no dependency changes.
  • New/changed behavior has unit + integration tests for every new branch: the pure evaluator's
    confirmed-open / confirmed-dead / ambiguous / mixed cases, the live-fetch orchestrator's token-mint
    and fallback paths, the advisory's new confirmedNoOpenLinkedIssue finding text and its interaction
    with the zero-citation case, and two end-to-end processJob tests proving the actual regression: a
    PR citing a closed issue under linkedIssueGateMode: block now fails the gate, and a PR citing a
    genuinely open one still passes.

If any required check was skipped, explain why:

  • Local validation was typecheck + the full affected-file test set (built in a clean npm ci worktree
    rather than reusing a possibly-stale one) rather than a full repo-wide test:ci/npm audit pass, since
    GitHub CI runs the complete gate on push.

Safety

  • No secrets, wallets, hotkeys, coldkeys, trust scores, or private scoring values are touched or exposed.
  • The gate's public output is unchanged in shape (same finding code/title; only detail text and the
    new trigger condition changed) — no new public-facing text pattern to sanitize.
  • Not an auth/CORS/session change; no negative-path tests needed for that reason.
  • No new API/OpenAPI surface.
  • Not a UI change (N/A) — no UI Evidence section included.
  • No changelog edit.

Notes

  • Fail-open is deliberate and load-bearing: a transient GitHub API error while verifying a linked issue's
    state must never wrongly block a PR that's genuinely, correctly linked to real open work — only a fully
    confirmed-dead set of citations trips the new check.

…k gate

pr.linkedIssues is populated by a pure body-text regex match and never
checked whether the cited issue is actually open, so linkedIssueGateMode:
"block" could be satisfied by citing an already-closed or fabricated issue
number. The missing_linked_issue blocker now also fires when every citation
resolves to confirmed-closed or not-found, fail-open on any ambiguous fetch
so a transient GitHub error never wrongly blocks a legitimately linked PR.
@superagent-security

Copy link
Copy Markdown
Contributor

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

@JSONbored JSONbored self-assigned this Jul 5, 2026
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (claude/zealous-herschel-f6bfba@e1e17a5). Learn more about missing BASE report.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@                        Coverage Diff                        @@
##             claude/zealous-herschel-f6bfba    #3514   +/-   ##
=================================================================
  Coverage                                  ?   93.03%           
=================================================================
  Files                                     ?      301           
  Lines                                     ?    31160           
  Branches                                  ?    11366           
=================================================================
  Hits                                      ?    28990           
  Misses                                    ?     1513           
  Partials                                  ?      657           
Files with missing lines Coverage Δ
src/queue/processors.ts 93.11% <100.00%> (ø)
src/review/linked-issue-hard-rules.ts 98.07% <100.00%> (ø)
src/rules/advisory.ts 97.27% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

loopover-orb Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Warning

🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨

⏸️ Gittensory review result - manual review recommended

Review updated: 2026-07-05 15:23:47 UTC

6 files · 1 AI reviewer · 2 blockers · readiness 100/100 · CI green · clean

⏸️ Suggested Action - Manual Review

  • 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.

Review summary
The change correctly separates raw PR-body issue citations from the stricter gate signal that at least one cited issue is live-verified open. The new advisory context is threaded through the visible gate-building paths, and the fail-open behavior on empty input, ambiguous fetches, and token-mint failure is covered by focused unit tests plus webhook-path tests for closed vs open citations. I do not see a reachable correctness defect in the provided diff.

Nits — 4 non-blocking
  • src/review/linked-issue-hard-rules.ts:230: nit: `resolveLinkedIssueHasOpenReference` should mirror the existing linked-issue fetch helpers with a local cap/slice before `Promise.all`, even though production extraction already caps `pr.linkedIssues`, so future direct callers cannot accidentally fan out over an arbitrary array.
  • src/review/linked-issue-hard-rules.ts:228: nit: the helper returns `true` for empty input while `resolveLinkedIssueAdvisoryContext` then negates it, which is correct but easy to misuse outside this call site; consider naming or documenting the exported resolver around the positive `hasOpenReference` contract more tightly.
  • src/review/linked-issue-hard-rules.ts:235: add the same `MAX_LINKED_ISSUES_TO_FETCH` defensive slice pattern used by `fetchLinkedIssueLabelsForPropagation` before issuing `Promise.all`.
  • src/queue/processors.ts:5908: consider adding a small unit test for `resolveLinkedIssueAdvisoryContext` itself so the skip-fetch behavior when `linkedIssueGateMode !== "block"` is pinned directly rather than only through higher-level webhook coverage.

Concerns raised — review before merging

  • 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.
Signal Result Evidence
Code review ❌ 2 blockers 1 reviewer
Linked issue ✅ No-issue rationale PR body explains why no issue is linked.
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: 56 registered-repo PR(s), 46 merged, 544 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 56 PR(s), 544 issue(s).
Gate result ❌ Blocking Repo-configured hard blocker found.
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository registration is not available in the local Gittensory cache.
  • Public profile languages: not available
  • Official Gittensor activity: 56 PR(s), 544 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • No action.
  • Link the issue being solved, or explicitly explain why this is a no-issue PR.
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.

🟩 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 Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 5, 2026
@JSONbored
JSONbored merged commit cddb974 into claude/zealous-herschel-f6bfba Jul 5, 2026
7 checks passed
@JSONbored
JSONbored deleted the fix/stale-linked-issue-gate branch July 5, 2026 15:28
JSONbored added a commit that referenced this pull request Jul 5, 2026
…k gate (#3514)

pr.linkedIssues is populated by a pure body-text regex match and never
checked whether the cited issue is actually open, so linkedIssueGateMode:
"block" could be satisfied by citing an already-closed or fabricated issue
number. The missing_linked_issue blocker now also fires when every citation
resolves to confirmed-closed or not-found, fail-open on any ambiguous fetch
so a transient GitHub error never wrongly blocks a legitimately linked PR.
JSONbored added a commit that referenced this pull request Jul 5, 2026
…k gate (#3514)

pr.linkedIssues is populated by a pure body-text regex match and never
checked whether the cited issue is actually open, so linkedIssueGateMode:
"block" could be satisfied by citing an already-closed or fabricated issue
number. The missing_linked_issue blocker now also fires when every citation
resolves to confirmed-closed or not-found, fail-open on any ambiguous fetch
so a transient GitHub error never wrongly blocks a legitimately linked PR.
JSONbored added a commit that referenced this pull request Jul 5, 2026
* feat(review): hold PRs that solve an unlinked open issue

Adds an opt-in, off-by-default guardrail: when a contributor PR links
no issue, a cheap deterministic pre-filter looks for open issues whose
title/body or changed-file paths overlap it, and any candidate is
verified by the free/self-host AI reviewer (never BYOK) before the PR
is held for manual review. Never auto-closes and never blocks a PR
that has nothing to match against -- only confirmed, high-confidence
matches route to a hold, so a maintainer can catch a contributor
slicing an issue across unlinked PRs to farm merge-ratio credibility
without the scrutiny a linked issue would invite.

* fix(review): require a genuinely open issue for the linked-issue block gate (#3514)

pr.linkedIssues is populated by a pure body-text regex match and never
checked whether the cited issue is actually open, so linkedIssueGateMode:
"block" could be satisfied by citing an already-closed or fabricated issue
number. The missing_linked_issue blocker now also fires when every citation
resolves to confirmed-closed or not-found, fail-open on any ambiguous fetch
so a transient GitHub error never wrongly blocks a legitimately linked PR.

* feat(review): escalate a confirmed repeat unlinked-issue match to a close

A first confirmed match still only holds the PR for manual review. A second
confirmed match by the SAME contributor (tracked via the existing
audit_events ledger, hasRecentAuditEvent/recordAuditEvent) is no longer a
coincidence worth the benefit of the doubt, so it closes the PR one-shot
instead. The close stays tagged closeKind: heuristic (not concrete evidence)
since the underlying signal is an AI semantic-match verdict, keeping it
subject to the close-precision breaker even after it repeats.

* fix(review): hold instead of merge a confirmed unlinked-issue repeat when close is disabled

heldForManualReview didn't account for unlinkedIssueMatchClose, so a confirmed repeat
could still satisfy canMerge with close autonomy off. Also closes the remaining
codecov/patch branch gaps: the linked-issue-hard-rule reason fallback and the
unlinkedIssueGuardrail minConfidence-only sparse override.
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. manual-review Gittensor contributor context

Development

Successfully merging this pull request may close these issues.

1 participant