Skip to content

ci: skip shielded Rust tests on PRs without shielded changes - #4293

Merged
QuantumExplorer merged 4 commits into
v4.2-devfrom
claude/shielded-ci-caching-7768a0
Aug 5, 2026
Merged

ci: skip shielded Rust tests on PRs without shielded changes#4293
QuantumExplorer merged 4 commits into
v4.2-devfrom
claude/shielded-ci-caching-7768a0

Conversation

@QuantumExplorer

@QuantumExplorerQuantumExplorer commented Aug 5, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

The shielded test phase of the Rust workspace job (cargo llvm-cov test -p dpp -p drive -p drive-abci -p dash-sdk -- shield) costs ~4.5 minutes of the ~13-minute warm-runner job — about as long as the entire non-shielded nextest phase — and runs on every PR that touches any Rust crate, even ones completely unrelated to shielded functionality. The Swift SDK build queues behind this job, so the cost compounds downstream.

What was done?

Detection — a new Check for shielded-relevant changes step in the changes job of tests.yml classifies a PR as shielded-relevant if:

  • a changed file's path mentions shield/orchard/halo2 (all shielded modules live in *shield* directories), or
  • the diff content of any .rs file mentions those keywords (catches edits to shielded match arms, error variants, and test names in shared files outside the shielded directories), or
  • build configuration changed: any Cargo.toml, Cargo.lock, rust-toolchain.toml, the rust setup action, or the Rust test workflows.

Coverage split and cachetests-rs-workspace.yml now reports the non-shielded phase to lcov-nonshielded.info, drops its profraw files with cargo llvm-cov clean --profraw-only, and reports the shielded phase separately to lcov-shielded.info, which is saved to actions/cache (key rs-shielded-lcov-v1-<sha>, prefix restore). A PR with no shielded-relevant changes restores the most recent shielded lcov — in practice the one saved by the last post-merge push run on the base branch — and skips the shielded phase entirely. Both files are uploaded together and codecov merges them, so combined PR coverage is unchanged. A cache miss simply falls back to running the suite, so the mechanism self-heals with no bootstrap step.

Safety net — the detection is a heuristic, not a dependency proof: shielded tests exercise shared consensus code, so a shared-code-only change could in principle break them while being classified unrelated. Push-to-dev, nightly, and workflow_dispatch runs always execute the shielded suite (and refresh the cache), so an escape is caught minutes after merge and bisects to exactly one PR. Codecov never gates merges here (fail_ci_if_error: false), so coverage staleness on the skip path is cosmetic only.

One subtlety worth noting for reviewers: the detector deliberately uses set -eu without pipefail — the detection pipelines end in grep -q, which exits on first match and SIGPIPEs the upstream git diff; under pipefail a match would read as pipeline failure and silently flip the answer to "unchanged".

How Has This Been Tested?

  • Replayed the detector logic over the last 30 merges to v4.2-dev: about half would take the fast path; every shielded-adjacent PR (the shielded denominations protocol change, CheckTx verification bounds touching shielded state-transition dirs) and every build-config change was correctly flagged to run.
  • Verified cargo llvm-cov clean --profraw-only exists in the pinned cargo-llvm-cov (0.8.4).
  • Measured the shielded step at ~4.5 minutes across recent warm-runner runs via the Actions API.
  • Both workflows pass YAML validation and actionlint (only pre-existing style notes remain).

Breaking Changes

None.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Improved automated test runs by detecting when shielded testing is required.
    • Reused cached shielded test coverage when relevant code is unchanged, reducing unnecessary work.
    • Separated shielded and non-shielded coverage reports for clearer analysis.
    • Updated coverage reporting to upload both report types independently.
    • Ensured full shielded testing remains enabled for manual runs, non-pull-request runs, and uncertain change detection.

The shielded test phase (cargo llvm-cov test -p dpp -p drive
-p drive-abci -p dash-sdk -- shield) costs ~4.5 minutes of the
~13-minute warm-runner Rust workspace job and runs on every PR that
touches any Rust crate, shielded-related or not.
The changes job now classifies a PR as shielded-relevant if a changed
path or changed .rs diff line mentions shield/orchard/halo2, or if
build configuration changed (any Cargo.toml, Cargo.lock,
rust-toolchain.toml, the rust setup action, or the Rust test
workflows). The workspace job splits its coverage report into
lcov-nonshielded.info and lcov-shielded.info (via cargo llvm-cov clean
--profraw-only between phases), caches the shielded half with
actions/cache, and on shielded-irrelevant PRs restores it and skips
the shielded run entirely; codecov merges the two uploaded files so
combined coverage is unchanged. A cache miss falls back to running the
suite, so the mechanism self-heals.
The detection is a heuristic: shielded tests exercise shared consensus
code, so a shared-code change could in principle break them while
classified unrelated. Push, nightly, and workflow_dispatch runs always
execute the shielded suite (and refresh the cache), so an escape is
caught minutes after merge and bisects to one PR. Replayed over the
last 30 merges to v4.2-dev, about half would take the fast path and
all shielded-adjacent PRs were correctly flagged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b57f0107-64e2-42d2-983e-268c3eda487c

📥 Commits

Reviewing files that changed from the base of the PR and between 098cb79 and 8b77178.

📒 Files selected for processing (2)
  • .github/workflows/tests-rs-workspace.yml
  • .github/workflows/tests.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/tests.yml

📝 Walkthrough

Walkthrough

The workflows detect shielded-related changes, pass the result to Rust workspace tests, reuse unchanged shielded coverage, generate separate LCOV reports, cache successful shielded coverage, and upload both reports.

Changes

Shielded coverage control

Layer / File(s)Summary
Shielded-change detection and wiring
.github/workflows/tests.yml
The changes job detects shielded-related changes and exposes shielded-changed. Manual runs and detection failures enable shielded tests. The Rust workspace test job passes the value downstream.
Conditional coverage execution
.github/workflows/tests-rs-workspace.yml
The reusable workflow accepts shielded-changed, validates separate LCOV files, restores shielded coverage when inputs are unchanged, and conditionally runs shielded tests.
Shielded report caching and upload
.github/workflows/tests-rs-workspace.yml
The workflow generates and caches shielded coverage after successful tests, records the coverage tree hash, and uploads separate non-shielded and shielded LCOV files.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers:vivekgsharma

Sequence Diagram(s)

sequenceDiagram
participant ChangesJob
participant RustWorkspaceTests
participant CoverageCache
participant Codecov
ChangesJob->>RustWorkspaceTests: Pass shielded-changed
RustWorkspaceTests->>CoverageCache: Restore shielded LCOV when inputs are unchanged
RustWorkspaceTests->>RustWorkspaceTests: Run required non-shielded and shielded coverage tests
RustWorkspaceTests->>CoverageCache: Cache shielded LCOV after successful shielded tests
RustWorkspaceTests->>Codecov: Upload non-shielded and shielded LCOV
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and concisely describes the main CI change: skipping shielded Rust tests when pull requests have no shielded-related changes.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/shielded-ci-caching-7768a0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added this to the v4.2.0 milestone Aug 5, 2026
@thepastaclaw

thepastaclaw commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit 8b77178)
Stage: Codex precheck starting
ETA: complete ~08:06 UTC (median 21m across 30 recent reviews)
Running 4m · Last checked: 2026-08-05 07:50 UTC

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/tests-rs-workspace.yml:
- Around line 238-246: Update the shielded coverage flow around the “Restore
shielded coverage from cache” step so prefix-matched cached LCOV is not restored
for an unverified source tree. Require validation against a shielded
dependency-closure or source-content hash before reuse; when validation is
unavailable or fails, prevent the cache path from supplying coverage and ensure
the shielded test suite runs instead. Preserve cache reuse only for verified
matching trees.
In @.github/workflows/tests.yml:
- Around line 277-278: Update the Rust content-diff condition in the workflow so
any failure in the pipeline, including the final grep non-match or command
error, is treated as shielded-relevant rather than setting
shielded-changed=false. Preserve the existing matching behavior for Rust diffs
while ensuring the conditional handles pipeline failures with the documented
fail-safe outcome.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8714535a-c068-4683-8151-81325679f083

📥 Commits

Reviewing files that changed from the base of the PR and between 93d8717 and 098cb79.

📒 Files selected for processing (2)
  • .github/workflows/tests-rs-workspace.yml
  • .github/workflows/tests.yml

Comment thread.github/workflows/tests-rs-workspace.yml Outdated
Comment thread.github/workflows/tests.yml Outdated
@codecov

codecovBot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.60%. Comparing base (93d8717) to head (703d899).

Additional details and impacted files
@@ Coverage Diff @@## v4.2-dev #4293 +/- ##
============================================
+ Coverage 87.55% 87.60% +0.05% 
============================================
Files 2700 2703 +3 Lines 343157 344990 +1833 ============================================
+ Hits 300464 302242 +1778 - Misses 42693 42748 +55 
ComponentsCoverage Δ
dpp88.82% <ø> (+0.18%)⬆️
drive86.25% <ø> (ø)
drive-abci89.65% <ø> (-0.01%)⬇️
sdk∅ <ø> (∅)
dapi-client∅ <ø> (∅)
platform-version∅ <ø> (∅)
platform-value92.88% <ø> (ø)
platform-wallet∅ <ø> (∅)
drive-proof-verifier48.02% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Address review feedback on the shielded skip path:
- Key the shielded coverage cache by a content hash over every tracked
source file mentioning the shielded keywords (plus Cargo.lock and
rust-toolchain.toml) instead of commit sha with prefix restore. An
exact-key hit now proves the cached lcov was produced from
byte-identical shielded sources, so a PR can never reuse coverage
from a tree whose shielded code differs from its own.
- Capture the content diff to a file in the detector so a git failure
is distinguishable from "no keyword match" — previously the final
grep's non-match status would have masked it and failed open to
skipping the suite.
- Extend content detection and the hash set to .proto files: shielded
gRPC message changes regenerate into dapi-grpc and must run the
suite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@thepastaclawthepastaclaw 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.

Preliminary review — Codex only

Carried-forward prior findings: none. New latest-delta findings: two blocking cache-reuse defects remain—the fast path can suppress the post-merge shielded test run, and the content key omits sources and build inputs that the detector classifies as shielded-relevant.

Source: reviewers codex/general=gpt-5.6-sol(completed); verifier=codex/verifier=gpt-5.6-sol(completed); coordinator=openclaw-agent/cliproxy/gpt-5.6-sol(orchestration-only).

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `.github/workflows/tests-rs-workspace.yml`:
- [BLOCKING] .github/workflows/tests-rs-workspace.yml:357-359: Do not mark cache-restored coverage as a fully tested tree
This writes `HEAD^{tree}` after both fresh shielded coverage and cache-restored shielded coverage. A PR that takes the fast path therefore marks its merge tree as fully reusable even though the shielded suite did not run. If the subsequent post-merge push has the same tree—which is common because the PR merge ref and merged commit can differ only in history—and is assigned to the same persistent runner, the initial coverage check finds the marker and both LCOV files and skips the entire test phase. That defeats the documented non-PR safety net for shared-code changes that the heuristic misses. Record the full-tree marker only after the shielded suite actually succeeds.
- [BLOCKING] .github/workflows/tests-rs-workspace.yml:245-249: Hash every input that the detector treats as shielded-relevant
The detector forces shielded tests for keyword-bearing paths and changes to any Cargo manifest, the Rust setup action, or the Rust test workflows, but this cache key hashes only `.rs` and `.proto` files whose contents contain a keyword, plus the root `Cargo.lock` and `rust-toolchain.toml`. Several Rust files under shielded paths are consequently omitted; for example, `packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs` contains none of the three keywords. Editing such a file without introducing a keyword, or changing a `Cargo.toml` feature without changing `Cargo.lock`, leaves the key unchanged. Although that change's run executes the suite, the immutable Actions cache entry cannot be replaced, so later unrelated PRs restore and upload shielded coverage generated from the pre-change source or build configuration. Build the key from the union of path matches, content matches, and every build input recognized by the detector.

Comment thread.github/workflows/tests-rs-workspace.yml
Comment thread.github/workflows/tests-rs-workspace.yml
Two blocking review findings on the shielded fast path:
- Write the coverage tree-hash marker only when the shielded suite
actually ran and succeeded. A fast-path run (cache-restored shielded
coverage) previously wrote it too, and since the post-merge push
commonly has the same tree as the PR merge ref, the marker could let
the push run on the same runner skip the entire test phase —
defeating the safety net for shared-code changes the detector
heuristic misses.
- Build the cache key from the union of everything the detector treats
as shielded-relevant: keyword-matching paths (shielded module files
such as error types under shielded/ directories don't all mention a
keyword in their content), keyword-matching .rs/.proto contents,
every Cargo manifest and lockfile, rust-toolchain.toml, the rust
setup action, and the Rust test workflows. Previously a
shielded-relevant edit that left the key unchanged could leave a
stale immutable cache entry reachable under a current key.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thepastaclaw

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitaiBot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@QuantumExplorer
QuantumExplorer merged commit 68be5d9 into v4.2-devAug 5, 2026
5 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/shielded-ci-caching-7768a0 branch August 5, 2026 07:53
QuantumExplorer added a commit that referenced this pull request Aug 5, 2026
Excluding the chain-simulation suite on PRs made every PR report a
spurious ~0.57% project-coverage drop (drive-abci -1.33%): base
coverage comes from full-suite push runs while PRs upload gated
coverage. Split coverage into three codecov flags — rust (always
uploaded), rust-strategy (chain simulations, push/nightly only), and
rust-shielded (shielded phase, when it runs) — with carryforward
enabled, so codecov reuses the base commit's coverage for any flag a
PR run doesn't upload and PR reports stay comparable.
The chain simulations now run as their own phase (push/nightly only)
with their own lcov, and the nextest phase uses the same gated filter
on every event so the rust flag measures the same population
everywhere. Carryforward also replaces the shielded coverage cache
from #4293 entirely — instead of restoring a content-verified cached
lcov on skip runs, the flag is simply not uploaded and codecov carries
the base's forward, which deletes the content-hash, cache-restore, and
cache-save steps. The complete-suite tree-hash marker now additionally
requires the chain-simulation phase to have succeeded, so a PR
fast-path run cannot mark its tree as fully tested for a same-tree
post-merge push run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@QuantumExplorer@thepastaclaw