Skip to content

fix(review): a dirty-base PR with missing required CI context defers forever instead of reaching the close disposition #7556

Description

@JSONbored

prReadyForReview (src/queue/processors.ts) defers review forever for a PR with a missing
required CI context, even when the PR already has an independently terminal, CI-agnostic signal:
a dirty (conflicting) base.

Root cause

In the ci?.hasPending branch (~processors.ts:3550-3651), the staleness cap is computed correctly:

const deferCapMs = ci.hasMissingRequiredContext ? MISSING_REQUIRED_CONTEXT_DEFER_MS : STUCK_CI_DEFER_MS;

But the ci.hasMissingRequiredContext branch right below it ignores that cap entirely and always
returns false (defer):

if (ci.hasMissingRequiredContext) {
  await recordAuditEvent(env, {
    ...
    detail: "Required CI context is still missing — review deferred instead of publishing a passing gate before expected CI reports",
    ...
  }).catch(() => undefined);
  return false;
}

Its sibling "generic stuck CI" branch immediately below (~3585-3649) has a proper
finalize-past-cap + per-head-SHA once-only guard (CI_STUCK_FINALIZE_GUARD_EVENT_TYPE) so a
permanently-stuck PR still eventually surfaces. The hasMissingRequiredContext branch has no such
escalation — it defers unconditionally, every pass, forever.

For most missing-required-context PRs that's the deliberate, correct behavior (see the two existing
tests keeps deferring a missing-required-context PR ... (#selfhost-ci-deferral-staleness) in
test/unit/queue.test.ts) — we must not publish a possibly-premature passing gate before an
expected required check reports. But it's wrong for a PR whose base is already dirty: the
disposition planner (src/settings/agent-actions.ts) computes
isConflict = input.pr.mergeableState === "dirty" and lets that close a contributor PR
regardless of CI state (willClose = ... || isConflict, and pendingCiMayStillCloseForTerminalReason
explicitly allows a terminal conflict close to proceed even while CI is still pending). A dirty-base
PR can never acquire the missing required context by waiting, so today it just sits open,
unlabeled, with no gate check-run, indefinitely.

Observed live: #7537mergeable: CONFLICTING, mergeStateStatus: DIRTY,
no labels, no LoopOver gate check-run. audit_events shows the same
"Required CI context is still missing — review deferred..." detail repeating every ~4 minutes for
40+ minutes with no resolution, matching this code path exactly.

Fix: in the hasMissingRequiredContext branch, skip the indefinite defer when the PR's live
mergeable state is already dirty — fall through to the existing finalize-past-cap + per-SHA-guard
logic so the pipeline reaches the disposition planner, which already knows how to close it. Every
other missing-required-context PR keeps deferring exactly as before (regression-tested).

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.maintainer-onlyOwner-only work — yields no Gittensor points.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions