Skip to content

A ship unit owns its pull request until the pull request is merged: merge-ready waits on facts, a DIRTY head buys a rebase round, and anyone's merge ends the unit ​

The title and filename predate the amendment below and name the withdrawn shape — the always-on rebase round bought by a DIRTY head; they are kept to preserve links.

Accepted 2026-09-20 05:45Z (22:45 PDT on the 19th), in the shape the amendment of #2048 gave it — the three mechanisms, in the order they ship: the rebase before every push (always, not configurable); the sweep a person runs with the two-rung resolver — git alone with the repository's own merge drivers and git rerere, then one bounded model round reading the repository's AGENTS.md; and watch-until-merge as an org setting with a per-repository override, off by default. Two calls are the maintainer's at acceptance: a stale-but-clean pull request is never rebased by the pipeline — DIRTY is the only trigger the sweep and the watch answer — and the resolver knows nothing about a repository's technology; what it may regenerate is only what the repository's own AGENTS.md names. The plan this record names in its rollout follows the record to accepted, with its first unit — the rebase before every push — ready to seed.

Amended 2026-09-20 04:55Z (while proposed), on the maintainer's redesign: the always-on rebase round — one per base move per unit — is withdrawn. It makes the expensive behaviour the default, and its only softer variant, "rebase once at some later time", is arbitrary and cannot be explained to a person. Three mechanisms replace it: a rebase before every push (always, not configurable), a sweep a person runs with a two-rung resolver, and watch-until-merge as a setting, off by default. Each changed section below carries a note of the same date; the incident, the today table and the rejected alternatives stand, with two alternatives added.

The ask. Decide (the maintainer, before the plan is written): how a ship unit's pull request stays mergeable as the base moves, without making the expensive behaviour the default. Written for an engineer who knows the plan runner's driver, the ship machine and the checks intake. Success criteria (amended 2026-09-20 04:55Z — the criteria now state the three mechanisms; the original criteria 1 and 4 stated the withdrawn always-on round):

  1. Every head that reaches review is current when it lands: a coding or fix child fetches the base and rebases its branch onto it immediately before each push, resolves what it must with the thread context it already has, re-runs the fast gates, then pushes. This is not configurable.
  2. One registry command — named in the user's twelve nouns, over the pull request noun — walks the open pull requests the pipeline owns, or one named pull request, and rebases each onto its base with the two-rung resolver. Rung one is git alone: git rebase with whatever merge drivers the repository itself declares in .gitattributes, and git rerere so a resolution made once replays on every later rebase of the same hunks; an empty git range-diff after the rebase carries the existing approval to the new head with no re-review. Rung two is one bounded model round with the thread's context and the repository's own AGENTS.md for any conflict git leaves — one per repository in flight, a short lease, a delta re-review.
  3. Watch until merge is a setting, off by default, org-level with a per-repository override, on the config surface that exists. When on for a repository, the unit stays on its pull request after merge-ready and, on each push-to-base webhook that leaves it DIRTY, runs the two-rung resolver for that one pull request, fixes tests and re-requests review as needed, until the pull request is merged or the person ends it — capped at one rebase per repository in flight and a per-pull-request spend limit, both configurable. Off — the default — merge-ready ends the unit as today.
  4. A stale-but-clean pull request is never rebased by the pipeline: it merges as it is. Nothing in the sweep or the watch suggests or makes structural changes to a person's repository.
  5. The merge door's conflict refusal names the remedy that exists: the watching unit's own round where the setting is on, the sweep command otherwise — never a person's hand merge as the only way.

TL;DR ​

Tonight, on 1.255.0 between 03:04Z and 03:53Z, three routed units (merge: person) ended merge_ready and their pull requests then went DIRTY when siblings merged first — #2029 (run ab8527aa), #2033 (plan the-verifier-s-floor-on-b4faed) and #2032 (plan write-the-next-decision-e5ac46, a two-row conflict on the generated decisions index) — and #2033 went DIRTY a second time after its rebase because #2029 merged in between. Nothing owned any of them: each unit had ended, a plain reply in the thread routes (issue 1878), and the merge door's conflict refusal says re-issue (issue 1747). Four rebases were posted by hand as agent:coding directives — 14 minutes of child time, about nine dollars, one wrong-branch attempt hard-stopped.

