Skip to content

Smart CI planner exhausts merge-ref retries before GitHub updates a PR head #3316

Description

@Chris0Jeky

Summary

The pull_request_target Smart CI planner can fail closed on a valid same-repository PR because GitHub's synthetic refs/pull/<n>/merge still names the previous head when the workflow begins. resolve-merge-ref.mjs retries three times, but the merge ref is sometimes updated only after that window.

This is distinct from an ambiguous or malicious binding: the PR API already reports the intended head, changed-file count and eventually a current merge commit; the short-lived merge ref simply lags the event.

Exact evidence

PR #3315, base 307c3b8b50bec1cb0bfaea3e570a942bcb1d4451, head 07c59d655fc4b225ab7c1c85c7d5f0e269601ce2:

  • Smart CI run 35540674080: all three merge-ref attempts reported head mismatch; planner emitted the full R4 error plan and the Required Gate failed.
  • After the PR became mergeable: true with a current merge_commit_sha, a close/reopen generated fresh run 35540751034; all three attempts again reported head mismatch before the synthetic ref caught up.
  • Closing/reopening again generated ordinary exact-head CI/Extended runs successfully, while Smart CI repeated the early merge-ref resolution race. The product branch and changed-file API metadata were stable throughout.

The fail-closed rule is correct. The defect is the observation window and event timing: a valid merge ref becomes available after the planner has already committed an error receipt.

Expected contract

  • Keep requiring merge SHA, tree SHA, observed first parent/base tip, and head SHA from the same fetched merge ref.
  • Treat a mismatching-but-well-formed merge ref as a bounded transient until an explicit deadline rather than three short fixed attempts.
  • Poll the PR's current merge_commit_sha/mergeability and fetch that exact ref until it binds to the event head, or fail closed at the deadline with the last observed identities.
  • Superseded workflow cancellation must end the poll promptly.
  • Never fall back to constructing or trusting a local merge from untrusted head code.
  • Receipt diagnostics must distinguish merge-ref-not-yet-current from a stable wrong-head/wrong-base binding.

Acceptance

  • Deterministic resolver tests cover: previous-head ref that becomes current within the deadline; ref that never becomes current; base movement; superseded/cancelled run; and a genuinely wrong tree/parent.
  • Retry timing is configurable and bounded, with no blind sleeps after the run is obsolete.
  • A live draft/open/synchronize/reopen rehearsal produces a bound plan without manual close/reopen loops or code-only nudge commits.
  • Stable mismatch still yields the current full R4 error plan and red gate.

Refs #2326, #2327, #2508. Found while qualifying #3315; product CI remains independently authoritative for that draft.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Priority IIThe active direction's next tranche: wedge capabilities, significant defects, near-term hardening.bugSomething isn't workingciCI/CD pipeline, workflow, and build infrastructure changes.testingTest coverage, harnesses, regression prevention, and verification pipeline work.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions