@@ -470,6 +470,8 @@ function waitForPRMerge(repoDir, repo, headBranch, baseBranch, dryRun, options =
470470 const startTime = Date . now ( ) ;
471471 let finalMergedAt = '' ;
472472 let sawAnyChecks = false ;
473+ let blockedNoChecksCycles = 0 ;
474+ const blockedNoChecksLimit = 8 ; // ~2 minutes at 15s polling
473475
474476 const isTransientRuleViolation = ( err ) => {
475477 const text = [
@@ -518,6 +520,12 @@ function waitForPRMerge(repoDir, repo, headBranch, baseBranch, dryRun, options =
518520 ` PR #${ prNumber } : state=${ state } , mergeState=${ mergeStateStatus } , review=${ reviewDecision } , pendingChecks=${ pendingChecks } , failingChecks=${ failingChecks } `
519521 ) ;
520522
523+ if ( mergeStateStatus === 'BLOCKED' && checks . length === 0 && pendingChecks === 0 ) {
524+ blockedNoChecksCycles += 1 ;
525+ } else {
526+ blockedNoChecksCycles = 0 ;
527+ }
528+
521529 if ( mergedAt ) {
522530 finalMergedAt = mergedAt ;
523531 break ;
@@ -531,6 +539,13 @@ function waitForPRMerge(repoDir, repo, headBranch, baseBranch, dryRun, options =
531539 throw new Error ( `PR #${ prNumber } has failing required checks.` ) ;
532540 }
533541
542+ if ( blockedNoChecksCycles >= blockedNoChecksLimit ) {
543+ throw new Error (
544+ `PR #${ prNumber } stayed BLOCKED with no status checks for ${ ( blockedNoChecksCycles * pollInterval ) / 1000 } s. ` +
545+ `This usually means required checks are configured but not running for this PR (workflow trigger/path filter/permissions mismatch).`
546+ ) ;
547+ }
548+
534549 // Retry requesting auto-merge once checks have started appearing.
535550 if ( ! autoMergeRequested && ( pendingChecks > 0 || sawAnyChecks ) ) {
536551 try {
0 commit comments