Amended 2026-09-20 04:55Z (while proposed) — the bet, redesigned. Three mechanisms in place of one always-on loop. First, every push is preceded by a rebase onto the fetched base, so every head that reaches review is current when it lands — not configurable. Second, a sweep a person runs: one registry command that rebases the open pull requests the pipeline owns (or one named) with a two-rung resolver — git alone first, with the repository's own merge drivers and git rerere, an empty git range-diff carrying the existing approval to the new head with no re-review; then one bounded model round with the thread's context and the repository's own AGENTS.md for any conflict git leaves. Third, watch until merge as a setting, off by default: a repository that turns it on keeps the unit on its pull request after merge-ready, running the same resolver on each push-to-base webhook that leaves it DIRTY, under a one-rebase-per-repository cap and a per-pull-request spend limit, until the pull request is merged or the person ends it. Stale-but-clean pull requests are never rebased by the pipeline: they merge as they are. Doing nothing keeps the by-hand rebase as the answer to every sibling merge.

Today at a50bf628 ​

ClaimProof at a50bf628
merge_ready is an ended kind: a reply into its thread can continue nothing, and the thread routes freshsrc/core/ship/coordinator.ts, the ended kinds beside idle (merged, already_landed, merge_ready, held, refused); thread-admission.md item 9's owner order reads the unit's ending
The walk reads the ending and moves on; when it returns, runPlan calls finish and nothing watches the pull request afterwardsrc/core/coordinator/driver.ts, walk and runPlan
The merge door refuses a conflicting pull request before the checks are read, and its remedy is a person's: "rebase onto the base, push, and merge it by hand once the checks are green"src/channels/adminCoordinator.ts, the mergeable_state: dirty refusal; agent-ship.md item 9
The checks reader exists and speaks to waiting instances: the check-run intake sends checks-settled-<head> to every instance registered at that head in the merge-wait book — the read record 0055 gave the round. Nothing reads or forwards the pull request's mergeable_state after the endingsrc/core/coordinator/checksIntake.ts, MergeWaitRegistry; src/execution/githubPulls.ts, fetchPullRequestFacts carries mergeableState for the ending's read only
The machine already re-enters a pass at the review round on an existing head — the resume after review_pending — and a re-entered pass can carry the unit's round countsrc/core/ship/coordinator.ts; src/core/coordinator/handOff.ts, the resume row; record 0051's warm-chain design carries reviewRounds across passes
Record 0051's warm window — ownership after merged or merge_ready for sixty minutes, restarted by replies — is designed and not built; either way it is a timer a reply restarts, not a fact the repository sendsno warmUntil under src/; 0051, "Amended — a finished unit stays warm"
The coding child's contract already tells a child to re-fetch the base right before its push and rebase once more when the base movedagent-ship.md item 9; src/core/ship/contract.ts
Tonight's incident: three merge-ready pull requests DIRTY on sibling merges, one twice; four hand rebases as agent:coding directives, 14 minutes of child time, about nine dollars, one wrong-branch attempt hard-stoppedthe operator log of 03:04Z to 03:53Z, 1.255.0: #2029 (run ab8527aa), #2033 (plan the-verifier-s-floor-on-b4faed), #2032 (plan write-the-next-decision-e5ac46)

The re-evaluation of record 0051: why this is a new record and not an amendment ​

The unit that asked for this record asked first whether 0051's acceptance reasoning already implies it. It does not, on two sentences of 0051's own. First, 0051 was accepted with the ending's line drawn at merge-ready: "a unit is ended when merged, merge-ready, blocked by a dependency, or refused at authorization: nothing a reply can change." Tonight shows a merge-ready ending has exactly one thing left that facts change — the pull request — and 0051's reasoning never weighed a repository fact, only a person's reply. Second, 0051's warm amendment already moved the line once, to a sixty-minute window restarted by replies, and in doing so rejected the unbounded shape by name: "why not no window? … an instance per unit alive indefinitely." This record reverses that rejection for the merge-ready ending, on a bound the amendment did not consider: not indefinite, but the pull request's own life — an open pull request is unfinished work, and merge or the person's stop ends it. A reversal of a rejected alternative is a new decision, not a note on the old one; the documentation rule (an accepted record only grows by an appended re-evaluation) is for a change checked against the record's reasoning, and this change contradicts it.

What survives of 0051 untouched: the owner order itself, the event and nudge machinery, idle and its lease rule, and the warm window — which now applies from merged, the one ending left where follow-ups arrive after the work is done.

Amended 2026-09-20 04:55Z (while proposed): the reversal is now a setting's, not the record's. With watch-until-merge off — the default — merge_ready stays an ended kind and 0051's line stands exactly as accepted. Only a repository that turns the watch on keeps its unit on the pull request, bounded by the pull request's own life, the one-rebase-per-repository cap and the per-pull-request spend limit. The two sentences above still say why the watch, where it is on, is a new decision and not a note on 0051.

The shape ​

Amended 2026-09-20 04:55Z (while proposed): this section is rewritten whole. The earlier shape — the merge chain beside the walk for every unit, a dirty fact buying a rebase round, at most one round per base move per unit, always on — is withdrawn: it makes the expensive behaviour the default, and "rebase once at some later time" is arbitrary and cannot be explained to a person. The three mechanisms below replace it.

One — rebase before every push, always. A coding or fix child fetches the base and rebases its branch onto it immediately before each push: it resolves what it must with the thread context it already has, re-runs the fast gates, then pushes. This extends the contract's existing pre-push re-fetch rule from "rebase once more when the base moved" to the unconditional form, and it is not configurable — a rebase against a base the child just fetched, with the conflict's context already in the child's window, is the cheapest rebase the system will ever run. Every head that reaches review is current when it lands; what this mechanism cannot do is keep a head current after it lands, which is the other two mechanisms' job.

Two — a sweep a person can run. One registry command — named in the user's twelve nouns, over the pull request noun (pulls rebase) — walks the open pull requests the pipeline owns, or takes one named pull request, and rebases each onto its base with a two-rung resolver. Rung one is git alone: git rebase with whatever merge drivers the repository itself declares in .gitattributes, and git rerere enabled, so a resolution made once replays on every later rebase of the same hunks; when the rebase completes and git range-diff over it is empty, the existing approval carries to the new head with no re-review — the branch's own change is byte-identical, only its parent moved. Rung two, for any conflict git leaves, is one bounded model round with the thread's context and the repository's own AGENTS.md — one per repository in flight, a short lease, and a delta re-review at the pushed head. The product never knows what a generator or a formatter is: a repository that wants a generated file regenerated rather than hand-merged says so in its AGENTS.md, and the model round reads it there.

Three — watch until merge, as a setting. Off by default; org-level with a per-repository override, on the config surface that exists. When on for a repository, the unit stays on its pull request after merge-ready — the merge-ready book beside the merge-wait book, registered with the pull request, head and base — and on each push-to-base webhook that leaves the pull request DIRTY (read once GitHub has recomputed mergeable_state, never on a clock), it runs the two-rung resolver for that one pull request, fixes tests and re-requests review as needed, until the pull request is merged or the person ends it. The loop is capped: one rebase per repository in flight, and a per-pull-request spend limit, both configurable; at a cap the DIRTY stands and the card names the sweep a person can run. A merged fact, whoever merged, ends the unit merged by other, and with the watch on the waiting unit owns its thread under the unfinished-unit clause, so an addressed reply is its turn and never the router's; with the watch off, merge_ready is an ended kind exactly as today.

What the pipeline never does. A stale-but-clean pull request is never rebased: it merges as it is — DIRTY, not staleness, is the only trigger the sweep and the watch answer. And nothing in the sweep or the watch suggests or makes structural changes to a person's repository: the resolver's whole brief is the conflict in front of it, and what it may regenerate is only what the repository's own AGENTS.md names. The merge door's conflict refusal changes its sentence to match the remedy that exists: the watching unit's own round where the setting is on, the sweep command otherwise.

One trace: tonight replayed — the cascade converges ​

