feat(github): hold sibling PR checks and comment when an apply preflights a target - #940
Draft
aparajon wants to merge 2 commits into
Draft
feat(github): hold sibling PR checks and comment when an apply preflights a target#940aparajon wants to merge 2 commits into
aparajon wants to merge 2 commits into
Conversation
This was referenced Aug 5, 2026
aparajon
force-pushed
the
armand/check-hold-storage
branch
from
August 5, 2026 14:03
4df18d8 to
8506ecb
Compare
aparajon
force-pushed
the
armand/check-hold-fanout
branch
from
August 5, 2026 14:03
8ab2a4c to
3973ef6
Compare
…ghts a target The check refresh processor consumes the new preflight request kind: before an apply changes a target schema, every open sibling PR with stored check state on that (environment, database type, database) target gets its check conditionally flipped to blocked (apply-in-flight) and a single explanatory PR comment, so a merge cannot land on a verdict the apply is about to invalidate. Checks owned by an in-progress apply and closed PRs are skipped; the flip is optimistic on the head SHA so a PR that moves mid-fan-out is never stomped, and the comment is idempotent via a hidden per-apply marker. Settle fan-outs release the holds by re-planning against the live schema, and defer without re-planning while a later preflighted apply is still active on the target. A release sweep backfills a settle for any terminal apply whose preflight held checks but whose settle was never recorded, so a hold can never outlive its apply. Consumer registration moves from handler construction to StartCheckRefreshProcessor: a registered consumer now means a processor is actually running to drain requests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fan-out Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
aparajon
force-pushed
the
armand/check-hold-storage
branch
from
August 5, 2026 15:14
8506ecb to
d72df1f
Compare
aparajon
force-pushed
the
armand/check-hold-fanout
branch
from
August 5, 2026 15:14
3973ef6 to
d30dc67
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this matters
A green check on a sibling PR is a promise that its plan still matches the target schema. The moment an apply starts changing that schema, the promise is stale — but today nothing on the PR says so, and the merge gate processor only knows how to re-plan after the apply finishes. This PR teaches the processor to consume preflight requests: hold every sibling PR's check action-required and explain why with a PR comment, before the apply's engine work begins. Stack 5/7, on top of #939.
What it does
fanOutCheckPreflight): for each open sibling PR with stored check state on the apply's target, conditionally flips the stored check to blocked (apply_in_flight_on_target), updates the aggregate Check Run, and posts one explanatory PR comment. Checks owned by an in-progress apply and closed PRs are skipped with logged outcomes. The flip is optimistic on the head SHA, so a PR that moves mid-fan-out is never stomped.RenderCheckHold): tells the PR's author what is changing, on which target, by whom, and what to do next (wait for the apply to settle; checks re-plan automatically). Idempotent via a hidden per-apply marker, so webhook redeliveries and retries never double-post.sweepPreflightedAppliesMissingSettle): settles are now the release valve for holds, so any apply that reaches a terminal state with a preflight but no settle (e.g. cancelled while queued, where no drive tail runs) gets a settle backfilled. A hold can never outlive its apply.StartMergeGateProcessor: a registered consumer now means "a processor is running and will drain requests", which the operator gate in the follow-up PR relies on.How it moves us toward the northstar
The PR's checks become an honest, live rendering of the target's state: "an apply is changing this schema right now" is visible where merges are decided, not buried in an operator log. The final PR in the stack turns this into a hard gate on apply start.
The chain: #867 (storage) → #868 (drive-tail recording) → #866 (settle re-plan processor) → #939 (request kinds + hold storage) → #940 (preflight hold fan-out) → #941 (apply-start gate) → #942 (plan-time holds). Merges bottom-up; each PR retargets to
mainas its base merges.🤖 Generated with Claude Code