Skip to content

feat(merge): close quest merge --land's gaps - #347

Merged
moq-bot[bot] merged 10 commits into
mainfrom
quest/m0/helpers/merge-land
Nov 2, 2026
Merged

moq-bot[bot] merged 10 commits into
mainfrom
quest/m0/helpers/merge-land

Conversation

@kixelated

@kixelated kixelated commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Closes the remaining gaps in quest merge --land that the quest quest/m0/helpers/merge-land.md lists, and deletes that quest along with its last link (in quest/m0/queue-watcher/pick.md's Related section).

Since moq-dev/quest#326, quest merge takes no label and no token. So this PR no longer releases a quest:merge label after a direct merge, and it no longer keeps a caller's token valid across refusals. See the Design change: comment.

Changes

  • Merge method. On an ungated base without a merge queue, --land now reads the repository's allowed methods:
    • It uses the method --squash or --rebase names, and refuses one the repository disallows.
    • Without a flag, it uses the only allowed method, or else a merge commit when that is allowed.
    • It refuses when merge commits are off and both squash and rebase are allowed.
    • --direct follows the same rule.
    • If the token can't see the settings, the old behavior stays and GitHub decides.
    • A gated base still squashes, and a merge queue still applies its own method. Each now warns only about a method you named, not about the default.
  • Outside a checkout. A PR URL never touched git. A bare PR number outside a checkout now exits 2 with <root> is not a checkout with an origin remote: … pass the full GitHub PR URL, or run inside a checkout or name one with --root. Before, it printed git's own fatal: not a git repository error.
  • Auto-merge carry-over.
    • quest status adds the head auto-merge was enabled on to the end of the auto-merge line, and --json adds it as autoMerge.head.
    • That head comes from the Quest-Land-Head pin when there is one. Otherwise it is the last update to the head branch before auto-merge was enabled, read from the head repository's activity. Updates are pushes, force pushes, branch creation, and merges into the branch (pr_merge, merge_queue_merge).
    • It prints - when it can't be told: GitHub hasn't listed the current head's update yet, an update happened in the same second auto-merge was enabled, or the head repository is gone. A token that may not read the head repository's activity also gets -, with a warning, and the rest of the status still prints.
    • quest wait prints auto-merge:moved once per head while auto-merge stays on for a head other than the current one. The actor is the account that enabled it, and the URL is <pr>/commits/<enabled head>.
    • The iterate skill now says to disable auto-merge with gh pr merge <pr> --disable-auto before any push.
  • --help, the README, and the merge skill describe the new behavior.

Choices made without asking

  • Enabled head from branch activity, not a commit-body pin. GitHub doesn't expose the head an auto-merge request was enabled on. Pinning Quest-Land-Head into every auto-merge commit body would replace the squash or merge commit message that ungated repositories get today. Reading it from the head branch's activity changes nothing GitHub merges. The cost is a - while GitHub's activity listing lags, which takes seconds to minutes.
  • No method picked when merge commits are off and two methods remain. The quest's plan says "use the only one allowed, or the one the flag names". When neither applies, --land refuses and asks for a flag. The Worker's landPullRequest, by contrast, falls back to squash; I left the Worker unchanged.
  • The disable-before-push rule lives in the iterate skill. The quest names the merge skill, but the merge skill never pushes. /quest-iterate is the skill that pushes, and in moq-dev/moq#6985 the push came from an iterate session.
  • Compatibility with moq-dev/quest#385. That PR moves a merge-queue base to an early pick return in land. Method selection here runs only when !snapshot.queue, so it doesn't touch the queue path. Whichever of the two lands second resolves the conflict in land the same way in either order:

Production observation: moq-dev/moq#6985 ejected as head_moved

This PR doesn't fix this one, because the fix is already on main. On 2026-11-01 the re-pick at a86499b ran at 05:39:51Z. The PR timeline shows no auto_merge_disabled or auto_squash_enabled event at that time. That matches quest before moq-dev/quest#306, which asked GitHub to enable auto-merge again. GitHub kept the existing request and its Quest-Land-Head: 5550df1… body. moq-dev/moq's flake.lock pins quest at 1ef2ca7 (2026-10-30), which predates #306. Since #306, enqueue disables and re-enables the request, so the pin names the new head. With this PR, quest status and quest wait would also have shown the stale pin before the gate ejected it.

Suggested follow-ups

  • Bump moq-dev/moq's quest flake input to a revision that includes moq-dev/quest#306, so re-picks there re-pin instead of being ejected as head_moved.
  • quest wait's setup (src/cli/wait.ts:240, which predates this PR) also reads only push, force_push, and branch_creation activity. When the current head came from a merge into the head branch (pr_merge or merge_queue_merge), a wait from that head can fail with cannot resolve push time, and the merge never prints as an event.

Validation

  • just check passes.
  • just test passes, run with CLAUDE_CONFIG_DIR unset.
  • New tests cover:
    • method selection and refusals, including --direct;
    • the enabled head from a pin, paged activity, merges into the head branch, lag, and same-second ambiguity;
    • a forbidden activity listing;
    • auto-merge:moved reported once per head, and not when auto-merge is on the current head;
    • the bare-number error outside a checkout.

Review

  • Reviewer: Codex (quest review --new, restarted after the design change), gpt-6.1-sol at medium effort, session 01a199ec-4087-7b53-bbff-1adb6e173f9c.
  • Round 1 at 8d7c22e6 reported one finding: the enabled head ignored pr_merge and merge_queue_merge activity, so a head reached by a merge into the branch read as unknown or as an older push. Fixed in b8dfdbf3, with a test.
  • Round 2 at b8dfdbf3: no findings.
  • Head 6596bb317e64ec22235779031c2bf2984ea09ffc: review skipped as too trivial. Since b8dfdbf3 it has a conflict-free merge of origin/main (0db65d93, exempt) and 6596bb31, which only removes quest/m0/helpers/submodule-links.md's Related link to merge-land.md, the quest this PR deletes. That link came in on main and broke the required check (link does not resolve). No code changed.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits October 31, 2026 23:40
- Pick the repository's merge method: the one --squash or --rebase names,
  refused when disallowed, else the only one allowed, else a merge commit.
- A bare PR number outside a checkout says to pass the PR URL.
- A direct merge releases quest:merge once GitHub reports it merged.
- quest status reports the head auto-merge was enabled on, from the
  quest land pin or the head branch's push activity, and quest wait prints
  auto-merge:moved when it differs from the current head. The iterate skill
  disables auto-merge before pushing.

Deletes the finished quest quest/m0/helpers/merge-land.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Close quest merge --land's gaps feat(merge): close quest merge --land's gaps Nov 1, 2026
…idden

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review November 1, 2026 07:12
@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d792e7d8-445d-466c-ad39-062653eb16af
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@kixelated

Copy link
Copy Markdown
Collaborator Author

I've taken this PR out of the queue for now. An audit found it contradicts moq-dev/quest#326: this PR releases a quest:merge label on direct merges and keeps a token valid across refusals, but after #326, quest merge takes no label and no token. Once #326 lands, this will be reworked to keep only the merge-method selection, PR URLs outside a checkout and auto-merge:moved, then queued again.

(Written by Claude Opus 5.5)

kixelated and others added 2 commits November 1, 2026 17:02
Rework the PR on top of #326, where `quest merge` takes no label and no
token: drop the direct-merge label release and the token-preserving
refusal order, and keep the merge-method selection on an ungated base,
the bare-number error outside a checkout, and the auto-merge head report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated and others added 2 commits November 1, 2026 17:42
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e's head

GitHub lists a merge into a branch as pr_merge or merge_queue_merge
activity, which also moves its head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Design change: this PR now keeps only three of its gaps, as decided in the 2026-11-01 comment after moq-dev/quest#326 merged.

Kept:

  1. Merge-method selection for quest merge --land on an ungated base.
  2. PR URLs, and a clear error for a bare number, outside a checkout.
  3. The auto-merge:moved carry-over: the enabled head in quest status, the event in quest wait, and the iterate skill's disable-before-push rule.

Dropped:

The merges of main through 5b3b33ec already removed that code, because #326 rewrote the same lines. The rework left only the PR body and one stale quest link to fix. This PR still finishes quest/m0/helpers/merge-land.md, whose Plan on main already leaves out the label work. So the PR deletes the quest and its last link, in quest/m0/queue-watcher/pick.md.

(Written by Claude Opus 5.5)

@kixelated
kixelated enabled auto-merge (squash) November 2, 2026 01:53
@moq-bot
moq-bot Bot merged commit 3c8cdce into main Nov 2, 2026
@moq-bot
moq-bot Bot deleted the quest/m0/helpers/merge-land branch November 2, 2026 02:04
kixelated added a commit that referenced this pull request Nov 2, 2026
Merges #347's merge-method changes into land, and applies
the 2026-11-02 design change: drop the pick comment and src/cli/pick.ts.
On a merge-queue base, a head GitHub refuses to enqueue now fails
quest merge with a refusal that says to fix the PR (for example with
/quest-iterate) and land it again. Queue removals reconciles picks from
merge-queue timeline events and auto-merge state, trusting the enqueuer
or enabler; Bad picks narrows to enqueueing armed picks GitHub never
queued.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant