Skip to content

ci: cut the race steps back under their job limits with test-only seams - #1014

Merged
REPPL merged 9 commits into
mainfrom
chore/race-speed-lane
Oct 15, 2026
Merged

REPPL merged 9 commits into
mainfrom
chore/race-speed-lane

Conversation

@REPPL

@REPPL REPPL commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Both required check legs had reached their time limits. The ubuntu check job is capped at 30 minutes, and its race step alone took about 21. The macOS whole-module race pass is capped at 45 minutes and ran about 40. Every merge-queue entry was being cancelled: #1003 twice, #976 twice, and #1011 once, a records-only change.

The standing policy is to never raise the timeout again, so this branch cuts test time instead. It changes no timeout, no required check name and no step split.

  • Two live-tree lint tests run only the rule they count, not the whole lint config. Under race: 82s to 4s and 83s to 2s.
  • Five lifeboat tests share one plan of this repository instead of re-probing it: 255s to 92s.
  • Three launch tests share one payload render and its secret scan: 167s to 54s.
  • A linearity test whose assertions are CPU bounds, which only the plain lane checks, skips under race.
  • The run lock's wait can be shortened from tests (shortLockTimeout), and the series lock test uses it.
  • Interview's harness stand-in is built once without the race detector, cutting the package from 180s to 36s.
  • The slowest packages are named first: loop and cli in the plain step, and loop and interview added to the race lists in ci.yml, release.yml and the release template.

The only production changes are two test hooks. lockTimeout and scanBundle become package variables, and behaviour is unchanged. Every lane runs exactly the same package set as before, checked with go list.

On this machine the macOS-style race pass dropped from 1296s to 876s. The ubuntu job is estimated at about 5 minutes faster. These are local measurements; this PR's own queue run is the confirmation.

Review: an Opus and a Sonnet reviewer worked on one frozen copy, and both approved. Two low notes go to their own records. One, the tested plain-step command no longer pins its flags, is captured separately. The other is a wording fix to this record's remedy, which lands when the record is resolved. iss-2610150500162972, major, stays open until a queue run confirms the saving.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5

REPPL added 9 commits October 15, 2026 06:19
PR #1003's check (ubuntu-latest) was cancelled at the cap twice and PR
#1008's first attempt and PR #976's merge-queue entry once each, so the
cancel policy of 2026-09-28 opens a speed lane for the ubuntu leg.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
TestForbiddenSynonymsRealGlossary and
TestColdReadingDefinitionsSatisfyTheAgentContract ran the whole record-lint
configuration over this repository to count one rule's findings. Each now
keeps the committed roots and arms only the rule it counts (GL002, and
agent_contract), which reads only its own configuration, so the count is
the same; the record-lint step and make preflight still run the full set
over the live tree. A planted "epic" in the brief and a cold-reading agent
without prompt_version each still fail their test.

Under -race (back to back on one machine): 74.4s to 3.5s and 76.0s to 1.5s;
plain: 5.0s to 0.2s and 5.1s to 0.1s.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
Five tests probed this repository from scratch, and the pack test probed it
and then planned it, which probes again. Every probe of this record costs
about 40s under -race, nearly all of it the open-questions marker scan over
every file. The tests that only read the report now share one Plan of this
repository (planThisRepo), whose Coverage is the probe Plan packed from,
unchanged, and the pack test reads that plan's own coverage rather than a
second probe, so each brief file is checked against the report it was
written from. TestEverySourcePartialCarriesAReason still runs every source
over its own context.

The five tests, back to back on one machine: 254.7s to 92.1s under -race,
22.5s to 11.9s plain.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
TestPayloadTreeImplementationsResolveIdentically and
TestRenderPayloadLeavesSourceTreeUnversioned each rendered this
repository's payload, and TestRepoPayloadBinariesScanClean scanned it
again; each pass is the payload's secret scan, about 50s under -race. The
tests now share one render (renderThisRepo), which reads the committed
manifests before it renders, so the unversioned test still compares them
against the bytes that stood before the render ran, and keeps the scan its
pre-check made of ResolveBundle(root, nil), the bundle the scan test read.
scanBundle becomes a variable so the shared render can keep that scan; it
refuses unless the render scanned exactly once.

The three tests, back to back on one machine: 166.8s to 54.3s under -race,
9.7s to 3.2s plain.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
TestTheHiddenHTMLReadersStayLinear asserts two CPU bounds and nothing else,
and both are asserted in the plain lane only (raceEnabled), while the two
readers it times run on the caller's goroutine. Under -race it built two
inputs at the size cap, asserted nothing and gave the detector nothing to
watch. It now skips there and runs unchanged in the plain lane, which the
ubuntu leg runs on every event.

Under -race, back to back: 67.5s to a skip.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
lockTimeout bounds how long a mutation waits for the run's lock before it
reports contention, and a test that holds the lock to watch a waiter back
off slept through all of it: three seconds per wait, and once per retry for
a waiter that retries. It is now a variable, and shortLockTimeout sets it to
100ms for the rest of a test. TestASeriesMoveBacksOffWhileAnotherHoldsItsLock
uses it; the assertions are unchanged.

The series test, back to back: 3.4s to 0.8s under -race, 3.5s to 0.4s plain.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
go test starts packages in the order its arguments name them, four at a
time on the ubuntu runner and three on macOS. The plain Test step named
none, so internal/surface/cli (110-147s there) started about three and a
half minutes in and finished the step alone; it now names
internal/core/implement/loop and internal/surface/cli ahead of ./...
The race lists name internal/core/implement/loop (172-244s on ubuntu,
370-730s on macOS) and internal/core/interview (160-214s) after the
scanner: in import-path order both started last, and loop was still
running when the ubuntu check of PR #976's queue entry was cancelled.

Every list still resolves to exactly its pattern (go test runs a package
named twice once): TestRaceLaneBudgetIsDeclaredAndFitsItsJob holds the four
race lists (ci.yml's two, release.yml, make preflight) and the release
template TestSelfScaffoldParity mirrors, the new
TestPlainTestStepRunsTheWholeModule holds the plain step to ./..., and
TestMacOSLegRunsItsSuiteOnlyWhereItLands now accepts a plain pass that
names packages ahead of ./... No step, check name or timeout changes.

At the runner's -p 4 on one machine, with this lane's test cuts, the race
step went from 1004s to 809s; at baseline internal/core/implement/loop
started nine minutes in and finished the step.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
…looking

iss-2610142326511964 is minted on the unmerged branch chore/macos-ci-60, so
on main the prose citation names no record and record-lint's
prose_citation_resolves refuses it. Mark the line forward-looking until
that branch lands.

Refs: iss-2610150500162972
Refs: iss-2610142326511964
Assisted-by: Claude:claude-opus-5-5
The interview tests play the harness with their own test binary, re-run as
claude, once or more per turn. Under -race every start of that binary pays
the detector's set-up, about a second on a developer Mac, so the race lane
spent most of the package's time starting stubs: 2.3s a case against 0.37s
plain. Under -race stubBinary now builds the same package's test binary
without the detector, once per run, in the environment the run started
with, and puts that on PATH; it runs the same TestMain, so the stub behaves
the same, and a build that fails leaves the instrumented binary in its
place. The plain lane is unchanged.

The package under -race, back to back on one machine: 180.4s to 35.6s,
including the build.

Refs: iss-2610150500162972
Assisted-by: Claude:claude-opus-5-5
@REPPL
REPPL enabled auto-merge October 15, 2026 09:31
@REPPL
REPPL added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit 058ba43 Oct 15, 2026
13 checks passed
@REPPL
REPPL deleted the chore/race-speed-lane branch October 15, 2026 10:25
REPPL added a commit that referenced this pull request Oct 15, 2026
Brings in the CI speed lane (#1014), which brings the race steps back
under their job limits, and the stale-usage notes (#1008).

Refs: itd-2610091918433290
Refs: itd-39
Assisted-by: Claude:claude-opus-5-5
REPPL added a commit that referenced this pull request Oct 15, 2026
Brings in the CI speed lane (#1014) and the stale-usage notes (#1008).

Refs: itd-6
Assisted-by: Claude:claude-opus-5-5
REPPL added a commit that referenced this pull request Oct 15, 2026
The CI speed lane (#1014) made the lock wait injectable for tests. The
take-back test's two busy-lock cases each waited out the full lock
timeout; with shortLockTimeout they fall from about 32s to under 4s, under
race as in the plain lane, and the test still asserts the same refusal.

Refs: itd-6
Assisted-by: Claude:claude-opus-5-5
REPPL added a commit that referenced this pull request Oct 15, 2026
Brings in v0.14.2 (#1021, #1022), embargo (#1015), memory (#1003), the
RepoPrompt reviewer route (#976) and the CI speed lane (#1014), with no
conflicts.

Refs: itd-2609091034175565
Assisted-by: Claude:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant