Development record
A Ready PR Merges Without Ever Wedging BEHIND
Superseded by itd-2610261025516272 on 2026-10-26: Its want, a ready pull request that never waits behind another, is met on every plan by itd-2610261025516272: GitHub's queue where the plan has one, the local landing queue elsewhere (product thinker, 2026-10-26)
Press Release
abcd-managed repos stop losing time to out-of-sync pull requests. Onboarding configures a merge queue by default: a PR marked ready enters the queue, the forge tests it combined with the current base, and merges it in order the moment it is green — no one runs
update-branchby hand, no PR sitsBEHINDforever because another merged first, and CI runs against the state that will actually land instead of re-running on every manual re-sync. Where a queue is not available, abcd falls back to a protocol-level auto-update — poll, and re-sync a behind PR automatically — so the toil is still gone. Either way the strict merge gate stays intact: it is what catches a duplicate record id minted by two parallel sessions, and abcd never trades that safety for convenience."Three of my routines were opening PRs in parallel and every one of them kept stalling
BEHIND— I was hand-updating branches and burning CI to land a one-line change," said Carol, a facilitator. "Now they queue and land themselves, and I never think about it."
Why This Matters
Under a ruleset that requires up-to-date branches, GitHub's auto-merge never
updates the branch itself, so the instant one PR merges, every other open PR is
BEHIND and wedged — armed, all checks green, and going nowhere ([iss-172]).
The manual fix (update-branch) re-runs the whole matrix and often just loses
the next race. Across parallel agents this is constant, and it wastes both the
facilitator's attention and CI minutes on nothing.
The tempting fix — drop "require up-to-date" — is the wrong one, and the record says so. [iss-172] records the invariant: strict-up-to-date is what forces a PR's merged result to be re-gated before it lands, and that gate is load-bearing because record-id minting is serialised only within a checkout, not across checkouts — two branches can each mint the same id, each pass the record gate in isolation, and the duplicate exists only in the merge. Strict is what catches it. Relaxing strict resolves the stall by removing that gate.
A merge queue resolves the stall the right way: it re-runs the required checks against the projected merge and lands PRs in order — so it preserves exactly the gate strict provides, automatically, without the manual churn. It is strict's safety minus the toil.
SOTA
Anchors: GitHub Merge Queue (GA 2023; the forge-native answer to this exact problem), and the merge-train lineage it descends from — Bors, GitLab merge trains, Zuul's speculative gating.
Declared path: 1 — adopt the SOTA forge feature. The merge queue is a ruleset
setting plus a CI trigger (merge_group), not a code dependency, so adopting it
carries no go.mod cost — the new-dependency stop does not apply; the only cost
is the config abcd already owns for managed repos. abcd's role is to configure
it during onboarding, not to reimplement queuing. Where the queue is unavailable
(older forge, a plan without it), the fallback is [iss-172]'s rung 1 — the
protocol-level poll-and-update-branch, which preserves strict. The
relax-strict option is deferred: it becomes safe only once [itd-114]
(collision-proof ids) removes the duplicate-id risk by construction; until then
strict is never relaxed. The independent fit-challenge runs at plan time.
Acceptance Criteria
BDD (the [itd-1] discipline).
- Given a managed repo with the merge queue configured, when two PRs are
ready concurrently, then they land in order with no manual
update-branchand neither sitsBEHIND, and the required checks run against the projected merge (the gate preserved). - Given onboarding configures the merge queue, when it sets up CI,
then the required checks also trigger on the
merge_groupevent — without which the queue cannot gate — and abcd verifies this rather than assuming it. - Given a repo where the merge queue is unavailable, when a PR falls
BEHIND, then abcd's rung-1 auto-update brings it current (poll +update-branch), preserving strict — never by relaxing strict. - Given [itd-114] (collision-proof ids) has not shipped, when the policy is configured, then strict-up-to-date is left intact (the duplicate-id gate stays); relaxing it is out of scope until collision-proof ids land.
Decomposition (itd-84 hand-run, 2026-08-16)
Verdict FILE-AS-IS with flags:
| Part | Type | Home |
|---|---|---|
| The managed-repo merge policy (queue default + rung-1 fallback) | capability | this intent |
Adopt GitHub Merge Queue; the merge_group CI trigger; the rung-1 fallback |
SOTA declaration (path 1) | this intent's SOTA section |
| "Strict is the duplicate-id gate; never relaxed until ids are collision-proof" | trust rule | already recorded as [iss-172]'s invariant — this intent RESPECTS it, does not re-declare |
| Ruleset + CI-trigger wiring on managed repos | plumbing | the itd-92 / itd-106 onboarding surface |
Typed links: refines [iss-172] (delivers its rung-2 "scaffolded CI / merge
queue" ask; iss-172 resolves when this ships), refines [itd-92]
(branch-protection setup) and itd-106 (CI setup), and refines [itd-114] —
itd-114 is what later unlocks safely relaxing strict.
No reversal flag. The earlier "just relax strict" idea would have reversed [iss-172]'s invariant; this design was corrected to respect it, so nothing is reversed — the correction is the point.
Open Questions
- Merge-queue availability across repo tiers. The queue (like rulesets) may need a paid plan on private repos — the same tier gap the 2026-07-29 ruleset sweep hit. Where unavailable, rung-1 is the whole answer; state that explicitly.
- The rung-1 credential question (carried from [iss-172]): a scaffolded
auto-update workflow needs a PAT/App because the default
GITHUB_TOKEN's pushes don't trigger CI. The agent-token protocol form has no such need. Decide whether the scaffolded rung is in scope here or stays with the itd-107 grill. - Queue batching config (how many PRs per CI run) — a tuning knob, defer.
Audit Notes
Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/.
Frontmatter
| id | itd-115 |
|---|---|
| type | intent |
| lifecycle | superseded |
| kind | standalone |
| severity | minor |
.abcd/development/intents/superseded/itd-115-abcd-managed-repos-merge-prs-without-the.md
open on GitHub ↗ · commit history ↗
Referenced by6
- iss-2610262042372556Persona Carol is an engineering manager in itd-12 and a facilitator in itd-115related
- iss-2610262042381184Both itd-115 and itd-2610110940216682 have abcd set up the merge queue when preparing a managed repositoryrelated
- iss-2610262043071551itd-115 keeps the strict merge gate to catch duplicate ids from parallel sessions; itd-114 says ids are collision-proof with no coordination.related
- iss-2610262043143346The facilitator persona is Carol in itd-115 and Nia in itd-120.related
- itd-2610170634394993Headless agents in parallel coordinate through the shared remote, not conversationrelated
- itd-2610261025516272Private repos land checked work without renting CIsuperseded by
mentions14
- iss-172abcd-managed repos need PR-queue hygiene when branch protection requires up-to-date branches: a queued auto-merge PR whose base moved sits BEHIND forever because GitHub auto-merge never updates branches. Two delivery rungs per basics-built-in/SOTA-delegated: (1) protocol-level now — after arming auto-merge, poll mergeStateStatus and run gh pr update-branch on BEHIND (works with the agent's own token, CI triggers normally); (2) scaffolded CI later — abcd scaffolds an update-branch workflow into managed repos, which requires a PAT/GitHub-App secret because the default GITHUB_TOKEN's pushes do not trigger workflows (the recursion suppression trap), or points at a merge queue where the plan allows. Same scaffolding family as itd-93's release gate; same merged-work-hygiene family as itd-95.
- iss-371The persona_registry lint checks names, not roles: itd-114 shipped 'Bob, a maintainer' (Bob is registered staff engineer; the maintainer role is Kira's) and itd-115 has 'Carol, a facilitator' (Nia's role) — both passed lint. The selection-by-role rule (personas.json, itd-79) has no detector for role-name agreement
- iss-2609012202237613Every auto-merge pull request opened tonight (#571, #572, #574) sat BEHIND with queue entry null until a hand-run update-branch, while #570 and #573 entered the queue only because they happened to be up to date at the moment they were armed. Cause: main-protection combines the merge queue (grouping ALLGREEN, merge method MERGE, mirrored 2026-08-19) with strict_required_status_checks_policy true. Auto-merge enqueues a pull request only when its merge state is CLEAN, and under the strict policy a pull request behind main is never CLEAN, so it cannot enter the queue whose whole purpose is to test it combined with the current base. Every merge from the queue moves main and knocks the next un-queued pull request BEHIND again, so a batch of parallel PRs needs one manual update per merge. iss-172 records the invariant that strict is never relaxed because it is what gates the merged result against a duplicate record id minted by two checkouts; that reasoning predates the queue, and the queue now gates exactly that merged result (the group commit on top of main runs every required check before anything lands), so strict adds no gate the queue does not already hold and costs the queue its entry. itd-115 promises the queue removes this toil. Directions, for the maintainer to rule: (1) set strict false in the live ruleset and the mirror, keeping the queue as the gate, and record the ruling against iss-172's invariant; (2) keep strict and automate iss-172 rung 1, an update-branch loop after arming auto-merge, which is what tonight's session runs by hand.
- iss-2609012313465609Measured on 2026-09-01 with thirteen auto-merge pull requests in flight: each one pays two full CI cycles before it lands, and the macOS check job alone takes about 13 minutes (ubuntu 9). Cycle one: the pull request is armed, main moves, the strict up-to-date policy makes it BEHIND, the keep-current script updates the branch, and the full CI re-runs on the updated head before the pull request is CLEAN enough to enter the merge queue. Cycle two: the merge queue runs the full CI again on the merge group. Every merge moves main and knocks the not-yet-queued pull requests back to cycle one, so a batch of thirteen cost roughly twenty-six 13-minute cycles serialised in ALLGREEN groups, and a one-line record change waited an hour. The maintainer asks how to speed the gates up, for example by running them locally first. Directions, none adopted: (1) local-first is already built and not wired on every account: make preflight is the pre-push gate and .githooks/pre-push runs it, but core.hooksPath is unset on at least one active account, so nothing runs before a push; wire it at ahoy install (an owned ConfigChange) and record which accounts have it; note that a local pass shortens nothing on the forge, it only stops red pushes. (2) Run the full matrix once, in the queue: on the pull_request event run the fast lane only (format, record gates, ubuntu build and test) and keep the macOS leg, the race lane and the smoke harness for the merge_group event, which already runs everything; the CI classifier that stands macOS down for docs-only changes shows the seam exists. (3) Cache the Go build and test cache across runs (actions/setup-go cache keyed on go.sum) and check whether the macOS job's 13 minutes is test time or cold-build time. (4) Let the queue batch: min_entries_to_merge_wait_minutes is 0, so each pull request tends to get its own group; a short wait lets several share one CI run. (5) The strict policy is the multiplier and was kept on 2026-09-01 (iss-2609012202237613); revisit only with the duplicate-id gate argument answered.
- itd-1Every Intent Has Acceptance Criteria; Every Audit Verifies Them
- itd-84An Intent Is Decomposed Before It Is Filed, And A Reversal Is Only Ever Flagged
- itd-92abcd tells every repo the truth about its fence
- itd-106abcd Sets Up the CI a Repo Requires, and Reports What It Did
- itd-107Autonomous Routines Assemble From One Versioned Template
- itd-114Two Agents Can Mint At The Same Instant And Never Collide
- itd-118Merged work leaves no residue: abcd-managed repos delete a PR branch on merge, and abcd tidies the stale local branch, tracking ref, and worktree
- itd-148Every change starts in its own worktree in abcd's store: the primary checkout is a read-only surface, and abcd blocks mutations there for every session but a declared coordinator
- itd-2610110940216682Every change is checked in full once, on exactly what lands
- itd-2610150602547271The facilitator's mode gates the merge