Repository navigation
fix(land): keep a PR at the gate's own base merge queued - #378
Merged
Merged
Conversation
#342 was parked for the fixer right after the gate pushed its own merge of the tested base: GitHub already showed that merge as the head, but still called it conflicting from the pin's stale mergeability, and mergePinned returned merge_conflict at once. That merge holds the base it was checked on, so it cannot conflict with it. A conflict GitHub reports on the gate's freshly pushed merge is now retried as unsettled mergeability; if it persists, the round throws and the next one rebuilds the queue on the base as it then is. The settle retries grow from 3.5 s to 15.5 s of backoff. The fixer then handed #342 back as "head moved", since collection took the gate's merge for a writer's commit. Collection now recognizes the gate's privately recorded merge for that queue entry, as resolvePreparedQueue does: a requeue pins the PR at it, a handback keeps the fixer's diagnosis, and a fix, built on the pin, replaces it with a lease on it, since building on it would revert the newer base it merged. A forged copy or a writer's commit still hands back as a moved head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
kixelated
enabled auto-merge (squash)
November 1, 2026 23:31
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.
Summary
moq-dev/quest#342 was parked right after the gate pushed its own base merge, then handed back by the fixer as "head moved". Both steps were gate bugs; this fixes both.
Root cause (from the host's state, journal, and batch log, 2026-11-01)
3b4e77c2, and the gate pushedaa87d974to feat(gate): admit a lone command on a host loaded by other work #342's branch at 22:51:35Z.aa87d974isquest land: merge tested base, with parents pin72750ef7and base3b4e77c2, recorded inhead-342-aa87d97….json.GitHub refused /repos/moq-dev/quest/pulls/342: Pull Request has merge conflicts(end ofbatch-1793572781096-323.log). The daemon then loggedparked 342. In that build, onlymerge_conflictparks;head_movedejects. So GitHub already showedaa87d974as the head but called it conflicting, using mergeability left over from the pin, which does conflict with3b4e77c2without the quest driver. feat(gate): admit a lone command on a host loaded by other work #342 now reportsmergeable: trueataa87d974, so the report was stale.merge_conflictat once in this case, so the bug was live.72750ef7. On collection, the checkcurrent !== entry.head && !(published && current === head)treated the gate's ownaa87d974as a writer's commit and handed feat(gate): admit a lone command on a host loaded by other work #342 back.Changes
mergePinned(src/cli/land-serve.ts): if GitHub calls the gate's freshly pushed merge conflicting (mergeable: false,dirty, or a "merge conflicts" refusal), the gate treats it as unsettled mergeability and retries. That merge holds the base it was tested on, so it cannot conflict with it. Only a base that moved since can make it conflict; then the retries run out, the round throws, and the next round rebuilds on that base. A conflict on a head the gate did not just push still parks as before. The settle backoff grows from 3.5 s to 15.5 s (5 retries), since feat(gate): admit a lone command on a host loaded by other work #342's refusal came 5 s after the push.collectJob(src/cli/land-fixer.ts): recognizes the gate's privately recorded merge for this queue entry, usingisPrepared(now exported), the same checkresolvePreparedQueueuses. The record must match the same pin, the sameenabledAt, parents pin + base, the tested tree, and the bot author. Author text alone is never trusted. When the PR stands at that merge:requeue: re-pinned at the gate's merge, keeping the pick's place through the attempt record.fixed: the fix descends from the pin, so it replaces the gate's merge with a lease on that merge, the wayprepareHeadalready replaces its own earlier merge. Building on that merge would revert the newer base it merged. If GitHub refuses that push, the handback carries noquest land applyresolution: that resolution is built from the pin, andapplyrefuses a PR whose head moved.handback: hands back with the fixer's own diagnosis, not "head moved".push(src/cli/land-head.ts): asks for workflow write when the pushed head changes workflows relative to either the head it builds on or the head it replaces.Choices for review
requeueat the gate's merge re-pins it there, as the brief asked, instead of leaving the pin onapprovedand relying on the private record. That records on GitHub which head will land, and it no longer depends on the record surviving.fixedreplaces the gate's merge (force-with-lease on it) instead of rebuilding the fix on top of it, for the revert reason above. The next batch re-merges the base anyway.Tests
New regression tests in
test/land.test.ts, each reproducing a step of the #342 sequence:mergeable: falseordirty, is retried and lands.The 6 behavior tests fail on
origin/main. The 2 safety tests pass both before and after. The "a refused second merge (merge_conflict)" and "classifies a refused merge" tests were updated for the new retry behavior.Local checks:
just checkpasses, andtest/land.test.ts,test/landed.test.ts, andtest/land-fixer-diagnostics.test.tspass, 187/187, withCLAUDE_CONFIG_DIRunset.Follow-ups
head-<n>-<sha>.json) behind until the PR closes. This is harmless (a new pick has a newenabledAt) and was true before this change.aa87d974.Review
quest review), gpt-6.1-sol, medium effort.61933a9204e913ca4c0e430e24c989a2f20908b6againstorigin/main(97ed0ff8).🤖 Generated with Claude Code
(Written by Claude Opus 5.5)