Stop gated sync and closeout jobs from waiting for caller CI

Merged
UN
3d ago
+2014-1106

The reusable sync and closeout jobs held a shared runner while polling CI that needed the same runner pool, for up to two hours. They now dispatch caller workflows, request head-guarded squash auto-merge in App mode, report parked approval-required runs and exit.

  • Remove both PR/ancestry polling and branch-refresh loops. GitHub required checks and conversations govern landing; later schedules rebuild and retry after a base advance.
  • Check the repository auto-merge setting and protected base once before calling gh pr merge --auto --squash, since the CLI can merge immediately on an unprotected PR. Disabled settings, absent protection, unverifiable metadata and merge-request errors emit a reason and exit. Persistent configuration problems require maintainer attention.
  • Cap sync/closeout jobs at 60 minutes, their dispatch steps at five minutes, and sync alerts at 10 minutes. The Dependabot reusable job already has a timeout and only retries API calls; it never waits for caller runs.
  • Preserve publication/privacy gates, owned-PR identity, token scope and permission checks, App-only unattended landing, closeout attribution holds and auto-merge revocation. Update caller-template guidance and regenerate the changelog.

Validation:

  • node --test --test-concurrency=2 test/bot-pr-workflow.test.ts test/self-versioned-workflows.test.ts test/workflow-rule-names.test.ts: 117/117 passed; also passed via pinned pm test --run --progress with scratch tracker storage.
  • NPM_CONFIG_USERCONFIG=/dev/null node --test --test-concurrency=2 --test-name-pattern="earlier armed auto-merge|previous auto-merge is revoked|ambiguous deliveries open" test/closeout-workflow.test.ts: 11/11 passed.
  • Build, build:test, typecheck, lint and changelog:check passed. Tracker health with extensions disabled passed. Local extension-enabled health reports an existing 2026.11.4/2026.11.8 version skew; dependency pins are unchanged. CI certifies the full release gate.

Revert proof: in a disposable copy, restoring only the old dispatch blocks while retaining the new tests and job timeouts fails all 18 selected dispatch/fallback regressions. Removing only the new job timeouts fails the timeout contract. The fixed implementation passes. Detailed commands and outcomes are recorded in pm-github-fxhd, which remains open with its claim released.

Fixes #228

Summary by Sourcery

Stop gated sync and closeout workflows from waiting on caller CI by dispatching checks, validating protected auto-merge prerequisites, and exiting for GitHub or scheduled runs to complete landing.

New Features:

  • Dispatch caller workflows and hand off landing to GitHub’s protected squash auto-merge without waiting for caller CI.

Bug Fixes:

  • Prevent gated sync and closeout jobs from holding shared runners while polling competing caller workflows.
  • Prevent auto-merge from being requested when repository settings, base protection, or required CI checks cannot be verified.
  • Ensure approval-required run reporting failures remain informational and preserve valid closeout cleanup behavior.

Enhancements:

  • Replace PR polling, ancestry checks, and branch-refresh loops with scheduled rebuild-and-retry behavior.
  • Add bounded timeouts for reusable jobs, dispatch steps, and sync alerts.
  • Strengthen closeout auto-merge attribution and revocation handling to record only successfully armed requests.

Documentation:

  • Update workflow caller guidance, README documentation, and attribution documentation for non-waiting dispatch and protected auto-merge behavior.

Tests:

  • Add regression coverage for non-waiting dispatch, timeout contracts, auto-merge prerequisites and fallback reasons, parked-run reporting, and closeout cleanup semantics.

Chores:

  • Regenerate the changelog and record project validation evidence.

Summary by cubic

Stops the gated sync and closeout jobs from holding a shared runner while polling caller CI that competes for the same pool, for up to two hours. They now dispatch caller workflows, arm head-guarded squash auto-merge in both App and protected No-App modes, report parked approval-required runs as informational, and exit.

  • Removes PR/ancestry polling and branch-refresh loops; required checks and conversations govern landing, and later scheduled runs rebuild and retry after a base advance.
  • Verifies auto-merge is enabled, the base branch requires PR status checks, and the head is up to date with base — via branch protection or the rules API — before calling gh pr merge --auto --squash, since the CLI can merge immediately when no checks guard the branch. Disabled settings, missing check requirements, head staleness, unverifiable metadata, and merge errors emit a typed reason and exit.
  • Caps sync/closeout jobs at 60 minutes, dispatch steps at five minutes, and sync alerts at 10 minutes.
  • Records the closeout revocation flag only after an observed successful arm, so a failed or unavailable arm still revokes any request armed earlier in the same run.
  • Preserves publication/privacy gates, owned-PR identity, token scope and permission checks, and closeout attribution holds. The README and attribution guide now describe the dispatch step instead of the removed branch-refresh loop; caller templates describe native auto-merge in both token modes, and the changelog is updated.

Tests split the closeout suite into reusable decision, publication, and helper files and add regression coverage for non-waiting behavior, timeout contracts, auto-merge fallback reasons, protection and rules-based check and freshness verification, both token modes, parked-run reporting, and closeout cleanup semantics. Fixes #228.