Development record
Private repos land checked work without renting CI
Press Release
An abcd-managed private repository lands each change after one check sized to what the change touches, run on the person's own machine, and buys hosted CI minutes only where the person chose to. While agents work, a check reruns only the tests whose inputs changed and reuses every result whose inputs are the same, whichever worktree produced it. A feature is checked in full once, as it will land, not once per step, and a change to records alone reruns only the tests that read those records. To land a change, abcd takes the default branch as it stands, tests the merge on the same machine, again only as far as the default branch's new commits reach, and merges exactly the tree it tested, one change at a time, so no pull request waits behind another for a re-run. abcd finds out what the repository's plan allows (a merge queue, required checks, or nothing at all), says plainly what enforces the check and what does not, and shows what each hosted run would cost per landing before the person picks one. A contribution from anyone but the person and their own agents still runs in hosted CI.
"My repositories are private, my laptop has ten cores, and I was paying a cloud runner to repeat what my agents had just run," said Alice, a solo founder. "Now the agents check their own work on my machine, a change to one package tests that package, and the only minutes I buy are for the one Linux run I asked for."
Why This Matters
abcd's own repository is the one repository abcd manages with the whole regime (a preflight, a push receipt, a merge queue), and it shows where the time goes (research note, "What abcd's own repository measures"):
- One preflight runs for about 24 minutes, and the wait at the machine's load gate before it took 37 to 62 minutes, with about 20 waiters across seven sessions on 2026-10-16 (iss-2610161639025702).
- Every lane starts with a cold cache. A fresh worktree's first preflight reused 0 of about 110 packages' test results, and a rerun in the same worktree reused 47 to 88, because the go command keys a build on the package's directory unless
-trimpathis set. - Every reviewed step of a feature pays its own full run, and a change to records alone pays the same as a change to code.
- The hosted pull-request run repeats the local preflight (iss-2610110939559446), and the queue then runs again, 1.27 times per merged pull request, with the macOS leg dropping entries at its 45-minute cap (iss-2609012313465609).
The record has owed this intent since 2026-09-29: iss-2609012313465609 was deferred on the ruling that an intent should choose among its directions, starting with which comes first.
In a private repository the same habits cost money, and the route abcd planned is closed:
- Hosted minutes beyond the plan's 2,000 (Free) or 3,000 (Pro, Team) a month cost $0.006 a minute on Linux and $0.062 on macOS, so a macOS minute costs about ten Linux minutes.
- GitHub's merge queue, the route itd-115 configures, exists for a private repository only when its organization is on Enterprise Cloud. A personal account or a Team organization has no queue.
- Rulesets, and with them required checks, need Pro or Team for a private repository. On GitHub Free nothing on the forge enforces a check at all.
- Nothing abcd installs gives a managed repository a preflight, a receipt or a CI check workflow:
ahoyinstalls four commit hooks, andlaunch scaffoldwrites the release workflows.
Two drafts already hold parts of this, and neither reaches that repository. itd-115 configures GitHub's merge queue by default, with a fallback that polls and updates a branch left behind. itd-2610110940216682 runs the full hosted suite once per change in the queue, and by its own scope condition a repository without a queue keeps the full suite on its pull requests. Neither makes a local check cheaper, and neither serves a private repository without a queue, which is most of the repositories abcd manages.
Local CI with a commit status, the gh-signoff pattern that Rails 8.1 made a framework default, answers the cost for a single developer: the laptop runs the suite and tells the forge so. It leaves two things to answer: an agent's sign-off is the agent's word, and a branch tested alone is not its merge.
Mechanism
We expect the local check per landing to cost in proportion to what a change touches, and the hosted minutes per landing to fall to none, or to the one Linux run the person chose, because three costs paid on every landing today can be avoided. Results whose inputs are byte-identical are rerun only because the cache key carries the worktree's directory. A feature's steps each pay a full run that one check of the landing tree covers. And the merge, the one thing a branch's own run cannot prove, is tested in hosted CI after a local run whose result a status could have carried. Shown wrong if, over a measured run of at least twenty landings in one private managed repository and twenty in abcd's own, the local check time per landing, the wait before it or the hosted minutes per landing is not lower than the 2026-10 baseline in the research note; or if a landed tree ever differs from the tree its check ran on; or if the release cut's run without reuse finds a defect that a reused result had passed; or if escapes, hosted failures a check run before the push would have caught, do not fall from the 13 of 32 failed runs of 2026-10-18 to 2026-10-26 (dcn-2610261152329451).
Scope Conditions
- Holds for repositories whose pushers are the person and the agents working under the person's identity. A contribution from anyone else runs the full hosted check.
- Holds for GitHub at the plan tiers its documentation states on 2026-10-26: a merge queue for organization-owned public repositories and for private repositories on Enterprise Cloud only, and rulesets on private repositories from Pro and Team up. Another forge reaches the same routes through the forge seam.
- Holds for tests that are deterministic given their inputs. A flaky test breaks reuse and selection alike, and is a defect to fix, not a reason to rerun everything.
- Holds where the person's machine runs the repository's full check in tens of minutes, not hours, under the machine's load gate.
- Holds where the person's own operating system is one the project ships to. Another operating system is covered by a hosted run the person chooses, or by the nightly and release runs.
Acceptance Criteria
- The reuse of unchanged test results on the person's machine, the tests that always rerun, and the record-only rerun are moved to itd-2611011325421304 (2026-11-01), which refines this intent; this intent keeps the landing route.
- Given a check that ran only a part of the gates, as an agent's quick check of one step does, when anyone lands the branch, then the landing is refused, naming the gates the check left out; only a check that covered every gate on the landing tree, each run or reused, lets it land.
- Given a feature built in several reviewed steps, when it lands, then it lands as one change with one landing check, and each step in between was checked with reuse rather than with a full run.
- Given a private repository with no merge queue and two branches ready to land, when abcd lands them, then it lands one at a time, each tested merged onto the default branch as it stands at that moment, and the tree that reaches the default branch is the tree that check ran on.
- Given the default branch moves between a branch's landing check and its merge, when abcd merges, then the stale merge is refused, and abcd tests the merge again, rerunning only what the new commits on the default branch reach.
- Given landings started from two computers at once, when both reach their merge, then they land one at a time, ordered by a hold on the shared remote, and neither lands an untested merge.
- Given a repository whose plan allows rulesets, when a landing check passes, then abcd records it on the tested commit as a status the ruleset requires; and given a plan that allows no rulesets, then abcd says plainly that nothing on the forge enforces the check and the local hooks are the whole fence.
- Given a repository that runs hosted CI and a pull request whose head carries a passed landing check, when the pull request is opened or updated, then the hosted pull-request run does no work beyond confirming that status.
- Given a pull request from anyone but the person and their agents, when it is opened, then the full hosted check runs on a hosted runner, a status its author posts is not accepted in place of it, and no self-hosted runner runs its code.
- Given abcd sets up a managed repository, when it offers the landing routes the plan allows, then each route states the hosted minutes and their price per landing at the published rates, with the date those rates were read, and states what the forge enforces under it.
- Given a private repository, when abcd sets up its hosted runs, then no macOS run is placed on every landing unless the person chooses it with its price shown; macOS runs nightly and at the release cut instead.
- Given a hosted run that fails, when abcd reads it, then it names the check that failed and whether that check could have run before the push (an escape), and given the failures since a stated date, then it counts escapes per check and names, for each check with any, the earliest local point that sees its input (the commit, the posted text, the landing, or the preflight before its test stages).
- Given the baseline in the research note, when this intent ships, then a measured run of at least twenty landings reports the local check time, the wait before it and the hosted minutes per landing against that baseline.
SOTA
Surveyed 2026-10-26 against primary sources (research note):
- Local CI with a commit status (gh-signoff; Rails 8.1
bin/ci): usable, and a framework default since Rails 8.1. Adopted as the pattern: the local result is posted as a status a ruleset can require. Not adopted as a dependency: posting a status is one forge call abcd makes itself. - The not-rocket-science rule and its queues (bors, Jane Street, GitHub's merge queue): mature. Adopted: test the merge before the default branch moves, one landing at a time, with fewer and larger landings. GitHub's queue is used where the plan offers it; where it does not, abcd runs the queue on the person's machine.
- Selection by dependency (Pants
--changed-dependents, Nx affected): mature inside their build systems, each a toolchain a repository would have to adopt. Not adopted now. The seam is the declared gate list's inputs, which a repository already on one of them can fill from it. - Reuse of results whose inputs are unchanged (Go's test cache; build-system caches;
GOCACHEPROG): mature. Adopted as the first lever: Go's own cache, shared across worktrees by-trimpathfor tests whose test log names no path inside the module (no open, stat, lstat or chdir of one); tests that read the tree share it once the test stages run from the fixed check directory itd-2611011325421304 settled on 2026-11-02 (~/.abcd.noindex/tests/<root-sha>/), with the tests whose inputs it cannot see declared. A cache shared between machines is a later backend behindGOCACHEPROG. - Learned test selection (Meta's predictive test selection): mature at Meta's scale, and needs a change history one repository lacks. Not adopted.
- Self-hosted runners: mature, free today with a postponed fee, and unsafe for code from outside contributors. Offered only as a route for the person's own changes.
Path taken: 2. A native floor (the declared gate list and its inputs, the receipt posted as a status, the local landing queue, reuse across worktrees) with seams for the field's backends: a forge merge queue where the plan offers one, and a dependency selector or a shared cache where a repository already runs one. No new dependency. The independent fit challenge runs at planning, with the collisions the research note lists.
Decomposition (itd-84 hand-run, 2026-10-26)
Confirmed by the product thinker on 2026-10-26 (decision 1 below). Verdict: SPLIT.
| Part | Type | Home |
|---|---|---|
| How a managed repository's changes are checked and landed: reuse, one check per landing, the local queue, the status, the route and its price | capability | this intent |
| A self-reported local result may replace duplicate hosted work, and may gate a landing, only for the person's and their agents' changes; it never gates an outside contribution, and a release cut never reuses a result | trust rule | an ADR at planning, then a brief invariant |
| Each check runs once, where it is cheapest to trust | stance | a principle at planning |
The gate list's schema, the receipt's fields, -trimpath, the declared tests |
plumbing | the spec and the brief |
Typed links, as confirmed:
supersedesitd-115: its want, a ready pull request that never waits behind another, is met here on every plan, through GitHub's queue where the plan has one and through the local queue elsewhere, which replaces its poll-and-update fallback.- itd-2610110940216682 stays the shape of hosted CI where a queue gates the default branch, as a sibling with no typed link. This intent's pull-request criterion (no work beyond confirming a passed landing check) tightens that draft's first criterion (the quick checks on one platform), flagged for the product thinker as a refinement of it, not a reversal.
refinesitd-106: that intent sets up which checks a repository has; this one decides where each runs and how a landing uses them.builds_onitd-2610161647248332: the route is chosen from what the forge can do, which that intent finds out.- The issues it answers, joined from both ends: iss-2609012313465609 (the intent that issue's deferral says is owed), iss-2610110939559446 (the receipt as a status) and iss-172 (pull-request queue hygiene in managed repositories). iss-2610161639025702 (preflight throughput) is answered here too, but is already promoted to itd-2610170634394993, so it is cited rather than joined.
No reversal flag. iss-172's invariant protects testing the merge before the default branch moves, and every route here still does that. The strict up-to-date setting stays on wherever the plan allows it; where the plan allows no rulesets, the local queue's own refusal of a stale merge does that job.
Open Questions
- The default route for a private repository with rulesets. The local queue with its self-reported status, which spends no hosted minutes, or the local queue plus one hosted Linux run of the merge per landing, which is an independent check at about $0.006 a minute. Either way the person sees both prices at setup.
- Who counts as the person's own. The person's identity and the agents working under it only, or every collaborator with write access.
- The self-hosted runner route. Offer it for the person's own changes, since it gives a check that the pushing agent does not run itself and costs no minutes, or leave it out, since it shares the machine and the load gate with the local checks.
- abcd's own repository. It is public, so its minutes are free and its queue gives an independent check of every merge. Keep the queue and adopt only reuse and one check per landing, or move it to the local queue too.
Decisions
- The routing is confirmed as proposed (2026-10-26). The product thinker accepted the split and the typed links with a plain yes, given the agent's recommendation. This intent holds the capability alone. The trust rule (a self-reported local result may replace duplicate hosted work and gate a landing only for the person's and their agents' changes, never an outside contribution, and a release cut never reuses a result) becomes an ADR at planning, then a brief invariant. The stance that each check runs once, where it is cheapest to trust, becomes a principle at planning. itd-115 is superseded by this intent, the link to itd-106 is a refinement, and itd-2610161647248332 is a builds-on edge. The graded table is in the decomposition-calibration note under this date.
- Escapes are recorded and the fixes are not bundled (2026-10-26). Asked whether to record what wastes hosted runs, the product thinker accepted the recommendation: the recording, counting each hosted failure a check run before the push would have caught, is a criterion of this intent, and the fixes for the escapes found so far are issues worked first, outside it (dcn-2610261152329451): iss-2609061525437969, iss-220, iss-2610241424265464, iss-2610261151381604, iss-2610261151481013 and iss-2610261152125261.
Audit Notes
Empty. Populated by intent-auditor when intent moves to shipped/.
Frontmatter
| id | itd-2610261025516272 |
|---|---|
| type | intent |
| lifecycle | drafts |
| severity | minor |
.abcd/development/intents/drafts/itd-2610261025516272-an-abcd-managed-private-repository-lands.md
open on GitHub ↗ · commit history ↗
References2
- itd-115A Ready PR Merges Without Ever Wedging BEHINDsupersedes
- itd-2610161647248332abcd finds out what the forge can do before choosing a routebuilds on
Referenced by4
- adr-2611011327164895A self-attested result is labelled as such, and only the person switches it on, by an act abcd's own verbs refuse to its agentsrelated
- 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.related
- 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.related
- 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.related
mentions16
- dcn-26102611523294512026-10-26 — The product thinker adopted the remedies of iss-2609061525437969 (narrowed to pull-request bodies), iss-220 (its compose half only) and iss-2610241424265464, and asked for them and the newly filed iss-2610261151381604, iss-2610261151481013 and iss-2610261152125261 to be built first. Grounds: of 32 failed hosted CI runs between 2026-10-18 and 2026-10-26, 13 were deterministic checks that could have run before the push (a pull-request body without its Assisted-by line 7, an undeclared issue id on the pull-request form 4, gitleaks 2), and 10 more were one govulncheck finding that stood on the default branch itself. Each check moves to the earliest local point that sees its input: the commit-msg hook, the shell guard before gh pr create, abcd land's composed body, or the preflight before its test stages.
- dcn-26110120490462592026-11-01 — With the drain wound down on 2026-11-01, three streams of work start in parallel: the terminal drain (itd-2610222215485265) in this session, the load work (itd-2610262140595217, itd-2610262141001890 and the memory floor) with Eve, and the CI work (itd-2610261025516272 and its new drafts) with Henry. While the subscription's weekly budget is near its limit, every agent a build or drain hands out runs on the person's API key through the claude runner, never as a host subagent; only the driving sessions stay on the subscription.
- iss-220simple deterministic CI failures have no compose-time prevention or self-repair path: the attribution gate detects a missing PR-body Assisted-by trailer post-hoc (PR 230), but nothing composes or verifies the body at creation time and no loop is authorised to apply the mechanical fix. PR-body composition is facilitator-owned manual work and therefore automation backlog: abcd should compose/verify the PR surfaces it requires for managed repos, and an allowlisted class of deterministic check failures (trailer append, formatting) should be self-repairing
- iss-2609061525437969The AI-assistance disclosure convention covers commits only: the COMMITTING rule requires an Assisted-by trailer on AI-assisted commits, but says nothing about pull-request descriptions or issue text, and nothing checks either. In a managed repo two PRs went out with the trailer on every commit and none on the PR body, which the maintainer read as an oversight. Extend the convention to PR descriptions (and issue text written by an agent), teach the guard's GitHub-CLI coverage to require the trailer there, and make the same guard refuse session links and other tool footers — the two halves of one disclosure rule: say a tool assisted, never link the session.
- iss-2610161639025702Preflight throughput sets the pace of all work on this machine, and nothing keeps it in bounds. On 2026-10-16 the load gate admitted one make preflight at a time, each took about 40 minutes, and about 20 waiters were queued across seven sessions. Every reviewed branch had its own preflight, so a seven-step feature needed seven full runs, and records-only branches paid the same full cost as code. Sessions waited hours, and the queue's ordering after the reboot starved late waiters (fixed separately on fix/load-queue-start-order). No rule tells sessions to batch work, and no part of preflight scales its cost to what a change touches.
- iss-2610241424265464A commit message that names an issue id without a Refs: or Resolves: line passes the commit-msg hook and is refused only by lint-issues RS004 inside make preflight. On 2026-10-24 that cost a whole preflight run (tens of minutes under the load gate) for a one-line amend, on a machine where preflight capacity was the scarce resource.
- iss-2610261151381604make preflight does not run the two hosted scans CI runs on every pull request, gitleaks over the commits the pull request would land and govulncheck over the module, so a finding either of them makes is found only after the push, in a hosted run. Between 2026-10-18 and 2026-10-26 they failed 12 of 32 failed CI runs: govulncheck 10 (one newly published standard-library vulnerability, on every pull request and queue entry from 2026-10-21 until the toolchain moved to go1.26.10 on 2026-10-22) and gitleaks 2.
- iss-2610261151481013When the default branch itself fails a hosted check, every branch pushed meanwhile pays a hosted run that is certain to fail, and nothing local says so before the push. From 2026-10-21 to 2026-10-22 a newly published Go standard-library vulnerability failed govulncheck on the nightly run and then on every pull request and queue entry, 10 runs, for about a day and a half, until the toolchain bump landed. A branch that changed neither go.mod nor go.sum could not have introduced it, and its author could have been told to land the bump first.
- iss-2610261152125261RS004 on the pull-request form, every issue id the title and body name declared on a Refs: or Resolves: line, is checked only by the hosted attribution workflow, although the title and body exist before gh pr create runs and the shell guard already reads them for the outbound policy. Between 2026-10-18 and 2026-10-26 it failed 4 pull-request runs, each fixed by adding one line to the body.
- itd-84An Intent Is Decomposed Before It Is Filed, And A Reversal Is Only Ever Flagged
- itd-106abcd Sets Up the CI a Repo Requires, and Reports What It Did
- itd-2610110940216682Every change is checked in full once, on exactly what lands
- itd-2610170634394993Headless agents in parallel coordinate through the shared remote, not conversation
- itd-2611011325421304A one-package change is checked in minutes, not the whole suite
- itd-2611011325428560A solo private repo can self-attest its gates, labelled so
- itd-2611011325430933A machine the person owns checks agents' work independently