Skip to content

feat(github): store born-held checks while a preflighted apply changes the target - #942

Draft
aparajon wants to merge 1 commit into
armand/check-preflight-gatefrom
armand/check-plan-time-hold
Draft

feat(github): store born-held checks while a preflighted apply changes the target#942
aparajon wants to merge 1 commit into
armand/check-preflight-gatefrom
armand/check-plan-time-hold

Conversation

@aparajon

@aparajon aparajon commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Why this matters

The preflight fan-out holds every sibling check that exists when an apply starts — but a sibling that pushes a commit (or runs a manual plan) mid-apply gets a fresh plan against the mid-change schema, and a passing verdict from that plan would mint a fresh green check that sidesteps the hold entirely. This closes the last first-party gap in the merge gate: plan-time writes now know when the target is mid-apply. Stack 7/7, on top of #941.

What it does

  • upsertPlanCheckRecord — the single choke point every plan-time stored-check write funnels through (auto plans, manual plans, and the settle fan-out's re-plans) — consults HasActivePreflightedApplyOnTarget before storing a verdict that would pass. If a preflighted apply is active on the (environment, database type, database) target, the check is stored born held: action_required with the same apply_in_flight_on_target blocking reason the preflight fan-out writes, so the aggregate check and its release path are identical to any other hold.
  • Released like every other hold: the apply's settle fan-out re-plans held sibling checks against the settled schema. Nothing new to sweep or release.
  • Verdicts that already block (plan changes, plan errors, review-time drift) keep their more specific reason — the hold only replaces a would-be-green conclusion.
  • Fails closed on uncertainty: a storage error while checking for an active apply fails the check write; it never assumes the target is quiet.
  • The plan comment is untouched — the hold changes the stored verdict, not the plan UX.
  • Metric: schemabot.merge_gate.plan_time_holds_total — a sustained rate with no matching settle re-plans means holds are piling up on a target; check the merge gate processor's logs.
 plan (auto / manual / re-plan) on target T
        │
        ▼
 verdict would pass? ──no──► store the real (blocking) verdict
        │yes
 preflighted apply active on T?
        ├─ storage error ──► fail the write (fail closed)
        ├─ yes ──► store born held (apply_in_flight_on_target)
        │            └─ released by the apply's settle re-plan
        └─ no ───► store success

How it moves us toward the northstar

With this, every path that can produce a passing check during an apply window is closed at the source: existing checks are held by the preflight fan-out, and new checks are born held. The merge gate on a busy target is now airtight against first-party surfaces — what remains (admin overrides, unprotected branches) is outside the code host's checks and is handled by drift detection and, eventually, merge-time revalidation.

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) → this PR (plan-time holds). Merges bottom-up; each PR retargets to main as its base merges.

🤖 Generated with Claude Code

…s the target

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aparajon
aparajon force-pushed the armand/check-plan-time-hold branch from bcd6aa4 to 4d42d5f Compare August 5, 2026 15:14
@aparajon
aparajon force-pushed the armand/check-preflight-gate branch from aeae2bb to 44166f4 Compare August 5, 2026 15:14
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.

1 participant