Expand description
Landing the winner: watch the pull request, fix what it complains about, and merge it.
Opening the pull request used to be where magi stopped and the operator started: watch the checks, read what the review bots found, push a fix, wait again, merge. That loop is mechanical, it takes an hour of wall-clock time per pull request, and doing it by hand six times in one session is how a queue that drains unattended stops being unattended. So it lives here.
§Shape
PrState is one observation of a pull request and decide is the whole
policy as a pure function of it. Nothing in decide talks to gh,
which is what makes “green with an unresolved comment is a fix, not a merge”
an assertion in a test rather than a claim in a comment. land is the
only part that performs I/O: observe, decide, act, repeat.
§What it refuses to do
Merging is the one irreversible thing magi can do to a repository, so the loop is built to stop rather than to guess:
- A red pull request is never merged. When the budget runs out the pull request is left open with a comment naming what is still failing, because a magi that force-merges a red pull request is worse than one that stops.
- A pull request whose checks cannot be read at all (
ghreported no rollup) is not merged either. Landing is for repositories with CI; with no signal there is nothing to be green. - A pull request a human merged or closed underneath us is
Step::Done- the person won, and their decision is not an error.
§Why --subject is not optional
A candidate branch holds one commit whose subject is
magi: candidate A (uncommitted work), and gh pr merge --squash prefers a
single commit’s message over the pull request title. Merging without
merge_argv’s explicit --subject therefore writes a main history that
says nothing about what landed. AGENTS.md records the trap; this module is
where it is prevented.
Structs§
- External
Merge - A pull request the operator merged outside of
land::land’s own loop, found by asking GitHub about the run’s own winning branch rather than requiring the operator to go and find the URL themselves. - PrState
- One observation of a pull request.
- Refusal
- Why
closablesaid no, and whether asking again later could say yes. - Review
Comment - One outstanding review comment, human or bot.
Enums§
- Approval
- What the owner’s answer to the approval question means.
- Blocking
- Whether a failing check actually stands between the pull request and
main, according to the forge. - Checks
- The aggregate verdict of a pull request’s checks.
- OpenPr
- What
gh pr list --head <branch> --base <base> --state openfound. - PrLifecycle
- Where a pull request is in its life.
- Step
- What the loop decided to do next. Pure, so the policy is testable.
Constants§
- APPROVAL_
NODE - Graph node recorded on the approval question.
- APPROVE
- The choice that lets the merge happen, verbatim as the owner taps it.
- CHECKS_
GRACE - How long the checks may stay unreadable before landing gives up on them.
- DIFF_
MAX_ LINES - Unified diff lines carried in the panel before it is truncated.
- HOLD
- The choice that leaves the pull request open.
- MARKER
- Marker carried by every comment magi posts on a pull request.
- POLL
- How often the pull request is re-read while its checks are still running.
- WAIT_
CEILING - How long one wait may last before landing gives up on the checks finishing.
Functions§
- approval
- Read the owner’s answer, where
Noneis an unanswered question. - approval_
panel - The approval panel’s html: what is about to land, and the evidence for it.
- branch_
is_ ancestor - Whether
branchis, right now, an ancestor ofbase_branchin the local git graph — the weaker, URL-less signal that a branch landed somewhere. - closable
- Pure half of
close_superseded_pr: readgh pr view --json headRefName,baseRefName,state,isCrossRepositoryand say whether closing is safe,Errcarrying the reason when it is not. - close_
superseded_ pr - Close the open pull request for
branch, if there is one and it is provably this run’s, with a comment naming what supersedes it.Ok(Ok(url))is the URL closed;Ok(Err(why))is a final “nothing to close” (no pull request, not this run’s, no forge);Erris anything a later attempt could resolve (a failedghcall, a head that moved since it was checked), which the caller must not treat as settled. - correct_
manual_ merge - Confirm
urlis actually a merged pull request, then rewritestate’sstatusandmergeexactly as the automatic land loop (land::land) would have written them had magi opened and merged this pull request itself. - decide
- Decide the next step. No I/O.
- deputy_
brief - What a merge-approval question’s deputy is told: the pull request, the run, what each answer does, and - when the run’s record is readable - the contested hand-off the question was filed over.
- disable_
automerge_ argv - Take auto-merge back. magi no longer arms auto-merge, but a run recorded by
an older build may still have one standing on the forge, so the disarm
paths (and
RunState::land_armed_head) stay. Run before anything that changes the head, so an armed merge never outlives the commit that was approved for it. - find_
external_ merge - Ask GitHub whether this run’s winning candidate branch was actually merged
somewhere
land::land’s own loop never saw — the gapmagi fold --mergedexists to close, minus the operator having to find the URL by hand. - find_
open_ pr - Open pull requests whose head is
branchand whose base isbase. A failingghis an error carrying its own output, never “none”: guessing there is how a duplicate gets created. - is_
noise - Is this comment body machinery rather than a finding?
- land
- Run the loop against a real pull request until it merges or the budget runs out.
- lifecycle
- Read just a pull request’s lifecycle state - open, merged, or closed -
with none of the checks/reviews/comments
landitself needs to decide what to do next. - merge_
argv - The argv magi merges with, minus the program name.
- merge_
argv_ at merge_argvpinned to the commit the decision was made about.- merge_
subject - The squash subject to merge under.
- parse_
inline_ comments - Parse
gh api repos/{owner}/{repo}/pulls/<n>/commentsinto inline review comments. No I/O. - parse_
pr - Parse
gh pr view --json url,number,state,statusCheckRollup,reviews,commentsoutput into aPrState. No I/O. - pick_
open_ pr - Pure half of
find_open_pr: classify the raw--json number,url,title,baseRefNameoutput. Entries whose base is notbaseare dropped even though the query already filtered on it, so a stub or an oldghthat ignores--basecannot get a pull request into the wrong branch adopted. - repair_
stale_ pr_ states - One-time (and idempotent) repair of records that froze an
openpull request: ask the forge about each distinct pull request that a terminal run still calls open - at mostmax_lookupsof them - and rewrite the merged and closed ones. A genuinely open pull request is left alone, and a lookup that fails is “unknown, change nothing”. Returns(records rewritten, lookups that failed). - set_
pr_ title gh pr edit <url> --title <title>, for an adopted pull request whose title differs from the one this run computed. Only the title: the body may have been edited by the owner and cannot be compared.- superseded_
comment - The comment left on a pull request closed because its change is already on the base.