Development record
Every change is checked in full once, on exactly what lands
Press Release
A person whose project abcd manages gets checks that are thorough and still fast. Each pull request gets the quick checks in minutes. The full suite, on every operating system the project supports, runs once per change, in the merge queue, on exactly what will land, so nothing reaches the default branch unchecked and nothing is checked three times. abcd sets this up when it prepares the repository: the workflow, a clean-up that stops runs the queue has abandoned, a queue sized to the runners the account actually has, a nightly full run in place of a run after every merge, and one test pass per platform. The person never tunes CI by hand, and a small project stops spending most of its CI time repeating itself.
Why This Matters
abcd is built for people who know what they want and are not CI engineers, which argues for more checking, not less. abcd's own repository showed what more checking costs when it is laid out naively: in the six days to 2026-10-11 it ran its full CI 300 times for 71 merged changes, once on the pull request, once or more in the merge queue, and once again after every merge, each run holding one of the account's five macOS runners for about 40 minutes. On 2026-10-11 nothing merged for five hours while queue entries waited for those runners and timed out. A person whose project abcd manages would meet the same wall sooner, with no one to diagnose it. The same safety net costs a third as much when the full suite runs once, where it matters: on the merge result.
Mechanism
We expect total CI time per merged change to fall by about half, with no change ever landing untested on any supported platform, because the merge queue already runs the full suite on the exact merge result: the pull-request run's full suite, the post-merge run and the second macOS test pass repeat work the queue run or the local preflight already did. Shown wrong if, after abcd's own CI takes this shape (iss-2610110938282654, iss-2610110938294826, iss-2610110938293273), runs per merged change do not fall, or platform defects reach the default branch that the old pull-request run would have caught.
Scope Conditions
- Holds for a repository on GitHub whose default branch is gated by a merge queue; a repository without one keeps the full suite on its pull requests, since nothing else tests the merge result.
- Holds where some runner is scarce (macOS on GitHub's free and team plans: five concurrent jobs); with no scarce runner the queue sizing is moot and the saving is the duplicate runs alone.
- Holds where every push already passes a local preflight on the developer's platform, so the pull-request run's platform pass repeats local work.
Acceptance Criteria
- Given a repository abcd prepares that gates its default branch through a merge queue, when its CI is set up, then a pull request runs the quick checks on one platform, every required check still reports a conclusion on the pull request, and the full suite runs on every supported platform in the merge queue on the merge result.
- Given the merge queue rebuilds its groups, when a superseded group's runs are still queued or running, then they are cancelled, and a run whose queue entry is still live is never cancelled.
- Given a merge to the default branch, when it lands, then no second full run starts for it, and a scheduled full run on the default branch checks it within a day and keeps the build cache warm.
- Given the account's concurrency for its scarcest runner, when the queue is configured, then it builds no more entries at once than that runner allows with room to spare, and its check timeout exceeds the full suite's measured duration.
- Given a platform whose suite runs a race-enabled pass, when the full suite runs there, then it runs one pass, not a plain pass and then a race pass.
- Given the checks abcd sets up, when the person reads them, then one page says in plain words what runs where and why, and what a queue ejection means.
SOTA
Surveyed on 2026-10-23; sources, evidence tiers and the local fit risks are in the forge, CI and merge SOTA note. The merge queue itself was surveyed under itd-115; this pass covers the CI layout around it.
- The lineage tests the merge result and re-tests behind a failure: Zuul
tests "each change applied to the tip of the branch exactly as it is going
to be merged" and re-tests the changes behind a failed one without it;
bors did the same on a staging branch and was phased out for GitHub's queue
(its page is undated and links to the July 2023 GA post); GitLab's merge
train removes a failed merge request and restarts the pipelines behind it,
but documents a job-level
retryfor jobs that fail intermittently: "If it succeeds after a retry, the merge request is not removed from the merge train". GitHub's queue has no retry of its own, so a retry there must sit inside the job. - GitHub's queue as documented: required checks must trigger on
merge_group, or "The merge will fail as the required status check will not be reported"; a queue cannot be enabled on a branch protection rule whose branch-name pattern contains a wildcard; the availability statements agree (the July 2023 changelog and GitHub's March 2024 account: public organisation-owned repositories on GitHub.com and every repository on Enterprise Cloud or Server, a personal account's public repository named in neither); build concurrency is 1 to 100; a status-check timeout and group sizes are ruleset settings; "Require all queue entries to pass required checks" decides whether a failing entry may ride a passing group; the queue "provides the same benefits as the Require branches to be up to date before merging branch protection". - A superseded group announces itself only to an App: the
merge_groupwebhook'sdestroyedaction (reason merged, dequeued or invalidated) is delivered to GitHub Apps, not to Actions, which is why a polling sweep is the Actions-only route; Actions concurrency cancels only withcancel-in-progress: trueand keeps one pending run per group. - "Light on the pull request, heavy in the queue" is a named practice: Mergify's "two-step CI" ("Run fast tests on every PR, and run expensive tests only before merge"), listed as something the native queue lacks as a built-in (vendor page). GitHub's own monorepo account reports groups of 30 and a 33% shorter wait and says nothing about trimming the pull-request run (vendor blog).
- The scarce runner is a constant: five concurrent macOS jobs on Free, Pro and Team, 50 on Enterprise; a job may run six hours.
- A nightly run keeps the cache warm within the rules: caches unused for seven days are evicted, 10 GB per repository, and a pull request can restore caches made on the default branch but not on other pull requests.
Path 1 for the queue and its triggers (the forge's merge queue,
merge_group, the ruleset's concurrency and timeout knobs, a scheduled run
for the cache), with the workflow layout as abcd's own scaffold. No Go
dependency: the forge feature is adopted as configuration, so the dependency
gate is not reached. On the open questions the evidence says: turn the
up-to-date rule off only where a queue gates the branch, since the queue
re-tests the merge result, which is the gate iss-172's invariant protects,
and refuse to turn it off anywhere else; on a platform flake the choice is
real, eject and re-queue or one in-job retry of the platform job (GitLab's
documented retry keeps a flaky merge request in its train; GitHub's queue
has no retry of its own), and re-queueing is one command either way (gh pr merge adds a pull request whose required checks have passed to the queue,
so re-queueing after an ejection is one command, an inference from the
manual, which says nothing about ejections); size build concurrency below
the macOS limit with the timeout above the measured suite. The independent
fit-challenge runs at plan time.
Open Questions
- Write the workflow, or check the person's own. The scaffold reads a managed repository's CI and never writes it (it derives check names and writes nothing hard-coded). This intent either lays down a CI workflow of its own, or checks the person's CI against the shape and says what to change.
- The up-to-date rule. Whether abcd turns off "require branches to be up to date" where a merge queue gates the default branch; the queue gives the same guarantee, and abcd's own repository kept the rule on 2026-09-01 (iss-2609012313465609 carries the measurement).
- Where a platform flake lands. Running a platform's suite only in the queue turns a flake on that platform into a queue ejection and a re-queue (iss-2610051434156079 is one); whether that cost is accepted, or the queue retries a platform job once.
- (SOTA 2026-10-23) Whether a managed repository without a merge queue (a personal account's public repository, which neither availability statement names) keeps the full suite on its pull requests, as the first scope condition says, and how the probe in itd-2610161647248332 tells the two apart.
- (SOTA 2026-10-23) Whether the superseded-group sweep stays a polling
workflow or moves to a GitHub App that receives
merge_groupdestroyed, once a managed repository has an App for other reasons (H2).
Decomposition
| Part | Kind | Home |
|---|---|---|
| A managed repository's CI runs the full suite once, in the queue | capability | this intent |
| The full suite must run on the merge result of every change before it lands | trust rule | a decision record and a brief invariant, owed before planning |
| A remedy is filed whole, built where it can be, measured where it cannot | stance | a-remedy-is-filed-whole (principle) |
| abcd's own CI takes the shape first | plumbing | iss-2610110938282654, iss-2610110938294826, iss-2610110938293273 (built on ci/full-suite-once-per-merge), iss-2610110613372021 (superseded queue runs) |
| Parts that cannot be built yet | measured records | iss-2609012313465609 (up-to-date rule), iss-2610110939547495 (raise the macOS limit), iss-2610110939559446 (receipt as a status) |
Verdict: FILE-AS-IS, the routing awaiting the product thinker's confirmation.
Audit Notes
Empty. Populated by intent-auditor when intent moves to shipped/.
Frontmatter
| id | itd-2610110940216682 |
|---|---|
| type | intent |
| lifecycle | drafts |
| severity | minor |
.abcd/development/intents/drafts/itd-2610110940216682-a-person-whose-project-abcd-manages-gets.md
open on GitHub ↗ · commit history ↗
Referenced by2
- iss-2610262042381184Both itd-115 and itd-2610110940216682 have abcd set up the merge queue when preparing a managed repositoryrelated
- iss-2610262042399506itd-106 and itd-2610110940216682 each scaffold the managed repository's CI workflow, to different shapesrelated
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-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.
- iss-2610051434156079On the v0.13.1 release PR's merge-queue run, the macOS race lane failed TestHookSubagentStopConcurrentCompletionsAllStage: 12 simultaneous subagent-stop hooks all exited 0 but only 10 transcripts were staged (internal/surface/cli/hook_subagent_stop_test.go:336). The same suite passed on the PR's own run and on every queue run earlier that day, so the loss appears only under a slow, race-instrumented host, but it is a silent loss: the hook reports success and the transcript never reaches the store. It is the defect iss-2609090828371674 resolved (the shared lock's backoff ceiling capping staging throughput), shown not to hold under load.
- iss-2610110613372021When the merge queue rebuilds its groups (an entry dropped, re-queued or re-armed), the CI runs of the superseded groups keep running and holding runners, though their gh-readonly-queue refs are deleted and nothing reads their results. On 2026-10-11 nothing merged from 03:36 to past 07:00 BST. Seven stale merge-group ci runs (PRs 903, 906, 908, 911 and 915 at older shas) held the runners while every live group's run sat queued, until a session cancelled them by hand.
- iss-2610110938282654check (macos-latest) runs on every pull request as well as on every merge-queue entry, and macOS is the account's scarcest runner, 5 jobs at once at a median 40 minutes each (8 queue runs, 2026-10-11). Between 03:36 and 08:40 on 2026-10-11 nothing merged: entries waiting for a macOS slot passed the queue's timeout and were removed. Every push already passed make preflight on a Mac, so the pull-request macOS run repeats a local run, and only the queue run tests the merged tree.
- iss-2610110938293273The macOS leg tests twice: go test ./... (median 13.6 min) and then go test -race ./internal/... (median 23.1 min), of a 39.9-min median job over 8 queue runs on 2026-10-11. The race pass already runs every internal test, so the plain pass adds only the packages outside internal/ at a third of the job's time.
- iss-2610110938294826ci.yml runs the full gate again on every push to main, though with the merge queue every commit on main is the merge result the queue already tested: 68 push runs in the 6 days to 2026-10-11 against 71 merged pull requests, each taking a macOS slot.
- iss-2610110939547495The account runs at most 5 macOS jobs at once, which is the binding limit on the merge queue: on 2026-10-11 queue entries waited for macOS slots past the check timeout and were removed. GitHub documents that support can raise concurrency limits; nobody has asked.
- iss-2610110939559446Every push already carries a local make preflight receipt that ran the same gates CI runs, but CI cannot see it, so the pull-request run repeats the work. The receipt is the pusher's word, not an attestation, and with many agents pushing that is too weak to replace the queue run; it could only spare duplicate work before the queue.
- itd-106abcd Sets Up the CI a Repo Requires, and Reports What It Did
- itd-115A Ready PR Merges Without Ever Wedging BEHIND
- itd-2610161647248332abcd finds out what the forge can do before choosing a route
- itd-2610261025516272Private repos land checked work without renting CI
- itd-2611011325421304A one-package change is checked in minutes, not the whole suite