You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The guarded merge gate can detect that a branch uses a merge queue, but it cannot distinguish an actively queued PR from removal, queue failure, or a confirmed merge. A successful enqueue command therefore cannot safely serve as merge completion.
Result
Adds the K1 read-only GitHub adapter contract for merge-queue lifecycle observations:
maps QUEUED, AWAITING_CHECKS, LOCKED, and MERGEABLE entries to an active queued observation;
maps UNMERGEABLE to failed, preserves RemovedFromMergeQueueEvent.reason, and reports merged only from GitHub's confirmed PR state;
binds active entries and removal events to the exact reviewed pull request and head;
rejects replaced heads, stale removals, partial or malformed GraphQL responses, missing terminal reasons, and ambiguous absence;
bounds the read with one deadline and preserves caller cancellation even when the runner returns or rejects after cancellation;
uses literal gh api graphql argv and recorded response fixtures for every state.
This leaves merge queues blocked in the existing runner. K2 owns persisted lifecycle/retry guards and K3 owns enqueue/polling/UI integration and the remaining #24 race acceptance.
Failing before: the initial 11 focused tests failed because inspectQueue did not exist; later review regressions reproduced partial records, malformed merged timelines, late cancellation, generic abort errors, mismatched entry heads, and stale removal events.
npx vitest run test/merge.test.ts — 73 passed.
npm test — 12 files, 264 tests passed.
npm run typecheck — passed.
git diff --check — passed.
Two required CI runs passed on the exact head; CI includes typecheck, unit/integration, and 43 browser tests.
The exact GraphQL query succeeded against GitHub's live schema. Live enum introspection confirmed the five supported queue-entry states.
AGENTS.md contains the required reusable review lesson.
No overlap with active Lane D or E PRs.
K2/K3 remain blocked on their documented runner/web ownership handoffs.
Review record
Round 1: required all requested GraphQL fields before terminal returns; added omission regressions. Finding fixed, replied to, and resolved.
Round 2: validated timeline nodes before MERGED and discarded responses that arrive after cancellation. Both concrete concerns fixed; thread replied to and resolved.
Round 3: preserved the caller's cancellation reason when the runner rejects generically. Summary finding fixed with regression.
Round 4: added an exact literal-argv assertion for the GraphQL query and typed variables. No inline findings.
Round 5: bound queue entries and removal events to the reviewed PR/head and rejected stale removal history. Finding fixed, replied to, and resolved.
Round 6: Findings: None. Declined the summary-only MERGING suggestion because GitHub's live MergeQueueEntryState schema does not contain that value; unknown future states continue to fail closed.
No findings were otherwise declined. All review threads are resolved. The broadly reusable lesson is now explicit in AGENTS.md: validate every requested safety-critical field before any early return and distinguish omission from API-defined null. Existing stable-identity and async-cancellation rules cover the remaining fixes without duplicate rules.
The combined abort signal is only checked before the GraphQL read and in the rejection path. If the underlying run resolves after the timeout or caller cancellation (for example, a runner that does not honor AbortSignal), this code continues through the response mapping and can report a successful observation after cancellation. Check signal.aborted immediately after the awaited read and rethrow its reason before validating or returning the response.
Preserve caller cancellation reason when runner rejects
github/merge.ts:304
When the supplied runner rejects in response to the composite signal—as the default execFile-based runner does—the catch rethrows that runner error instead of options.signal.reason; the current test only passes because its fake runner explicitly rejects with the reason. A shutdown/caller cancellation can therefore surface a generic AbortError rather than the actionable cancellation reason. Handle caller cancellation before the timeout check and rethrow options.signal.reason when it is aborted.
Avoid attributing stale removal events to the current PR head
github/merge.ts:301
When mergeQueueEntry is absent, this treats the last removal event in the 20-item history as proof that the reviewed head was removed. A PR can have an old removal for a previous head and then be updated to the current reviewed head without ever being queued, which would be incorrectly reported as removed. Query and validate a stable entry/head identity on the queue events (or fail closed when it is unavailable) before returning this terminal state.
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
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.
Problem
The guarded merge gate can detect that a branch uses a merge queue, but it cannot distinguish an actively queued PR from removal, queue failure, or a confirmed merge. A successful enqueue command therefore cannot safely serve as merge completion.
Result
Adds the K1 read-only GitHub adapter contract for merge-queue lifecycle observations:
QUEUED,AWAITING_CHECKS,LOCKED, andMERGEABLEentries to an activequeuedobservation;UNMERGEABLEtofailed, preservesRemovedFromMergeQueueEvent.reason, and reportsmergedonly from GitHub's confirmed PR state;gh api graphqlargv and recorded response fixtures for every state.This leaves merge queues blocked in the existing runner. K2 owns persisted lifecycle/retry guards and K3 owns enqueue/polling/UI integration and the remaining #24 race acceptance.
Closes no issue; contributes K1 to #24.
Validation
Exact pushed head:
e1001abeaa89a59f056922b3198792423a24fecbinspectQueuedid not exist; later review regressions reproduced partial records, malformed merged timelines, late cancellation, generic abort errors, mismatched entry heads, and stale removal events.npx vitest run test/merge.test.ts— 73 passed.npm test— 12 files, 264 tests passed.npm run typecheck— passed.git diff --check— passed.Ownership and dependencies
b181d152ed522cf0ea6179d0ab7f0b45b00a6a4fgithub/merge.ts,test/merge.test.tsAGENTS.mdcontains the required reusable review lesson.Review record
MERGEDand discarded responses that arrive after cancellation. Both concrete concerns fixed; thread replied to and resolved.Findings: None. Declined the summary-onlyMERGINGsuggestion because GitHub's liveMergeQueueEntryStateschema does not contain that value; unknown future states continue to fail closed.No findings were otherwise declined. All review threads are resolved. The broadly reusable lesson is now explicit in
AGENTS.md: validate every requested safety-critical field before any early return and distinguish omission from API-definednull. Existing stable-identity and async-cancellation rules cover the remaining fixes without duplicate rules.