feat(storage): merge gate request kinds and an apply-in-flight check hold - #939
feat(storage): merge gate request kinds and an apply-in-flight check hold#939aparajon wants to merge 3 commits into
Conversation
b054f62 to
fd47dab
Compare
4df18d8 to
8506ecb
Compare
…ck hold Check refresh requests gain a kind column distinguishing settle requests (re-plan sibling PR checks after an apply reaches a terminal state) from preflight requests (hold sibling PR checks before an apply starts engine work). The unique key becomes (apply_id, kind) so one apply can carry both. Storage adds ReopenForRetry to re-arm a terminally failed request, FindTerminalAppliesWithPreflightMissingSettle to find preflighted applies whose hold was never released, HasActivePreflightedApplyOnTarget to detect a live hold on a target, and MarkBlockedForApplyInFlight to conditionally flip a stored check to blocked without touching rows owned by an in-progress apply or a moved head SHA. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… holds Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fd47dab to
6bc0242
Compare
8506ecb to
d72df1f
Compare
The operator gate must be able to start an apply on the stored check holds alone: the holds are storage-only writes, while request completion additionally requires the code-host rendering (Check Run update and hold comment), which an outage can stall indefinitely. holds_recorded_at stamps the hold phase set-once and lease-guarded, and the re-arm sweep keeps a terminally failed render retrying while its apply is active. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🤖 Review findings - created by Kiran's code review agent - for pull/939, d72df1f. Verdict: 8 findings — 1 blocking (upgrade-path Blocking
Non-blocking
General suggestions
The one thing that could have broken, verifiedRewiring the existing settle outbox to be kind-scoped over an already-live table: EnsureSchema ALTERs Verified correct
This review was generated by Claude Code (claude-fable-5). |
Why this matters
When an apply starts changing a target schema, every other open PR holding a green check against that same (environment, database type, database) target is now holding a verdict that may no longer be true — and nothing stops a merge from landing on it while the apply is still running. The existing merge gate guardrail only reacts after an apply completes. Closing the window before and during an apply requires new durable primitives, which this PR adds at the storage layer. Stack 4/7, on top of #866.
What it does
kindcolumn tomerge_gate_requests, splitting the outbox into two request kinds:(apply_id, kind)so one apply can carry both requests through its lifecycle.holds_recorded_atstamp on the request: the preflight fan-out sets it once when every sibling hold is durably in place. It is a storage-only write — no code-host call in the path — so it lands even during a code-host outage, and it is the signal the operator gate starts the apply on (rather than full request completion, which includes the code-host rendering).MarkPreflightHoldsRecorded— lease-conditional, set-once stamp ofholds_recorded_at.ReopenForRetry— re-arms a terminally failed request so a gate can retry it.ReopenTerminalPreflightsForActiveApplies— re-arms terminally failed preflights whose apply is still active, so a hold's code-host rendering keeps retrying after the apply has started on the stored holds.FindTerminalAppliesWithPreflightMissingSettle— finds applies whose preflight held sibling checks but whose settle (the release) was never recorded.HasActivePreflightedApplyOnTarget— detects a live hold on a target so a settle doesn't prematurely release it.MarkBlockedForApplyInFlight— conditionally flips a stored check to blocked, refusing to touch rows owned by an in-progress apply or a moved head SHA (optimistic concurrency on the head SHA).How it moves us toward the northstar
Merging a PR should be safe exactly when its checks are green. This stack makes an in-flight apply on the same target visible in every sibling PR's checks, so git remains the interface and the check state is never a stale rendering of reality. This PR is pure storage; the processor fan-out and the operator gate build on it.
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