Skip to content

feat(land): screen queued PRs with quest check and report overlaps before batching - #322

Merged
moq-bot[bot] merged 4 commits into
mainfrom
quest/m0/land-queue-checks
Oct 31, 2026
Merged

moq-bot[bot] merged 4 commits into
mainfrom
quest/m0/land-queue-checks

Conversation

@kixelated

@kixelated kixelated commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Finishes quest/m0/land-queue-checks.md: before batching, quest land screens each queued PR, so a problem one PR can be blamed for never ejects a whole batch.

Changes

  • Per-PR quest check before batching (src/cli/land.ts build/screen): each queued head is squashed alone onto the current base in the daemon's scratch worktree, using the same quest resolve merge driver as the chain. quest check then runs on that squash. A PR whose findings the base lacks, such as a link to a quest the base has since finished (moq-dev/moq#7135), is left out of the chain and ejected alone as failed_checks, with the findings in its comment. Findings are compared with the base's by path and message, ignoring line numbers, so a PR that only moves an existing finding is not blamed for it. A base with no quest/ directory skips the check.
  • Fixer on a rejection: each rejection is saved as its own failure.json (tip = that squash, log = the findings) and goes through resumeFailure, so a configured fixer gets it the same way it gets a failed batch.
  • Queue-time overlap report (src/cli/land-serve.ts reportOverlaps): a newly queued PR is also squashed onto each PR ahead of it (each squashed alone onto the base). If any of them conflict, the daemon comments once on the later PR with their numbers and files, as with moq-dev/moq#6994 / moq-dev/moq#7196. screened.json in the state directory records each PR's queue time, so a PR is screened again only after it is requeued.
  • snapshot(root, commit, submodules = false) (src/cli/tree.ts) treats every path inside a submodule as existing instead of reading the submodule. The daemon's bare repository has no submodule checkouts.
  • README, the quest land serve help, and tests are updated. The test Forge can now delete files, and three quest-file fixtures now add or delete the quest files they link, so they pass quest check.
  • quest/m0/helpers/queue-siblings.md is narrowed. On quest land the dead-link failure now ejects only the culprit, before batching. That quest keeps the tolerant check, or another way to spare the PR from ejection, on every gate.

Trust model: why the per-PR check runs in the daemon, not --sandbox

quest check here runs nothing from the PR's tree:

  • It is not a subprocess of the checkout. The daemon calls the core check() in-process on snapshot(dir, commit), which reads quest files from git objects (git ls-tree -r and git cat-file --batch) in the daemon's private repository. No files are checked out for it, so no bunfig.toml, .env, hook, or package script in the PR is ever loaded. ls-tree and cat-file --batch apply no filters or textconv.
  • check() is pure: it parses Markdown and tests whether paths exist in the tree listing. The one place it could read outside git objects is a submodule. With submodules = false it never runs git -C <root>/<module>, so a PR-controlled gitlink path cannot point it at another repository on the host.
  • The squash merges use the existing trusted path, mergeWorktree: hooks are off, GIT_CONFIG_GLOBAL=/dev/null, and the merge driver is quest resolve, run from the git directory, as build already did.
  • Error messages from an unreadable tree (for example a non-UTF-8 quest, or no quests left) become findings with the scratch path removed, so no host path reaches a PR comment.

Running it through --sandbox would cost one container per queued PR on every round and add nothing, because nothing from the tree runs.

Choices made without asking

  • A screened-out PR uses the existing failed_checks reason, not a new one. quest status and /quest-complete already handle it, and the comment says it was quest check.
  • Every queued PR is screened each round, not only the batch. That is cheap, git-only work, and it ejects a failing PR as early as possible.
  • Overlaps are checked only against PRs ahead in the queue, and reported on the later PR, the one that has to fix the overlap. A PR that conflicts with the base itself is left to the chain's existing merge_conflict handling.
  • The overlap report is a plain comment with no hidden marker, so quest status does not read it as an ejection.

Suggested follow-ups

  • Re-report overlaps when the PR ahead changes. Today a PR is screened once per queue time. If a PR ahead is requeued it is screened against the PRs ahead of it, but the PRs behind it are not screened again.
  • Consider running quest check --base (the quest-branch accuracy check) in the same screen, if CI does not already gate it.

Review

  • Reviewer: Codex, gpt-6-astra, medium effort (quest review --deep; this change processes untrusted PR content in the trusted daemon).
  • Round 1 on 8366a73: 1 finding. A screening rejection skipped the fixer lifecycle. Fixed in 62c4f45: each rejection is saved as a failure.json and goes through resumeFailure, with a new test.
  • Round 2 on head 62c4f45dccc9e29cb0d39de219fa5be0b38c0205: 0 findings.

Local checks on 62c4f45: just check passed. just test passed (725 passed, 2 skipped; 426 for each build's lifecycle), run with env -u CLAUDE_CONFIG_DIR.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 3 commits October 31, 2026 08:11
Before building a batch, quest land squashes each queued PR alone onto
the current base and runs quest check on it in the daemon, reading quest
files from git objects. A PR with findings the base lacks, such as a link
to a quest the base finished, is ejected alone as failed_checks instead
of failing the whole batch. A newly queued PR is also squashed onto each
PR ahead of it, and the daemon comments once on it with the PRs and files
it conflicts with.

Finishes quest/m0/land-queue-checks.md and narrows
quest/m0/helpers/queue-siblings.md to what remains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title quest land checks queued PRs before batching them feat(land): screen queued PRs with quest check and report overlaps before batching Oct 31, 2026
@kixelated
kixelated marked this pull request as ready for review October 31, 2026 15:34
@coderabbitai

coderabbitai Bot commented Oct 31, 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: b209f5b2-ca99-4051-813a-0a5e8b24e121
  • 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

@moq-bot
moq-bot Bot merged commit 4c0eb97 into main Oct 31, 2026
@moq-bot
moq-bot Bot deleted the quest/m0/land-queue-checks branch October 31, 2026 23:06
moq-bot Bot pushed a commit that referenced this pull request Nov 1, 2026
* fix(land): screen only the PRs a batch reaches

#322 squashed every queued PR onto the base and every new one onto each PR
ahead of it before building a batch. With 62 queued on moq that is about
1,900 merges, so the daemon screened for over 20 minutes and never built a
batch. Each candidate is now screened as the batch reaches it, memoized per
batch, and a new PR's conflict report covers the four PRs landing soonest.

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

* test(land): give the daemon tests a measured timeout

On the land gate's host under load 28, land tests that take 1.1-1.8 s
unloaded took 5.2-6.8 s and failed vitest's 5 s default, ejecting this PR
twice. Like move, start and landed, the file now allows 30 s.

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

---------

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