Skip to content

ci+deps+test(persistence): run the S3+ES composite suite on every agent, fix its latent defects, and bump past the crc-fast x86_64 panic - #391

Merged
smunini merged 12 commits into
mainfrom
ci/390-anti-vacuous-gated-suites
Jul 28, 2026
Merged

ci+deps+test(persistence): run the S3+ES composite suite on every agent, fix its latent defects, and bump past the crc-fast x86_64 panic#391
smunini merged 12 commits into
mainfrom
ci/390-anti-vacuous-gated-suites

Conversation

@aacruzgon

@aacruzgon aacruzgon commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Run the S3+ES composite suite on every agent, fix its latent defects, and remove the crc-fast panic at the root

Summary

crates/persistence/tests/s3_es_tests.rs self-skips unless RUN_MINIO_S3_ES_TESTS=1, and no workflow ever set it. The suite had never run in CI — every green run passed it vacuously (#390).

Un-skipping it uncovered two further layers:

  1. The suite was born broken. 3 of its 10 tests fail deterministically anywhere they actually execute. Fixed here.
  2. The AWS S3 SDK panicked on the self-hosted Windows agent. This is the same defect ci: fix Windows MinIO step crc-fast panic + add CI timeouts #345 hit, and it is an upstream crc-fast bug rather than a property of the runner. Rather than gate the suite to Linux, this PR fixes it at the root by bumping the SDK past the fixed crc-fast — which also lets ci: fix Windows MinIO step crc-fast panic + add CI timeouts #345's checksum workaround be removed.

Net result: the suite runs unconditionally on every agent, verified 10/10 on the Windows agent that previously failed 8/10, and the Windows MinIO leg regains the checksum coverage it has been forfeiting since #345.

Why

Three separate ways this was silently verifying nothing:

  • A suite that never ran. RUN_MINIO_S3_ES_TESTS was unset everywhere, so s3_es_tests skipped in every CI run since it was written. The finished in 0.01s signature was there the whole time.
  • A suite that couldn't have worked. Even when run, its harness never indexed anything into Elasticsearch, so every positive search assertion was failing — and its delete/isolation assertions could pass vacuously on timing.
  • A production bug hiding as a CI quirk. The crc-fast panic was treated as a Windows-runner peculiarity. It is not: any HFS deployment writing to S3 on a CPU without SSE4.1+PCLMULQDQ panicked on every upload.

Changes

crates/persistence/tests/s3_es_tests.rs

  1. The composite never indexed anything into ES. The harness used the default sync config — SyncMode::Asynchronous — but never called start_sync_workers(). With an S3 primary (no durable outbox), every secondary sync failed with "async worker was never started", and composite.create/update/delete swallow sync errors by design (primary succeeded, warn! only). Nothing ever reached ES, so all positive search assertions failed. The harness now builds the composite with SyncMode::Synchronous, which is also the semantics the tests assert. Verified by writing to the ES backend directly (worked all along) — the bug was purely the composite wiring in the harness.
  2. Fixed 100ms sleeps → bounded polling. ES refresh visibility on a loaded runner can lag past any fixed sleep, so a search_until() helper polls (10s bound). The delete test now waits for the create to be searchable before deleting, so its absence assertion can't pass vacuously; the tenant-isolation test waits for tenant-a's visibility before asserting tenant-b sees nothing, making the isolation check meaningful rather than timing-dependent.

Cargo.lock, crates/sof/Cargo.toml

  • aws-sdk-s3 1.119.0 → 1.122.0, pulling aws-smithy-checksums 0.63.12 → 0.64.4 → crc-fast 1.6.0 → 1.9.0, past the upstream fix.
  • helios-sof's lru 0.12 → 0.16, following the SDK's own pin (^0.12^0.16) so the lockfile keeps a single lru. The comment there already prescribed exactly this: "Bump to the latest once the AWS SDK updates its lru pin." Usage is new/get/put only; no source change needed.

.github/workflows/ci.yml

Investigation

1. Reproducing the Windows failure

An earlier revision of this PR gated the suite to Linux on two assumptions: that the AWS SDK panics on the Windows agent, and that the ES container was unproven there. To replace conjecture with evidence, run 30303350382 (commit 2717104ce, reverted) removed the gate and pinned test-rust to [self-hosted, Windows]. The job failed as intended:

thread 's3_es_test_create_then_search' panicked at
  ...\crc-fast-1.6.0\src\arch\mod.rs:121:13:
x86 features missing (SSE4.1 && PCLMULQDQ)

test result: FAILED. 2 passed; 8 failed; finished in 13.07s

Assumption 1 confirmed. The only two passing tests are precisely the two that never PUT an object to S3.

Assumption 2 disproved — ES was never a blocker. s3_es_test_read_missing_returns_none passed, and it runs the whole make_harness() path: ES testcontainer start, ElasticsearchBackend construction, and initialize().await.expect("initialize ES backend"). The container works on that agent.

2. Root cause

crc-fast 1.6.0, src/arch/mod.rs:

ArchOpsInstance::SoftwareFallback => {
    #[cfg(target_arch = "x86")]
    crate::arch::x86_software_update(state, bytes, params);

    // This should never happen, but just in case
    panic!("x86 features missing (SSE4.1 && PCLMULQDQ)");
}

A table-based software fallback has existed since 1.2.0, but the call to it is gated #[cfg(target_arch = "x86")]32-bit x86 only. On x86_64 that line compiles to nothing and control drops into the panic!. (The helper it would have called is broken the same way: its inner software call is also cfg'd to x86, and it discards the return value, falling through to an identical panic.) The // This should never happen comment is the tell — the author assumed every x86 CPU advertises SSE4.1+PCLMULQDQ; the agent is a virtualized guest that does not. The SDK reaches this on every upload via aws-sdk-s3aws-smithy-checksumscrc-fast.

Upstream fixed it in 1.7.1, under "Ensure Miri passes on x86_64" (PR #26) — not advertised as a CPU-compat fix, which is why the changelog doesn't flag it:

version panics clean software fallback
1.6.0 yes no
1.7.0 yes no
1.7.1 no yes
1.8.0 – 1.10.0 no yes

3. Why the fix needs an SDK bump

Not reachable by cargo update alone: aws-smithy-checksums 0.63.12 requires crc-fast ~1.6.0 (>=1.6.0, <1.7.0), there is no 1.6.1, and a [patch.crates-io] override cannot satisfy a tilde requirement either. It has to arrive through the SDK.

Why 1.122.0 and not latest: aws-sdk-s3 1.140.0 needs aws-smithy-types 1.6.1serde ^1.0.228, and the workspace pins serde = { version = "=1.0.224" } (Cargo.toml:40). 1.122.0 is the earliest release carrying the fix and it resolves against that pin.

Relationship to #345

cc @smunini#345 hit this exact panic in the Windows MinIO step and diagnosed it correctly down to the line number and dependency chain. Its workaround was the right call at the time: the fix genuinely wasn't reachable, for the tilde-pin reason above, and #345 said so explicitly, naming the root fix as "expose host CPU features (SSE4.1 + PCLMULQDQ) to the Windows runner's hypervisor."

What's new here is the mechanism. #345 described crc-fast 1.6.0 as having "no software fallback on x86_64" — true in effect, but the fallback exists and is merely cfg'd out, which makes this an upstream bug with an upstream fix rather than a hardware requirement. That opens a third option beyond "workaround" and "change the hypervisor": bump the SDK. With the panic gone, #345's env opt-out is unnecessary and is removed here.

This matters for coverage, not just tidiness. WHEN_REQUIRED doesn't merely route around a crash — it disables the SDK's default integrity protection, so the Windows leg was running a different SDK configuration than the Linux leg, and the checksum path (the thing that was broken) was the one part Windows never exercised. Both legs now run identical defaults and differ only by shell.

#345's remaining caveat still stands: "any other hardware-CRC/crypto path on that runner could still hit this." This fixes crc-fast specifically, not the general class of hardware-accelerated paths on a guest with a restricted CPU feature set.

Testing

CI, on the Windows agent that originally failed

Each run below was temporarily pinned to [self-hosted, Windows] to guarantee it landed on github-agent4; every pin has been reverted, and the branch ships runs-on: [self-hosted].

run change under test s3_es_tests MinIO settings
30303350382 gate removed, no SDK bump 8 failed / 2 passed not reached
30310519486 + SDK bump 10 passed / 0 failed opt-out still in place
30318227484 + #345 opt-out removed, main merged 10 passed / 0 failed 5 passed / 0 failed

Final run (job), with the SDK's default CRC32 path active on the CPU that used to panic:

running 10 tests
test s3_es_test_create_then_search ... ok
test s3_es_test_delete_then_search ... ok
test s3_es_test_multi_tenant_isolation ... ok
test s3_es_test_history_from_s3 ... ok
test s3_es_test_read_from_s3 ... ok
test s3_es_test_read_after_delete_returns_gone ... ok
test s3_es_test_s3_search_returns_unsupported ... ok
test s3_es_test_read_missing_returns_none ... ok
test s3_es_test_update_then_search ... ok
test s3_es_test_vread_from_s3 ... ok

test result: ok. 10 passed; 0 failed; finished in 14.45s
running 5 tests
test test_minio_settings_create_only_single_winner ... ok
test test_minio_settings_concurrent_patches_never_lose_an_update ... ok
test test_minio_settings_delete_is_idempotent ... ok
test test_minio_settings_round_trip ... ok
test test_minio_settings_stale_if_match_conflicts ... ok

test result: ok. 5 passed; 0 failed; finished in 0.80s

14.45s of real container work, not the finished in 0.01s skip signature — the first genuine full pass of this suite on a non-Linux agent. Because the eight previously-panicking tests had never reached their ES assertions on Windows, passing them also proves ES indexing, search visibility, and the search_until() bound work there — not merely that the panic is gone. And because real uploads now compute CRC32 on a CPU lacking those instructions, the crc-fast 1.9.0 fallback is genuinely exercised rather than just present.

Local

  • RUN_MINIO_S3_ES_TESTS=1 cargo test -p helios-persistence --test s3_es_tests --features s3,elasticsearch10/10 against real MinIO + ES containers.
  • cargo clippy --all-targets --all-features with CI's exact -A flags — exit 0, re-run after merging main.
  • cargo test -p helios-sof --lib127/127 (the lru bump).
  • cargo check -p helios-persistence --features s3,elasticsearch --tests and cargo check -p helios-sof --all-targets — clean.
  • cargo metadata exits 0 with no lockfile rewrite after the main merge, confirming the merged Cargo.lock is consistent.
  • cargo fmt --all applied.

Notes

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@aacruzgon
aacruzgon force-pushed the ci/390-anti-vacuous-gated-suites branch from 7e9a650 to 0425f82 Compare July 24, 2026 17:06
@aacruzgon aacruzgon changed the title ci(persistence): run the S3+ES composite suite with an anti-vacuous contract check ci(persistence): un-skip the S3+ES composite suite via env on the main test step Jul 24, 2026
…n test step

The s3_es_tests.rs suite self-skips unless RUN_MINIO_S3_ES_TESTS=1, and
no workflow ever set it — the suite had never run in CI, and every green
run passed it vacuously (#390). It is the only coverage of the composite
S3-CRUD + Elasticsearch-search wiring against real backends.

Set the variable on the existing 'Run tests with all features' step
(per maintainer preference, no new steps in ci.yml), gated to Linux
via a runner.os expression because the ES container is not viable on
the virtualized Windows agent.

The anti-vacuous count assertion originally proposed for this suite
moves to #390 PR B, which makes availability guards fail loudly in CI
at the code level instead of asserting counts in YAML.

Tests: validated via this PR's own CI run, which now executes the
10 S3+ES tests inside the workspace test step.
@aacruzgon
aacruzgon force-pushed the ci/390-anti-vacuous-gated-suites branch from 0425f82 to 9376bf6 Compare July 24, 2026 17:15
The suite had never actually run anywhere (#390), and un-skipping it in
CI revealed it was born broken — 3 of 10 tests fail deterministically:

- The harness built the composite with the default sync config, which is
  SyncMode::Asynchronous, but never called start_sync_workers(). With an
  S3 primary (no durable outbox) every secondary sync fails with 'async
  worker was never started'; composite create/update/delete swallow that
  error by design (primary succeeded), so nothing ever reached ES and
  every positive search assertion failed. The composite now uses
  SyncMode::Synchronous, which is also the semantics these tests assert.

- The fixed 100ms sleeps for ES refresh are replaced with a bounded
  search_until() poll (10s), so index-visibility lag on a loaded CI
  runner cannot flake the suite. The delete test now also waits for the
  create to be searchable first, so its absence check can't pass
  vacuously; the tenant-isolation test waits for tenant-a visibility
  before asserting tenant-b's absence, making that check meaningful.

Tests: RUN_MINIO_S3_ES_TESTS=1 cargo test -p helios-persistence
--test s3_es_tests --features s3,elasticsearch — 10/10 pass locally
against real MinIO + ES containers (first full pass of this suite);
scoped CI-style clippy clean.
@aacruzgon aacruzgon changed the title ci(persistence): un-skip the S3+ES composite suite via env on the main test step ci+test(persistence): un-skip the S3+ES composite suite and fix its latent defects Jul 24, 2026
Comment thread .github/workflows/ci.yml Outdated
Reproduction experiment for #391 review feedback: make the S3+ES composite
suite (s3_es_tests.rs) run on a non-Linux agent so the assumed Windows
failure is observed rather than inferred.

Two gates had to move together. `runs-on: [self-hosted]` picks whichever
agent is free, and RUN_MINIO_S3_ES_TESTS was
`${{ runner.os == 'Linux' && '1' || '' }}`, so a Windows landing skipped
the suite silently - which is exactly why the previous green run on
github-agent4 (Windows) proved nothing. Pin to the Windows agent and set
the variable unconditionally.

Both changes are marked TEMPORARY and revert once the failure signature is
captured.
Run 30303350382 removed the gate and pinned Test Rust to the Windows agent
to observe the failure instead of predicting it. Two things came back.

The panic is real and precisely located: 8 of 10 tests died in
crc-fast-1.6.0/src/arch/mod.rs:121 with "x86 features missing (SSE4.1 &&
PCLMULQDQ)". crc-fast 1.6.0 gates its software fallback behind
#[cfg(target_arch = "x86")], so on x86_64 the fallback never compiles and
the SoftwareFallback arm falls through to a panic. Upstream fixed it in
1.7.1; aws-smithy-checksums 0.63.12 pins ~1.6.0, so reaching the fix means
moving aws-sdk-s3 to >= 1.122.0.

The second half of the gate was wrong: Elasticsearch works on that agent.
s3_es_test_read_missing_returns_none passed, and it runs the full
make_harness() path including the ES testcontainer and initialize().

Comment-only; the gate expression is unchanged.
@aacruzgon

This comment has been minimized.

…agent

The S3+ES suite was gated to Linux because the AWS S3 SDK panics on the
self-hosted Windows agent. Run 30303350382 pinned Test Rust to that agent
with the gate removed and captured the cause: 8 of 10 tests panicked in
crc-fast-1.6.0/src/arch/mod.rs:121, "x86 features missing (SSE4.1 &&
PCLMULQDQ)". The agent is a virtualized guest lacking those instructions,
and crc-fast 1.6.0 gates its software fallback behind
#[cfg(target_arch = "x86")] - so on x86_64 the fallback never compiles and
the SoftwareFallback arm falls through to a panic. The SDK reaches it on
every upload via aws-sdk-s3 -> aws-smithy-checksums -> crc-fast.

crc-fast fixed the fallback in 1.7.1, but aws-smithy-checksums 0.63.12
pins `crc-fast ~1.6.0`, which excludes it, and a [patch] override cannot
satisfy a tilde requirement either. The fix has to arrive through the SDK:
aws-sdk-s3 1.122.0 -> aws-smithy-checksums 0.64.4 -> crc-fast 1.9.0.

1.122.0 rather than latest: aws-sdk-s3 1.140.0 needs aws-smithy-types
1.6.1 -> serde ^1.0.228, and the workspace pins serde = "=1.0.224"
(Cargo.toml:40). 1.122.0 is the earliest release carrying the fix and it
resolves against that pin.

helios-sof's lru moves 0.12 -> 0.16 to follow the SDK's own pin, which
went ^0.12 -> ^0.16 in this bump. Its comment already prescribed exactly
this ("Bump to the latest once the AWS SDK updates its lru pin"); without
it the lockfile would carry two lru versions whenever `s3` is enabled.
Usage is new/get/put only and needed no source change.

With the panic gone, RUN_MINIO_S3_ES_TESTS becomes an unconditional "1".
Elasticsearch was never the blocker the gate also claimed: in that same
run s3_es_test_read_missing_returns_none passed, exercising the whole
make_harness() path including ES container start and initialize().
Reverts once the S3+ES suite is confirmed 10/10 on the agent that failed
in run 30303350382. Not for merge.
@aacruzgon aacruzgon changed the title ci+test(persistence): un-skip the S3+ES composite suite and fix its latent defects ci+deps+test(persistence): run the S3+ES composite suite on every agent, fix its latent defects, and bump past the crc-fast x86_64 panic Jul 28, 2026
@aacruzgon

This comment has been minimized.

The Windows leg of the MinIO conditional-writes check set
AWS_REQUEST_CHECKSUM_CALCULATION and AWS_RESPONSE_CHECKSUM_VALIDATION to
WHEN_REQUIRED. That existed only to dodge the crc-fast 1.6.0 panic on this
virtualized x86_64 agent - the same bug that gated the S3+ES suite to Linux.

Dodging it disabled the SDK's default integrity protection, so this leg ran
a different SDK configuration than the Linux leg, and the checksum path was
the one thing Windows never exercised. With crc-fast 1.9.0 (via aws-sdk-s3
1.122.0) the panic is gone, so both legs now run identical defaults and the
Windows leg regains checksum coverage. The steps still differ only by shell.
… removal

Reverts once the MinIO settings tests are confirmed 5/5 with the SDK's
default checksum path active. Not for merge.
…ated-suites

# Conflicts:
#	.github/workflows/ci.yml
@aacruzgon

This comment has been minimized.

@aacruzgon
aacruzgon requested a review from smunini July 28, 2026 04:33
@smunini
smunini merged commit 48e1df3 into main Jul 28, 2026
19 checks passed
@smunini
smunini deleted the ci/390-anti-vacuous-gated-suites branch July 28, 2026 15:56
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.

2 participants