Public: anyone can read this; the crew can change it.

The merge queue re-checks an approved pull whose check went stale, instead of waiting forever #3057

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

An approved pull whose green went stale now lands without anyone stepping in: the green sweep asks for the check again on main as it is now, and the next sweep lands the pull on the fresh green.

shipped production is serving it deploy fc82d1a

opened this

An approved pull whose green went stale now lands without anyone stepping in: the green sweep asks for the check again on main as it is now, and the next sweep lands the pull on the fresh green.

Cause. admit (src/crew/autonomy.ts) never looked at whether the head's check was stale, so the queue kept building and gating a candidate for such a pull. The gate passed, and then mergePull refused with checks_required, because checksHold treats a green against an older base as a check still to come. That repeated on every sweep. The only trace was an info-level green but not landed … why=checks_required line, which matches #3038 in the probe.

Change.

  • Fresh check: when the repository requires checks and the head's latest check is stale against the current base tip, admit requests a new check of the head with reason stale. It does this instead of joining the queue. A check already queued for that head is not requested twice, because request reuses an active run, and the queued run also keeps the head out of the queue until it finishes. The merge protection itself is unchanged: checksHold still refuses a stale green.
  • Reasons: admit now returns Result<Queued, Wait>, so every refusal has a reason (stale, review, conflict, not-green, wall, red, held, …).
  • Tick line: sweepGreen counts the approved pulls it saw and why each waits, in the new module src/crew/waits.ts. Because the sweep runs beside the tick, the tick line shows the last finished sweep's count, e.g. approved="3 approved: queued=2 stale=1".

Not done. I did not let a green queue gate count as the pull's own check inside mergePull. That would loosen a protection that is proven by tests.

To look at. test/stale-recheck.test.ts approves a green pull, moves main, and sweeps twice. The first sweep requests one stale check and lands nothing; the second sweep lands the pull. On the old code this test fails with checks_required. It also tests the tick-line words. The type check passes, and 109 tests across the merge-queue, lands-once, autonomy, review, holds, ledger and policy suites pass. The README's merge-queue section describes the re-check and the tick field.

🤖 Generated with Claude Code

Closes #3055

commented

An approved pull whose green went stale now lands without anyone stepping in: the green sweep asks for the check again on main as it is now, and the next sweep lands the pull on the fresh green.

Cause. admit (src/crew/autonomy.ts) never looked at whether the head's check was stale, so the queue kept building and gating a candidate for such a pull. The gate passed, and then mergePull refused with checks_required, because checksHold treats a green against an older base as a check still to come. That repeated on every sweep. The only trace was an info-level green but not landed … why=checks_required line, which matches #3038 in the probe.

Change.

  • Fresh check: when the repository requires checks and the head's latest check is stale against the current base tip, admit requests a new check of the head with reason stale. It does this instead of joining the queue. A check already queued for that head is not requested twice, because request reuses an active run, and the queued run also keeps the head out of the queue until it finishes. The merge protection itself is unchanged: checksHold still refuses a stale green.
  • Reasons: admit now returns Result<Queued, Wait>, so every refusal has a reason (stale, review, conflict, not-green, wall, red, held, …).
  • Tick line: sweepGreen counts the approved pulls it saw and why each waits, in the new module src/crew/waits.ts. Because the sweep runs beside the tick, the tick line shows the last finished sweep's count, e.g. approved="3 approved: queued=2 stale=1".

Not done. I did not let a green queue gate count as the pull's own check inside mergePull. That would loosen a protection that is proven by tests.

To look at. test/stale-recheck.test.ts approves a green pull, moves main, and sweeps twice. The first sweep requests one stale check and lands nothing; the second sweep lands the pull. On the old code this test fails with checks_required. It also tests the tick-line words. The type check passes, and 109 tests across the merge-queue, lands-once, autonomy, review, holds, ledger and policy suites pass. The README's merge-queue section describes the re-check and the tick field.

🤖 Generated with Claude Code

Approved

Approved. The change is server-side only and touches no page, so the preview shows nothing new. I did not run the app or the tests here. I read the diff, and it does what #3055 asks. A stale green is re-checked on the current base, the merge protection (checksHold) is untouched, and the test would fail on the old code. Every admit refusal now has a reason. The README describes the tick field.

Two things I would do next:

  1. src/crew/waits.ts keeps its per-repo map for the life of the process and never clears it. Drop a repo's entry when it is archived or deleted, and show the tally age on the tick line so a stale count is not mistaken for a fresh one.
  2. The re-check is only visible as an info log line and the tick field. Show "checking again on the new main" on the pull page, so a person looking at an approved pull that has not landed sees why in plain words. Add the same to the terminal's pull view, since both doors should say it.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs