Development record
A preflight waits for its turn as one whole run
Summary
Delivers itd-2610262127138979: make preflight waits at the load gate once, for the whole run, before any of its stages (a records-only change takes a shorter rule that waits at no gate), so a queued preflight does no lint, eval, build, vet or test work; the number allowed at once is read again at every look of a wait; and two runs reaching the gate together are ordered without waiting on each other until timeout.
Grounding (the two pre-interview reviews of 2026-10-26): today the lint gates, both eval lanes, build and vet are the recipe's prerequisites and run before the first gate (Makefile preflight target), and the first gate and the race gate are the plain form, which exits as soon as it opens, so nothing before the tests waits. WaitLoad reads the slot count once, before its polling loop (internal/core/implement/load_wait.go). The command form of the gate (implement load --wait -- <cmd>) already holds the turn for the whole command, and sessions that wrapped a whole preflight in it ran one at a time and passed at the first attempt.
Approach
- Whole-run admission. The
preflighttarget becomes a thin entry that runs the existing recipe through the gate's command form, so the waiter is the parent of the whole run and its turn holds until the run ends. The recipe's own first gate goes, because a second waiter inside a held turn can deadlock against a run queued meanwhile (traced in the review: each shut by the other until the two-hour timeout). The race gate stays inside the run for slot counts above one, judged as today, and must not count its own parent run as another preflight. The command-formturnWonpath inmachineload/queue.godecides between two runs arriving together. - The count read at every look.
PreflightSlotsis read insideWaitLoad's loop, not once before it, and the race-gate shortcut that depends on it reads the same value at the same look.cmd/test-parallelismandGoTestParallelismdivide the cores by that same value, through one reader, so the gate and-pnever disagree. A value that becomes unusable mid-wait refuses at the next look, naming the file. The report names the value and its source (config file or environment): always in--json, and on the opening line above one slot. - What is taught. The LOAD rules (
internal/core/rules/defaults/rules.json), the conventions block abcd installs (internal/core/ahoy/defaults/), the Makefile's comments and AGENTS.md say that a preflight waits as one whole run, and that the gate's command form is no longer needed aroundmake preflight.
Out of scope, recorded elsewhere: releasing a slot whose holder is idle (iss-2610262155232329); admitting on projected headroom and changing the count automatically (itd-2610262141001890, after the run record of itd-2610262140595217); the short-run lane (iss-2610260845422800).
How each criterion is met
- Three runs, one admitted, the others idle. Approach 1. Test: a Makefile-structure test asserts no stage runs before the gate's command form in the
preflighttarget, and a gate test with a fake process table of threemake preflightwaiters asserts exactly one is admitted. - A change to the number reaches waiting runs. Approach 2. Test: a
WaitLoadtest changes the configured count between looks and asserts the next look judges by it and its report names value and source; a second changes it to an unusable value and asserts the refusal names the file. - Two runs at one moment. Approach 1's
turnWonpath. Test: two waiters of different accounts with equal start times; one opens within the jitter-plus-stand-back bound and neither reaches its timeout. - A repository's number is ignored. Existing refusal kept and covered by a test that sets a load key in a repository's
.abcd/config.jsonand asserts the count is unchanged.
Footprint
- packages: internal/core/implement/load.go, internal/core/implement/load_wait.go, internal/core/implement/load_slots.go, Makefile, AGENTS.md, internal/core/machineload, cmd/test-parallelism, internal/core/rules, internal/core/ahoy
- tests: internal/core/implement/load_wait_test.go, internal/core/implement/load_slots_test.go, internal/core/machineload, cmd/test-parallelism/main_test.go
Steps
No steps listed: the spec is built as one step. To split it, list the steps in order as 1. <title>, each with - packages: and - tests: indented beneath it; - landed: <pull request or commit> marks a step that has landed.
Frontmatter
| id | spc-2610262202438999 |
|---|---|
| type | spec |
| lifecycle | closed |
.abcd/development/specs/closed/spc-2610262202438999-abcd-works-out-for-itself-how-many.md
open on GitHub ↗ · commit history ↗
References1
- itd-2610262127138979A preflight waits for its turn as one whole runimplements
mentions5
- iss-2610260845422800The load gate queues a targeted go test (one package, a few minutes) behind whole preflights in one FIFO line, so a short job starves: on 2026-10-26 an implementer's package test for the review-set lane timed out at the gate twice at the 2h limit, behind 19 waiters and 17 make preflight processes (load averages 31.5, 20.7, 40.5 at 09:44). Neither the fixed admission count (iss-2610161756384596) nor the ungated stages (iss-2610241214065079) covers the ordering: even a measured admission count keeps a short job behind every long one already queued.
- iss-2610262155232329A load-gate slot held by a run that has stopped using the machine is never released: a holder that hangs or idles keeps its slot until its own timeout, and every other waiter waits behind it (part of the remedy of iss-2610241414124940, split out of itd-2610262127138979 at its planning on 2026-10-26, because whole-run admission does not decide it). Admitting a run on the headroom it will need rather than the load at one instant (part of iss-2610241911052191) moves with it to the adaptive count, itd-2610262141001890.
- iss-2610271913060860The footprint of spc-2610262202438999 lists only Go packages, yet its Approach rewrites the Makefile's preflight target and edits AGENTS.md. A build reserves the footprint alone, so it does not hold those files, and its refusal on 2026-10-27 named only the overlap on internal/core/rules while two live reservations of the Makefile went unnoticed. Nothing compares the files a spec's Approach names with its footprint, so a build can start against a peer that is editing the same file.
- itd-2610262140595217abcd records how each preflight on a machine behaved
- itd-2610262141001890abcd adjusts how many preflights run at once from what it recorded