ci: cut lint, unit-tests and race-bifrost wall time (direct golangci-lint, test cache, slow-test fixes)

Cuts the wall time of lint, unit-tests and unit-tests-race-bifrost.

Results

Pipeline 2924459745 on this branch, against CI p50 on 2026-10-02..07:

Job Before (p50) This branch
lint (MR) 6.7 min 1.0 min
lint --all (merge trains, develop, go.mod changes: 23% of lint jobs) 23 min (p90 33) ~1 min warm, ~4 min cold analysis cache
unit-tests, first run of a commit 7.4 min 4.3 min
unit-tests, re-run / re-push 7.4 min 0.8 min
unit-tests-race-bifrost 5.6 min 3.0 min

The race job's first attempt failed on TestFetchTxsFiltersReceiptsToVaults (tron, context deadline exceeded against its mock server). That test also failed the race job on !5125 (merged) on 2026-10-07 without these changes; the retry passed.

Changes

Lint

  • golangci-lint runs once over ./... (scripts/golangci-ci.sh) at the version .trunk/trunk.yaml pins. trunk's plugin ran one golangci-lint process per package directory with --concurrency 1, so each directory type-checked its dependencies again.
  • trunk runs every other linter with --all (~30s), concurrently with lint.sh and golangci-lint. There's no upstream diff: develop passes the same check, so any issue on an MR is the branch's.
  • The job keeps the default shallow clone (the full one took 44s p50, 148s p90). lint-tokens.bash fetches develop's tip itself.
  • The 18 trunk-ignore(golangci-lint/...) comments become //nolint, which trunk and a direct run both honor.
  • Parity check on injected violations: the direct run found everything trunk found, plus an unused function in x/thorchain and everything in bifrost/observer, where golangci-lint failed to load export data inside trunk's sandbox.

Unit and race tests

  • Sleep-bound tests:
    • Bridge retry backoff in the mainnet-tag utxo tests (57s → 13s).
    • The seed-phrase test re-runs its own test binary instead of building thornode (20s → 1s).
    • TSS keyshare encryption runs at a lower scrypt work factor in that package's tests only (35s → 13s; 143s → 24s under -race). Production stays at AgeWorkFactor = 18, and a test asserts that.
    • The oracle websocket settle wait is 0 in tests (30s → 15s).
  • Four test-only commits are cherry-picked from draft !5164 (merged) (config retry waits, bridge retry backoff, p2p bootstrap wait, eth approval wait). Drop them here if !5164 (merged) lands first.
  • test-network-specific runs alongside the main suite instead of before it. The main suite's output still streams.
  • scripts/ci-stable-mtimes.sh gives each tracked file an mtime derived from its git blob id, so go test reuses cached results across CI jobs. A fresh clone otherwise invalidates every package that reads a file. Used by unit-tests, unit-tests-race-bifrost, xmr-e2e-gates and go-tss.

Measured and not kept

With the slow tests fixed, the unit job is CPU-bound in a 6-CPU slot (link ~245s plus test runs ~336s of action time). -p 12, -vet=off, -ldflags=-w and dropping coverage made no difference.

Follow-ups (not in this MR)

  • Each runner slot has its own GOCACHE volume, which limits the test cache hit rate. A shared host bind mount, like /trunk-cache, would help.
  • Remaining long poles under -race: utxo (95s on CI), observer (62s).

🤖 Generated with Claude Code

Merge request reports

Loading
Loading