Amended 2026-09-20 04:55Z (while proposed): the trace is rewritten against the three mechanisms; the hard case — three units of three plans merge-ready on heads that touch the generated decisions index, the base moving twice inside the hour — is unchanged.

  1. 03:04Z: under mechanism one, each of #2029, #2032 and #2033 was pushed after a rebase onto its just-fetched base, so all three reached review current and hold approvals at their heads.
  2. A person merges #2029. Its unit ends as today. The base moved: GitHub recomputes, and #2032 and #2033 read DIRTY. With the watch off — the default — nothing owns them and nothing spends: the plane's table and the units' cards say DIRTY and name the sweep.
  3. The person runs the sweep once. It walks the pipeline's open pull requests, one rebase in flight per repository. On #2033, rung one rebases onto the tip and git leaves the two-row conflict on the generated decisions index; rung two runs — one bounded model round that reads this repository's AGENTS.md ("never hand-edit a generated file … npm run fix"), takes either side, regenerates the index, re-runs the fast gates and pushes. git rerere records the resolution. The range-diff is not empty (the regenerated rows differ), so a delta re-review runs at the new head; merge: person re-reports merge-ready in one line. On #2032, swept next, rung one replays the recorded resolution on the same hunks — git alone, no model round.
  4. A person merges #2033. The base moved again and #2032 reads DIRTY a second time — tonight this was a person's fourth directive; here it is one more row of the same sweep, or the next sweep, and rung one's replayed resolution again costs no model round. Its delta re-review approves; a person merges it.
  5. With the watch on for this repository instead, steps 3 and 4 need no person: each push-to-base webhook that leaves a pull request DIRTY wakes its unit's loop, the resolver runs under the in-flight cap and the spend limit, and each unit ends merged when its merge is observed. Either way the cascade converges because every round reads the pull request fresh and a head that reads clean is left alone — stale-but-clean merges as it is.

Why not X ​

Why not fix the conflict refusal's wording (issue 1747's first ask)? A better sentence still names a person as the mechanism. Tonight's cost was not confusion about the remedy — it was 14 minutes of directed child time and a wrong-branch attempt, the work itself. The wording fix survives only as criterion 5: the sentence changes because the remedy changed.

Why not have the person re-issue ship after the base moves? A re-issue re-runs an approved unit: a fresh pass, a fresh coding round on work that needed only a rebase, and a second instance splitting the unit's rows, its page and its grant count — the two-places problem 0051 already rejected twice.

Why not GitHub's merge queue? The queue rebases and re-runs checks, but the approval it carries forward is the one our reviewed-head gate deliberately voids: a required re-review at the new head is this pipeline's own rule, and only a live unit can run it. The queue also serializes the whole repository where the plane's admission serializes only the rounds that contend. Where a base requires a queue, the merge door already enqueues (agent-ship.md item 9); that path composes with this record — the wait watches the queue's outcome the same way.

Why not the warm window, already designed? It is a timer restarted by replies. Tonight's first DIRTY landed 45 minutes after an ending and the second after a rebase the window knows nothing about; a window lapses while the pull request is still open, and it wakes for a person's words, never for a repository fact. The window stays — for merged, where it belongs.

Why not rebase on every base move, always on — this record's own first shape? (Added 2026-09-20 04:55Z.) It makes the expensive behaviour the default: every sibling merge charges every open unit a model round whether or not anyone wanted that head current yet, and the only softer variant — "rebase once at some later time" — is arbitrary and cannot be explained to a person. The incident numbers above are the state at 03:53Z; by the end of that night the cascade had grown to five orphaned pull requests and eight model rebase rounds at about fifteen dollars (the maintainer's comments on issue 1747). Withdrawn; the sweep and the watch keep the round behind a person's command and a setting that is off by default, and rung one means most rebases cost git, not a model.

Why not a resolver that understands each repository's technology? (Added 2026-09-20 04:55Z.) A resolver that knows this stack's generators, that stack's formatters and the next one's lockfiles is a slippery slope with no end — the maintainer's words. The product never knows what a generator or a formatter is: a repository that wants a generated file regenerated says so in its own AGENTS.md, and rung two's model round reads it there — the same file every coding child already reads.

What would change our mind ​

Amended 2026-09-20 04:55Z (while proposed): rewritten for the three mechanisms; the earlier escape hatches — the plane-side watch, the ship.ownUntilMerged flag — are subsumed by the watch being a setting that ships off. If rung two's one bounded round proves too small for real conflicts, the sweep reports the conflict and stops — it never grows into the technology-aware resolver rejected above. If watch-on repositories find one rebase per repository in flight starving their merges, the cap is already a per-repository knob. If GitHub's mergeable recompute proves too slow or lossy to trigger the watch, the intake falls back to reading the facts on every base push. Reversibility: the watch ships off by default; the sweep runs only when a person asks; and the pre-push rebase reverts to today's fetch-only rule by one contract line.

Rollout: the plan units and their spec rows ​

Amended 2026-09-20 04:55Z (while proposed): the plan is rewritten to match the redesign — the earlier four units (the dirty fact, the always-on rebase round, the merge-observed ending, the unit-thread line) are withdrawn with the shape they built. The plan holds four units; this record ends here.

  • Unit one — rebase before every push. The coding and fix children's contract: fetch the base and rebase onto it immediately before each push, resolve with the thread context in hand, re-run the fast gates, push; not configurable. Code: src/core/ship/contract.ts.
  • Unit two — the sweep. The registry command over the pull request noun (pulls rebase), walking the open pull requests the pipeline owns or one named; the two-rung resolver — rung one git alone with the repository's .gitattributes merge drivers and git rerere, the empty-range-diff gate carrying the approval with no re-review; rung two one bounded model round with the thread's context and the repository's AGENTS.md, one per repository in flight, a short lease, a delta re-review; the merge door's conflict refusal naming the sweep. Code: the command registry, src/execution/githubPulls.ts, src/channels/adminCoordinator.ts.
  • Unit three — watch until merge. The setting, off by default, org-level with a per-repository override on the config surface that exists; the merge-ready book and the push-to-base webhook read; the resolver run per DIRTY pull request with test fixes and re-requested review; the caps — one rebase per repository in flight and a per-pull-request spend limit, both configurable; the merged fact ending the unit; the watching unit owning its thread. Code: src/core/coordinator/checksIntake.ts, src/core/coordinator/driver.ts, src/core/ship/coordinator.ts.
  • Unit four — the spec rows. agent-ship.md (the wait, the resolver, the refusal's remedy), agent-coding.md (the pre-push rebase), thread-admission.md (the watching unit's owner-order clause) and routing-and-config.md (the setting and its caps) each carry the rows the first three units bind.

Validation criteria ​

CriterionProof
A coding or fix child fetches the base and rebases onto it immediately before every push, re-runs the fast gates, then pushes; no configuration turns it off[gap] unit one: src/core/ship/contract.test.ts
The sweep walks the open pull requests the pipeline owns, or one named; a stale-but-clean pull request is left alone[gap] unit two: the command's tests
Rung one is git alone — the repository's declared merge drivers, git rerere replaying a resolution on the same hunks — and an empty git range-diff carries the existing approval to the new head with no re-review[gap] unit two: src/execution/githubPulls.test.ts
Rung two is one bounded model round with the thread's context and the repository's AGENTS.md; one per repository in flight, a short lease, a delta re-review at the pushed head[gap] unit two: the resolver's tests
The watch is off by default; on for a repository, each push-to-base webhook that leaves the pull request DIRTY runs the resolver, fixes tests and re-requests review, until merged or ended; the caps hold — one rebase per repository in flight, a per-pull-request spend limit, both configurable, org-level with a per-repository override[gap] unit three: src/core/coordinator/checksIntake.test.ts, src/core/coordinator/driver.test.ts
With the watch on, the waiting unit owns its thread under the unfinished-unit clause and an addressed reply is its turn; off, merge_ready is an ended kind byte for byte as today[gap] unit three: src/core/dispatch/thread.test.ts, src/core/ship/coordinator.test.ts
The merge door's conflict refusal names the watching unit's round where the setting is on and the sweep otherwise, never a hand merge as the only way[gap] unit two: src/channels/adminCoordinator.test.ts
The spec rows in agent-ship.md, agent-coding.md, thread-admission.md and routing-and-config.md resolve[gap] unit four: npm run specs:check
Live: tonight's hard case replayed — three pull requests on the generated index, the base moving twice — converges under one sweep (watch off) and under no person (watch on), read on the tracker issue[gap] units two and three, human-gated

Amended 2026-09-20 ​

This re-evaluation records mechanism one shipping and checks it against the acceptance's reasoning. The rebase before every push is now the coding preset's own instruction (REBASE_BEFORE_PUSH, src/agents/registry.ts), carried byte-identically by every coding prompt right after the fast gates — a ship fix round's child runs the same prompts — and the ship contract's first instruction points at it (REBASE_POINTER, src/core/ship/contract.ts) in place of the conditional "rebase once more if it moved" it carried before: the unconditional form this record decided, not configurable, exactly the shape the amendment above chose over the always-on round. The first validation row's [gap] is proven by the rebase-before-push rows on agent-coding.md item 13 (src/agents/registry.test.ts, the paragraph's order and its byte-identical carriage), the contract-pointer row on agent-ship.md item 13 (src/core/ship/contract.test.ts), and a replayed child whose base moved during its round showing the fetch, the rebase and the fast gates before the push in that order (src/load/scriptedProvider.test.ts). Nothing here contradicts the acceptance's two calls: the pipeline still never rebases a stale-but-clean pull request — this mechanism runs only inside a child's own round, before its own push — and the resolver knows no technology beyond what the repository's AGENTS.md names.

Amended 2026-09-20 — mechanism two shipped ​

This re-evaluation records mechanism two — the sweep a person runs — shipping, and checks it against the acceptance's reasoning. The registry command is pulls rebase (src/core/commands/pulls.ts; the command-id grammar takes no hyphen, so the group is pulls, the pull request noun's short form this record itself used), on every surface the registry serves, taking one named pull request or every open one the pipeline owns in the repository. The two-rung resolver is src/core/pullSweep.ts over src/execution/gitRebase.ts: rung one is git alone — the repository's own .gitattributes merge drivers, git rerere with auto-staging so a resolution made once replays on later rebases of the same hunks, git range-diff whose all-= answer carries the existing approval to the new head with no re-review, a --force-with-lease push and regenerated description anchors; rung two is one bounded model round per pull request (PULL_SWEEP in src/core/budgets.ts: a short lease and a spend cap), a changed patch getting a delta re-review, a second conflict ending with the conflict named in one line. One rebase runs in flight per repository; a stale-but-clean pull request is skipped — DIRTY is the only trigger, exactly the acceptance's first call — and the resolver knows no technology: what a model round may regenerate is only what the repository's own AGENTS.md names, the second call. The proof table's rows two through four are proven by agent-ship.md item 20's rows: the sweep and its skip rule (src/core/pullSweep.test.ts, the decision table, the lines and the per-repository bound), rung one against real git (src/execution/gitRebase.test.ts — the rerere replay, the range-diff gate, the refused lease), and the command's rows (src/core/commands/pulls.test.ts; the registry-driven conformance suite covers every surface and the pulls:write admission). Two pieces remain open as the specs' own gaps: the production wiring of the sweep service (CoreCommandWiring.pulls — the listing, the checkout, the model rung through dispatch(), the carry and the delta re-review; the command answers unavailable until it lands) and the merge door's refusal sentence, which still names the hand rebase until the wiring gives it the sweep to name.

Amended 2026-09-20 — the sweep's production wiring landed ​

This re-evaluation records the two pieces the previous amendment left open shipping (issue 2067), and checks them against the acceptance's reasoning. CoreCommandWiring.pulls is wired in src/index.ts over src/core/pullSweepWiring.ts, so pulls rebase runs on every surface instead of answering unavailable: the listing is the repository's open pull requests whose head is a plan branch on the base repository (listOpenPullRequests in src/execution/githubPulls.ts), each one's mergeable_state read fresh off its own facts and the approval read off the posted reviews pinned at the head; rung one runs in a throwaway clone of the pull request's branch (src/execution/sweepCheckout.ts — the App token only in the clone's config, the directory gone when the pull request's walk ends); the approval carry is the bot's LGTM: review pinned to the new head — exactly what the merge door and the auto-approve workflow read — the anchor regeneration rewrites the description's blob permalinks to the pushed head, and the delta re-review and the one bounded model round go through dispatch() as the requester, never started by the command handler (invariant 3), the round under the lease's budget: (the spend cap has no per-run lever on a plain dispatch today; the lease is the round's bound). And the merge door's conflict refusal now names the sweep — "pulls rebase <pr> rebases it onto <base> (an unchanged patch carries the approval); merge it by hand once the checks are green" — as does the merge: person ending's conflicting headline, closing the proof table's refusal row for the watch-off half (the watch-on half stays with unit three). The wiring row of the table is proven by agent-ship.md item 20's rows: the wiring's joints and the no-unavailable answer on chat, the CLI and MCP (src/core/pullSweepWiring.test.ts), a DIRTY pull request from a fixture walking rung one end to end against real git in a temp directory (src/execution/sweepCheckout.test.ts), the listing (src/execution/githubPulls.test.ts), and the refusal sentence in both settings (src/channels/adminCoordinator.test.ts, src/core/ship/coordinator.test.ts); the live cascade proof stays human-gated as item 20's own [agent] validation row, a step list run against a real DIRTY pull request. Nothing here contradicts the acceptance's calls: DIRTY is still the only trigger, and the resolver still knows no technology beyond what the repository's AGENTS.md names — the model round's request says exactly that.

