Skip to content

fix(github): re-open the merge gate when an apply terminalizes on a superseded commit - #969

Draft
aparajon wants to merge 2 commits into
mainfrom
armand/stale-gate-replan
Draft

fix(github): re-open the merge gate when an apply terminalizes on a superseded commit#969
aparajon wants to merge 2 commits into
mainfrom
armand/stale-gate-replan

Conversation

@aparajon

@aparajon aparajon commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Why this matters

An apply that finishes after its PR has moved on leaves its stored check row pinned to the commit it ran against. That row folds into the aggregate as a blocking placeholder, and nothing re-keys it: the push that moved the head left the row alone because an apply still owned it, and folding again on the superseded commit only republishes the same placeholder. The gate stays shut with no operator command that can open it.

commit A ── apply starts ──────────────── apply terminal
   │                                          │
   └── push ──▶ commit B (PR head)            └── fold on A ──▶ placeholder ──▶ re-fold on A ──▶ …

What it does

  • The apply's own terminal refresh re-plans on the PR's current commit, so the row is re-keyed and the gate re-opens without human input.
  • The re-plan stands down when another apply on the same PR is still in flight. Replaying the plan flow there could replace an apply-owned merge block with a fresh passing plan, so the gate stays shut — the safe direction.
  • A row already keyed to the current commit is not superseded; the ordinary fold owns it and the re-plan does not run.
  • The placeholder summary names the command that records results for the commit the aggregate is published on, scoped to the environment whose gate is held open.

🤖 Generated with Claude Code

…uperseded commit

A stored check row recorded for a commit the PR has moved past contributes a
blocking placeholder to the aggregate, because results computed for one commit
say nothing about another. Nothing re-keys that row on its own: the push that
moved the head declined to overwrite it while an apply owned it, and the fold
that follows the apply reaching a terminal state re-publishes the same
placeholder over the same stale row. A plan on the current commit is the only
action that records results for it.

The terminal refresh now re-plans on the PR's current commit instead of folding
on the superseded one. It refuses while any apply on the PR is non-terminal, so
a started apply stays authoritative for its PR's check state, and refuses on
storage uncertainty for the same reason; both refusals leave the gate blocking.
A closed PR is left to close-time cleanup.

The blocking placeholder itself now names its exit — the plan command that
records results for the commit — and logs a warning with a metric when no apply
is running on any commit, which is the shape only an operator can clear.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 7, 2026 20:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a merge-gate deadlock where a terminal apply can leave its stored check row keyed to a superseded commit, causing the aggregate check to remain blocked indefinitely even though the PR head has advanced. It introduces an automatic re-plan on the PR’s current head when this condition is detected, and improves aggregate messaging/telemetry to make the “stale rows with no running work” condition actionable for operators.

Changes:

  • Add a terminal-apply hook that detects a superseded stored check head and triggers an auto-plan on the PR’s current head, while refusing to run if any apply on the PR is still non-terminal.
  • Improve aggregate Check Run title/summary when stale rows block the latest commit, including explicit operator command guidance and additional warning telemetry.
  • Add integration tests covering the stale-gate replan path and its safety deferrals (in-flight apply; already-current head).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/webhook/stale_gate_replan.go Adds the terminal-apply superseded-head detection and auto-plan replan mechanism.
pkg/webhook/stale_gate_replan_integration_test.go Integration coverage for re-keying behavior and safety stand-down conditions.
pkg/webhook/handler.go Hooks the replan into the terminal-apply refresh path before folding the aggregate.
pkg/webhook/check_publisher.go Enhances aggregate placeholder summary/title and adds warning telemetry for “stale + no running work”.
pkg/webhook/check_aggregate.go Updates placeholder title, adds summary helper, and introduces an “any in progress on any commit” helper.
pkg/webhook/check_aggregate_test.go Adds tests for the new helper and summary formatting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/webhook/stale_gate_replan.go Outdated
The superseded-head re-plan recorded a success before the plan dispatch ran
and dropped the error the dispatch returned. A re-plan that fails leaves the
merge gate blocked on the superseded commit, which is the condition the metric
exists to surface, so it read as healthy exactly when it was not.

The metric now records after the dispatch and takes its status from the
outcome, and a failed re-plan logs at error level with the head sha the gate
is stuck on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants