diff --git a/auditor/index.ts b/auditor/index.ts index 05a5972..c3bd9c0 100644 --- a/auditor/index.ts +++ b/auditor/index.ts @@ -115,13 +115,28 @@ async function runCycle(state: State): Promise { console.log(`[auditor] skip PR #${pr.number} (SHA ${pr.head_sha.slice(0, 8)} already audited)`); continue; } - // Per-PR audit cap — once a PR has been audited MAX_AUDITS_PER_PR - // times, halt further audits until the operator manually clears - // audit_count_per_pr[] in state.json. Prevents runaway burn - // when each fix surfaces new findings. + // Per-head-SHA audit cap. Each new push gets MAX_AUDITS_PER_PR + // fresh attempts; the counter auto-resets when the head SHA + // changes. Operator only intervenes manually if a single SHA + // somehow needs MORE than the cap (rare — usually transient + // upstream errors clear themselves inside 3 attempts). + // + // Reset rule: if `last` exists (we've seen this PR before) AND + // pr.head_sha != last, that's a new push. Drop the counter. + // The dedup branch above already handles same-SHA → skip, so + // we only land here when the SHA actually moved. + if (last !== undefined && (state.audit_count_per_pr[prKey] ?? 0) > 0) { + const prior_count = state.audit_count_per_pr[prKey]; + console.log(`[auditor] PR #${pr.number} new head ${pr.head_sha.slice(0, 8)} (prior ${last.slice(0, 8)}, was ${prior_count}/${MAX_AUDITS_PER_PR}) — resetting cap counter`); + state.audit_count_per_pr[prKey] = 0; + } const auditedSoFar = state.audit_count_per_pr[prKey] ?? 0; if (MAX_AUDITS_PER_PR > 0 && auditedSoFar >= MAX_AUDITS_PER_PR) { - console.log(`[auditor] skip PR #${pr.number} (capped at ${auditedSoFar}/${MAX_AUDITS_PER_PR} audits — clear state.json audit_count_per_pr.${prKey} to resume)`); + // This branch only fires now if the SAME head SHA somehow + // burned MAX audits (transient upstream errors retried that + // many times). Operator can clear state.audit_count_per_pr. + // = 0 to force one more attempt; otherwise wait for next push. + console.log(`[auditor] skip PR #${pr.number} (same head ${pr.head_sha.slice(0, 8)} burned ${auditedSoFar}/${MAX_AUDITS_PER_PR} — push new code or clear state.json audit_count_per_pr.${prKey})`); state.cycles_skipped_capped += 1; continue; }