Amended 2026-09-20 — mechanism three's setting, book, intake and caps landed ​

This re-evaluation records mechanism three — watch until merge, as a setting — landing its setting, its book, its trigger and its caps, and checks them against the acceptance's reasoning. The setting is the pulls block, off by default, org-level with a per-repository override on the config surface that exists: config set org --pulls.watch on|off and config set repo --repo <owner/name> --pulls.…, with the caps beside it (--pulls.rebaseInFlight, one rebase in flight per repository by default; --pulls.spendLimitUsd, one pull request's model-round spend), resolved repository over org over the default (ConfigStore.mergeWatchOf over resolveMergeWatch, routing-and-config.md item 32), gated by the config:write grant on the org's config scope. The merge-ready book sits beside the merge-wait book (MergeReadyBook in src/core/mergeWatch.ts: the pull request, head and base, the waiting instance and unit) and the trigger is the push-to-base webhook (handlePushIntake beside the check-run intake): each registered pull request of the pushed branch is read once GitHub has recomputed mergeable_state — never on a clock — and only a DIRTY one buys a round of the sweep's two-rung resolver for that one pull request, a second DIRTY pull request queuing behind the repository's in-flight cap and a spend-capped one standing with the card naming pulls rebase, exactly the acceptance's caps. A merged fact, whoever merged, is sent to the waiting unit (sendPullMerged) to end it merged by other; a stale-but-clean pull request is never rebased — DIRTY stays the only trigger, the acceptance's first call — and the resolver is the sweep's, so it still knows no technology beyond what the repository's AGENTS.md names, the second call. The merge door's conflict refusal now names the remedy that exists in both settings (criterion 5's two sentences): the watching unit's own round where the setting is on, pulls rebase otherwise. The proof table's watch rows are proven by agent-ship.md item 21's rows and thread-admission.md item 9's watching-unit row; with the watch off, merge_ready stays an ended kind byte for byte. One piece remains open as item 21's own gap: the driver's watch loop — the unit registering itself into the book at its merge-ready ending, waiting on the merged event with no sandbox and no child alive, and composing the merged by-other ending from it — so a unit still ends merge_ready under either setting until that loop lands; the watching unit's thread ownership is proven at the owner rule's seam (a row without an ending owns) and becomes production behavior with the same loop.

Amended 2026-09-20 — the ending words changed: unfinished leaves the readable set ​

This re-evaluation notes a change to the words a person can read on a unit's end, checked against the acceptance's reasoning (a unit owns its pull request until it is merged, and what a person is handed must be actionable). Five units in one night ended with the bare word unfinished seconds after their review's LGTM — three with nothing red — because the checks step's cases did not cover a required check whose run did not exist yet or a draft pull request (issue 2063). Record 0055's 2026-09-20 amendment reshapes that step as one decision table; what touches this record's proof table is the endings' words: unfinished is now the machine's word alone, a unit row a seal finds with a thread and no ending prints "no ending was recorded — re-issue agent:ship in its thread to continue", and a draft pull request ends held: draft — mark it ready to continue after waiting for the ready event. The unfinished-unit clause the watch rows above name is unchanged — a unit with no ending still owns its thread — only the word a person reads for it changed, so this is an appended note, not a superseding record. Proof: the round-verdict rows on agent-ship.md item 9 (the decision table, the draft cell, the no-nameless-exit regression).