Skip to content

ci: PR-feedback quick wins — auto-cancel, drop dead job, restore module cache#986

Merged
oskarszoon merged 4 commits into
bsv-blockchain:mainfrom
oskarszoon:ci-speed/phase-1-quick-wins
May 29, 2026
Merged

ci: PR-feedback quick wins — auto-cancel, drop dead job, restore module cache#986
oskarszoon merged 4 commits into
bsv-blockchain:mainfrom
oskarszoon:ci-speed/phase-1-quick-wins

Conversation

@oskarszoon

Copy link
Copy Markdown
Contributor

First of three phases from a CI-speed investigation. The PR-feedback gate has drifted up over the last quarter (pr-smoke +33% in 9 weeks, main-build +19%); these are the low-risk, broad-benefit changes that don't touch test behaviour.

Changes

Auto-cancel superseded runs. Added a concurrency group with cancel-in-progress: true to the PR-triggered gate workflows (teranode_pr_tests, teranode_pr_smoketests, teranode_pr_init, dashboard_pr_smoke) and to sonar-pr-analyze (keyed on the originating PR, since it's workflow_run-triggered). Pushing a new commit to a PR now cancels the prior in-flight run instead of running both to completion — less runner saturation, less queue time on busy days. Not applied to main/push workflows. benchmark-compare is deliberately excluded: cancelling a partial benchmark run would drop comparison results.

Removed the no-op sequential-sqlite job. It had no run step — it checked out, set up Go, and uploaded a results file that was never produced. Zero coverage behind an always-green check. Confirmed separately that the --db sqlite name filter matches zero tests, so it ran nothing regardless. Not a required status check.

Restored a Go module cache. actions/cache on ~/go/pkg/mod only (keyed on go.sum) for the compile-heavy jobs in teranode_pr_tests and teranode_main_tests. Deliberately NOT the build cache (~/.cache/go-build) — that is what #3352 disabled, for thrashing the 10 GB Actions cache limit with large -race build artifacts. The module cache is small and stable, and setup-go's own caching stays off.

Risk

Low — config only. The module cache reverts cleanly if it regresses. Validated with actionlint (only pre-existing custom-runner-label warnings).

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

Status: Complete


Summary

This PR implements low-risk CI optimizations to reduce PR feedback time. The changes are configuration-only and well-reasoned.

Key Changes:

  • Auto-cancels superseded PR workflow runs (reduces runner saturation)
  • Removes the no-op sequential-sqlite job (verified: no tests match --db sqlite)
  • Restores Go module cache on compile-heavy jobs (deliberately NOT the build cache)

Analysis:

Concurrency configuration: Correctly applied to PR-triggered workflows with appropriate grouping keys. The sonar workflow uses a fallback pattern to handle both regular and fork PRs.

Benchmark exclusion: Confirmed that benchmark-compare was deliberately excluded in commit 967b3af to preserve result integrity.

Dead job removal: Verified that sequential-sqlite had no run steps and would match zero tests (no test functions containing 'sqlite' in the sequential test directory).

Cache strategy: Module cache (~/go/pkg/mod) only, avoiding the build cache that previously hit the 10 GB Actions limit. All cache configurations are consistent across workflows.

Security: All action versions pinned to commit SHAs.

Observations:

The sonar-pr-analyze concurrency group expression at .github/workflows/sonar-pr-analyze.yaml:21 uses a fallback pattern that handles both cases (PR number when available, branch name as fallback), which is correct for workflow_run triggers that may have empty pull_requests arrays for fork PRs.

Verdict: No issues found. Changes align with stated goals and follow best practices.

@oskarszoon oskarszoon requested review from icellan, ordishs and sugh01 May 29, 2026 14:57
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-986 (70f487a)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 144
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.272µ 1.229µ ~ 0.700
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 54.94n 55.00n ~ 0.400
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 54.95n 55.04n ~ 0.800
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 54.95n 54.99n ~ 1.000
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 25.25n 25.43n ~ 0.700
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 42.43n 42.63n ~ 0.400
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 96.29n 95.94n ~ 0.400
MiningCandidate_Stringify_Short-4 167.5n 168.5n ~ 0.300
MiningCandidate_Stringify_Long-4 1.276µ 1.254µ ~ 0.100
MiningSolution_Stringify-4 662.9n 645.1n ~ 0.100
BlockInfo_MarshalJSON-4 1.331µ 1.336µ ~ 0.400
NewFromBytes-4 124.3n 124.0n ~ 0.700
AddTxBatchColumnar_Validation-4 2.666µ 2.528µ ~ 1.000
OffsetValidationLoop-4 543.5n 544.7n ~ 0.700
Mine_EasyDifficulty-4 61.08µ 61.59µ ~ 1.000
Mine_WithAddress-4 7.092µ 6.978µ ~ 0.100
DiskTxMap_SetIfNotExists-4 3.481µ 3.512µ ~ 0.400
DiskTxMap_SetIfNotExists_Parallel-4 3.293µ 3.193µ ~ 0.200
DiskTxMap_ExistenceOnly-4 308.4n 307.7n ~ 1.000
Queue-4 188.7n 189.5n ~ 0.300
AtomicPointer-4 4.903n 4.932n ~ 0.700
ReorgOptimizations/DedupFilterPipeline/Old/10K-4 906.4µ 866.5µ ~ 0.400
ReorgOptimizations/DedupFilterPipeline/New/10K-4 814.7µ 790.1µ ~ 0.100
ReorgOptimizations/AllMarkFalse/Old/10K-4 108.2µ 107.5µ ~ 0.400
ReorgOptimizations/AllMarkFalse/New/10K-4 61.89µ 61.75µ ~ 0.700
ReorgOptimizations/HashSlicePool/Old/10K-4 55.30µ 65.87µ ~ 0.100
ReorgOptimizations/HashSlicePool/New/10K-4 11.79µ 11.92µ ~ 0.400
ReorgOptimizations/NodeFlags/Old/10K-4 4.588µ 4.715µ ~ 0.100
ReorgOptimizations/NodeFlags/New/10K-4 1.589µ 1.587µ ~ 1.000
ReorgOptimizations/DedupFilterPipeline/Old/100K-4 9.400m 9.253m ~ 0.400
ReorgOptimizations/DedupFilterPipeline/New/100K-4 9.530m 9.594m ~ 1.000
ReorgOptimizations/AllMarkFalse/Old/100K-4 1.069m 1.072m ~ 1.000
ReorgOptimizations/AllMarkFalse/New/100K-4 682.5µ 683.4µ ~ 0.700
ReorgOptimizations/HashSlicePool/Old/100K-4 594.1µ 709.2µ ~ 0.100
ReorgOptimizations/HashSlicePool/New/100K-4 297.0µ 306.1µ ~ 0.100
ReorgOptimizations/NodeFlags/Old/100K-4 50.24µ 50.53µ ~ 0.700
ReorgOptimizations/NodeFlags/New/100K-4 17.52µ 18.14µ ~ 0.100
TxMapSetIfNotExists-4 52.24n 52.02n ~ 1.000
TxMapSetIfNotExistsDuplicate-4 40.40n 40.26n ~ 0.400
ChannelSendReceive-4 596.9n 611.8n ~ 0.100
BlockAssembler_AddTx-4 0.02780n 0.02735n ~ 1.000
AddNode-4 11.79 11.17 ~ 0.100
AddNodeWithMap-4 12.55 11.23 ~ 0.100
DirectSubtreeAdd/4_per_subtree-4 58.73n 59.11n ~ 1.000
DirectSubtreeAdd/64_per_subtree-4 28.87n 32.76n ~ 0.100
DirectSubtreeAdd/256_per_subtree-4 27.76n 27.95n ~ 0.300
DirectSubtreeAdd/1024_per_subtree-4 26.46n 26.58n ~ 0.100
DirectSubtreeAdd/2048_per_subtree-4 26.13n 26.10n ~ 0.800
SubtreeProcessorAdd/4_per_subtree-4 288.8n 292.5n ~ 0.300
SubtreeProcessorAdd/64_per_subtree-4 287.7n 288.9n ~ 1.000
SubtreeProcessorAdd/256_per_subtree-4 282.0n 292.5n ~ 0.200
SubtreeProcessorAdd/1024_per_subtree-4 273.8n 282.1n ~ 0.100
SubtreeProcessorAdd/2048_per_subtree-4 275.8n 280.8n ~ 0.100
SubtreeProcessorRotate/4_per_subtree-4 281.7n 280.9n ~ 0.700
SubtreeProcessorRotate/64_per_subtree-4 278.4n 276.9n ~ 0.700
SubtreeProcessorRotate/256_per_subtree-4 279.1n 279.4n ~ 1.000
SubtreeProcessorRotate/1024_per_subtree-4 278.5n 277.5n ~ 0.300
SubtreeNodeAddOnly/4_per_subtree-4 55.50n 54.84n ~ 0.100
SubtreeNodeAddOnly/64_per_subtree-4 36.11n 36.02n ~ 0.100
SubtreeNodeAddOnly/256_per_subtree-4 35.11n 35.03n ~ 0.400
SubtreeNodeAddOnly/1024_per_subtree-4 34.50n 34.43n ~ 0.200
SubtreeCreationOnly/4_per_subtree-4 110.1n 109.9n ~ 0.500
SubtreeCreationOnly/64_per_subtree-4 345.8n 348.2n ~ 1.000
SubtreeCreationOnly/256_per_subtree-4 1.221µ 1.226µ ~ 0.500
SubtreeCreationOnly/1024_per_subtree-4 3.818µ 3.784µ ~ 0.400
SubtreeCreationOnly/2048_per_subtree-4 6.702µ 6.797µ ~ 0.100
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 280.2n 276.8n ~ 0.100
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 279.4n 277.2n ~ 0.400
ParallelGetAndSetIfNotExists/1k_nodes-4 2.014m 2.007m ~ 0.200
ParallelGetAndSetIfNotExists/10k_nodes-4 5.385m 5.257m ~ 0.100
ParallelGetAndSetIfNotExists/50k_nodes-4 7.421m 7.366m ~ 0.700
ParallelGetAndSetIfNotExists/100k_nodes-4 10.04m 10.10m ~ 0.700
SequentialGetAndSetIfNotExists/1k_nodes-4 1.793m 1.757m ~ 0.100
SequentialGetAndSetIfNotExists/10k_nodes-4 4.437m 4.419m ~ 0.700
SequentialGetAndSetIfNotExists/50k_nodes-4 13.38m 13.39m ~ 1.000
SequentialGetAndSetIfNotExists/100k_nodes-4 24.76m 24.81m ~ 0.700
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 2.076m 2.037m ~ 0.200
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 8.569m 8.471m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 13.89m 13.07m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 1.797m 1.791m ~ 0.400
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 8.164m 8.020m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 44.06m 43.63m ~ 0.100
CalcBlockWork-4 474.8n 470.9n ~ 0.200
CalculateWork-4 650.2n 647.9n ~ 0.700
BuildBlockLocatorString_Helpers/Size_10-4 1.354µ 1.359µ ~ 1.000
BuildBlockLocatorString_Helpers/Size_100-4 15.58µ 16.09µ ~ 1.000
BuildBlockLocatorString_Helpers/Size_1000-4 129.0µ 128.2µ ~ 0.100
CatchupWithHeaderCache-4 104.4m 104.4m ~ 0.400
_prepareTxsPerLevel-4 412.9m 415.6m ~ 1.000
_prepareTxsPerLevelOrdered-4 3.681m 3.779m ~ 0.700
_prepareTxsPerLevel_Comparison/Original-4 422.4m 413.1m ~ 0.400
_prepareTxsPerLevel_Comparison/Optimized-4 3.642m 3.839m ~ 0.400
_BufferPoolAllocation/16KB-4 4.094µ 3.907µ ~ 0.700
_BufferPoolAllocation/32KB-4 10.790µ 8.900µ ~ 0.400
_BufferPoolAllocation/64KB-4 18.88µ 17.18µ ~ 0.100
_BufferPoolAllocation/128KB-4 37.46µ 33.52µ ~ 0.100
_BufferPoolAllocation/512KB-4 131.7µ 121.0µ ~ 0.100
_BufferPoolConcurrent/32KB-4 22.94µ 19.46µ ~ 0.100
_BufferPoolConcurrent/64KB-4 31.91µ 30.06µ ~ 0.200
_BufferPoolConcurrent/512KB-4 151.9µ 152.0µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/16KB-4 683.3µ 694.5µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/32KB-4 679.3µ 724.0µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/64KB-4 688.1µ 679.8µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/128KB-4 688.5µ 747.5µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/512KB-4 671.2µ 652.7µ ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/16KB-4 37.59m 37.42m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/32KB-4 37.72m 37.44m ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/64KB-4 37.68m 37.83m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/128KB-4 37.68m 37.19m ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/512KB-4 37.28m 37.10m ~ 0.100
_PooledVsNonPooled/Pooled-4 831.9n 833.0n ~ 1.000
_PooledVsNonPooled/NonPooled-4 9.031µ 8.313µ ~ 0.200
_MemoryFootprint/Current_512KB_32concurrent-4 7.424µ 8.288µ ~ 0.100
_MemoryFootprint/Proposed_32KB_32concurrent-4 9.559µ 10.865µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 9.375µ 10.549µ ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.314m 1.292m ~ 0.400
SubtreeSizes/10k_tx_16_per_subtree-4 308.5µ 302.4µ ~ 0.100
SubtreeSizes/10k_tx_64_per_subtree-4 74.18µ 72.92µ ~ 0.200
SubtreeSizes/10k_tx_256_per_subtree-4 18.24µ 18.12µ ~ 0.400
SubtreeSizes/10k_tx_512_per_subtree-4 8.913µ 8.950µ ~ 0.700
SubtreeSizes/10k_tx_1024_per_subtree-4 4.379µ 4.488µ ~ 0.200
SubtreeSizes/10k_tx_2k_per_subtree-4 2.194µ 2.227µ ~ 0.400
BlockSizeScaling/10k_tx_64_per_subtree-4 71.90µ 70.70µ ~ 0.700
BlockSizeScaling/10k_tx_256_per_subtree-4 17.61µ 17.87µ ~ 0.100
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.429µ 4.464µ ~ 0.400
BlockSizeScaling/50k_tx_64_per_subtree-4 364.1µ 378.1µ ~ 0.200
BlockSizeScaling/50k_tx_256_per_subtree-4 87.94µ 90.23µ ~ 0.100
BlockSizeScaling/50k_tx_1024_per_subtree-4 21.72µ 21.96µ ~ 0.700
SubtreeAllocations/small_subtrees_exists_check-4 150.6µ 150.5µ ~ 1.000
SubtreeAllocations/small_subtrees_data_fetch-4 160.4µ 159.4µ ~ 0.400
SubtreeAllocations/small_subtrees_full_validation-4 313.3µ 312.3µ ~ 0.700
SubtreeAllocations/medium_subtrees_exists_check-4 8.956µ 8.937µ ~ 1.000
SubtreeAllocations/medium_subtrees_data_fetch-4 9.362µ 9.504µ ~ 0.700
SubtreeAllocations/medium_subtrees_full_validation-4 17.75µ 17.82µ ~ 0.700
SubtreeAllocations/large_subtrees_exists_check-4 2.089µ 2.123µ ~ 0.700
SubtreeAllocations/large_subtrees_data_fetch-4 2.224µ 2.259µ ~ 0.100
SubtreeAllocations/large_subtrees_full_validation-4 4.419µ 4.399µ ~ 1.000
StoreBlock_Sequential/BelowCSVHeight-4 334.1µ 338.5µ ~ 0.200
StoreBlock_Sequential/AboveCSVHeight-4 346.9µ 339.6µ ~ 0.700
GetUtxoHashes-4 276.7n 271.7n ~ 0.700
GetUtxoHashes_ManyOutputs-4 45.85µ 45.86µ ~ 1.000
_NewMetaDataFromBytes-4 216.0n 215.4n ~ 1.000
_Bytes-4 399.1n 404.9n ~ 0.100
_MetaBytes-4 137.9n 140.4n ~ 0.700

Threshold: >10% with p < 0.05 | Generated: 2026-05-29 15:08 UTC

@ordishs ordishs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve — well-scoped, config-only CI change. Verified:

  • sequential-sqlite removal is safe: zero references under .github/, smoketests has no needs: graph, and sonar-pr-analyze only consumes coverage-report/golangci-lint-report/sonar-filename-report (none from smoketests).
  • benchmark-compare exclusion holds: it lives in its own workflow file, so the workflow-level concurrency on the gates can't reach it — partial benchmark runs are preserved.
  • All four PR gate workflows covered, no concurrency-group name collisions, and the sonar pull_requests[0].number || head_branch key matches the existing claude-code-review pattern.
  • Cancelling superseded gate runs is safe downstream: both sonar and claude-code-review guard on conclusion == 'success', so a cancelled run just doesn't trigger them.
  • Module cache is correctness-safe: mod-dir-only, go.sum-keyed, SHA-pinned; Go checksum-verifies against go.sum.

Non-blocking follow-ups:

  • Confirm sequential-sqlite is not listed as a required status check in branch protection (only thing not verifiable from the repo).
  • Fork PRs fall back to head_branch in the sonar key — same-branch-name collisions across forks could cross-cancel (sonar-only, matches existing pattern).
  • Consider extending the module cache to the PR smoketests jobs in a later phase.
  • "Small module cache" is really "stable/infrequently-written" (674 modules) — the size argument is weaker than the write-frequency one.

@oskarszoon oskarszoon merged commit 40ce20f into bsv-blockchain:main May 29, 2026
27 checks passed
@oskarszoon oskarszoon deleted the ci-speed/phase-1-quick-wins branch May 29, 2026 17:43
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.

3 participants