mirror of
https://github.com/awesome-dsh-plugin/awesome-dsh-plugin.git
synced 2026-09-28 05:13:14 +08:00
Stop telling authors to resubmit over the age bar; let regate reach them
The age check is the only gate failure that time alone clears, and regate.yml already re-runs on exactly this wording every six hours. Saying 'resubmit in about Nh' sent people off to close and reopen, or to force-push an empty commit, to buy something they already had. 15 of the 32 currently failing gates are this message and nothing else. Editing this file also resets regate's gateChangedAt, which marks every open verdict stale at once — ~140 of them. Those shared one queue with the PRs that are genuinely blocked, sorted by PR number, and stale entries carry old numbers while aged-in ones carry new: the whole backlog would have gone ahead of the submissions waiting on a clock, turning a six-hour wait into two days, because a maintainer edited a comment. So the queue is now three tiers. 'blocking' (never gated / failed open / aged in) means nothing has vouched for the PR or its author is stuck behind a clock. 'revalidate' means the verdict is probably still right and is being re-asked out of diligence. Diligence yields.
This commit is contained in:
@@ -81,10 +81,10 @@ jobs:
|
||||
|
||||
const prs = await github.paginate(github.rest.pulls.list, { owner, repo, state: 'open', per_page: 100 })
|
||||
// Oldest first. pulls.list answers newest-first, and only
|
||||
// `speculative` was ever sorted (below) — so `urgent` inherited that
|
||||
// order and MAX_RERUNS truncated its tail, which is exactly where
|
||||
// the pull requests blocked longest live. #2146 sat on a "resubmit
|
||||
// in about 24h" verdict for 119 hours: every pass re-ran twenty
|
||||
// `speculative` was ever sorted (below) — so the blocked list
|
||||
// inherited that order and MAX_RERUNS truncated its tail, which is
|
||||
// exactly where the pull requests blocked longest live. #2146 sat
|
||||
// on an "aged in" verdict for 119 hours: every pass re-ran twenty
|
||||
// newer submissions and stopped before reaching it. Twenty-two of
|
||||
// them were in that state on 2026-08-25, the oldest five days deep.
|
||||
prs.sort((a, b) => a.number - b.number)
|
||||
@@ -101,7 +101,24 @@ jobs:
|
||||
}
|
||||
// Collected first, re-run second, so the cheap-and-urgent reasons
|
||||
// are never crowded out by the speculative one (see PASS_STALE).
|
||||
const urgent = []
|
||||
//
|
||||
// Three tiers, not two. `blocking` and `revalidate` used to share
|
||||
// one list sorted by PR number, which is fine until the gate file
|
||||
// changes: then EVERY open verdict becomes stale at once, ~140 of
|
||||
// them, and at 20 per pass they occupy the queue for two days.
|
||||
// Stale entries are old PR numbers and aged-in ones are new, so
|
||||
// ascending order put the whole backlog ahead of the submissions
|
||||
// that are actually blocked — a plugin waiting only for its
|
||||
// repository to turn one day old would wait two days instead of
|
||||
// six hours, and the trigger would be a maintainer editing a
|
||||
// comment in the gate script.
|
||||
//
|
||||
// The two are not equally urgent. `blocking` means nothing has
|
||||
// vouched for this PR or the author is stuck behind a clock;
|
||||
// `revalidate` means the verdict is probably still right and is
|
||||
// being re-asked out of diligence. Diligence yields.
|
||||
const blocking = []
|
||||
const revalidate = []
|
||||
const speculative = []
|
||||
let requeued = 0
|
||||
for (const pr of prs) {
|
||||
@@ -110,7 +127,7 @@ jobs:
|
||||
// and each iteration costs a listForRef. Stopping here makes the
|
||||
// sweep cheaper than the version that scanned every open PR to
|
||||
// build a list it was about to truncate.
|
||||
if (urgent.length >= MAX) break
|
||||
if (blocking.length >= MAX) break
|
||||
|
||||
let gate, check
|
||||
try {
|
||||
@@ -169,15 +186,19 @@ jobs:
|
||||
// human re-check, which is not a control.
|
||||
const passStale = gate?.conclusion === 'success' && ranAt && (Date.now() - ranAt) > PASS_STALE_MS
|
||||
|
||||
if (never || stale || aged || unverified) urgent.push([pr, runId, never ? 'never gated' : stale ? 'verdict predates the current gate' : aged ? 'aged in' : 'gate failed open (neutral) — never verified'])
|
||||
if (never) blocking.push([pr, runId, 'never gated'])
|
||||
else if (unverified) blocking.push([pr, runId, 'gate failed open (neutral) — never verified'])
|
||||
else if (aged) blocking.push([pr, runId, 'aged in'])
|
||||
else if (stale) revalidate.push([pr, runId, 'verdict predates the current gate'])
|
||||
else if (passStale) speculative.push([pr, runId, `passing verdict is ${Math.round((Date.now() - ranAt) / 3600000)}h old`])
|
||||
}
|
||||
|
||||
// Urgent first: those PRs are blocked on the re-run, while a stale
|
||||
// pass is only *possibly* wrong. Whatever budget is left goes to
|
||||
// re-checking greens, oldest verdict first.
|
||||
// Blocked first: those PRs cannot proceed without the re-run. Then
|
||||
// re-validation of verdicts issued by gate code that no longer
|
||||
// exists, then re-checking greens — both oldest verdict first.
|
||||
revalidate.sort((a, b) => a[0].number - b[0].number)
|
||||
speculative.sort((a, b) => a[0].number - b[0].number)
|
||||
for (const [pr, runId, why] of [...urgent, ...speculative]) {
|
||||
for (const [pr, runId, why] of [...blocking, ...revalidate, ...speculative]) {
|
||||
if (requeued >= MAX) { core.info(`hit MAX_RERUNS=${MAX}, stopping`); break }
|
||||
core.info(`#${pr.number}: ${why}`)
|
||||
try {
|
||||
@@ -189,7 +210,7 @@ jobs:
|
||||
core.info(`#${pr.number}: could not re-run (${e.status})`)
|
||||
}
|
||||
}
|
||||
core.info(`re-queued ${requeued} pull request(s) (${urgent.length} urgent, ${speculative.length} stale-pass candidates)`)
|
||||
core.info(`re-queued ${requeued} pull request(s) (${blocking.length} blocked, ${revalidate.length} to re-validate, ${speculative.length} stale-pass candidates)`)
|
||||
|
||||
} catch (e) {
|
||||
if (e.status === 403 || e.status === 429) core.warning(`API quota busy — skipping this pass (${e.status})`)
|
||||
|
||||
@@ -399,7 +399,14 @@ async function check(entry) {
|
||||
const ageDays = (Date.now() - new Date(meta.body.created_at).getTime()) / 86400000
|
||||
if (ageDays < MIN_AGE_DAYS) {
|
||||
const hours = Math.ceil((MIN_AGE_DAYS - ageDays) * 24)
|
||||
problems.push(`repository is ${ageDays.toFixed(1)} days old (needs ${MIN_AGE_DAYS}) — resubmit in about ${hours}h, nothing is held against a resubmission`)
|
||||
// Do NOT tell people to resubmit. This is the only failure that time
|
||||
// alone clears, and `regate.yml` re-runs the gate on exactly this
|
||||
// wording every six hours (its `aged` rule matches /days old/), so the
|
||||
// verdict flips on its own. The old text said "resubmit in about Nh",
|
||||
// which sent authors off to close and reopen, or to force-push an empty
|
||||
// commit, to buy something they already had. Leave the pull request
|
||||
// alone and it goes green by itself.
|
||||
problems.push(`repository is ${ageDays.toFixed(1)} days old (needs ${MIN_AGE_DAYS}) — nothing to do: this check re-runs by itself and should clear in about ${hours}h. No need to resubmit, push, or close and reopen; the age bar is the only thing failing here.`)
|
||||
}
|
||||
}
|
||||
return { problems, unverified }
|
||||
|
||||
Reference in New Issue
Block a user