The Dependency Edit That Nearly Broke the Build: Wiring Up Phase 2 of the cuzk Pipelined Prover

"Now update cuzk-core's Cargo.toml:" — and with that, the assistant triggered an edit that would produce a cascading build error requiring three additional messages to diagnose and fix. This is the story of message 450, the briefest of edits that exposed a subtle mismatch in Rust feature flag conventions across a family of closely related crates.

The Message in Full

The subject message is deceptively simple:

[assistant] Now update cuzk-core's Cargo.toml: [edit] /home/theuser/curio/extern/cuzk/cuzk-core/Cargo.toml Edit applied successfully.

That is the entirety of message 450 — a single transitional sentence followed by a tool invocation and its success confirmation. On its surface, it appears to be a routine dependency update. But this message sits at a critical juncture in the implementation of Phase 2 of the cuzk proving engine, and the edit it performed carried an incorrect assumption that would immediately surface as a build failure.

The Context: Why This Edit Was Necessary

To understand message 450, we must understand the architecture it serves. The cuzk proving engine, under development in the extern/cuzk/ Rust workspace, is a pipelined SNARK proving daemon for Filecoin proof generation. Phase 0 and Phase 1 established a monolithic prover that called filecoin-proofs-api functions directly. Phase 2 aims to replace this with a pipelined architecture where CPU circuit synthesis and GPU NTT+MSM proving overlap, preventing the GPU from sitting idle while the CPU prepares the next batch of work.

The Phase 2 pipeline required two new modules in cuzk-core:

  1. srs_manager.rs — A direct SRS (Structured Reference String) parameter loader that bypasses the private GROTH_PARAM_MEMORY_CACHE used by the upstream filecoin-proofs crate. This module needs SuprasealParameters from the bellperson fork and direct access to .params files on disk.
  2. pipeline.rs — The split synthesis/prove functions that call bellperson::synthesize_circuits_batch() for CPU-side circuit synthesis and bellperson::prove_from_assignments() for GPU-side proving. These functions need types from filecoin-proofs, storage-proofs-core, storage-proofs-porep, and the other storage-proofs family crates to construct circuits and manage proof data. The SRS manager had just been created in message 447. Now it was time to wire up the dependencies so these modules could actually compile. This is Step 4a of the Phase 2 implementation plan: "Add new dependencies to cuzk-core Cargo.toml (filecoin-proofs, storage-proofs-*, bellperson, blstrs, rayon, ff)." Message 449 had already updated the workspace-level Cargo.toml with version declarations for these new dependencies. Message 450 was the second half of that operation: adding the actual dependency lines to cuzk-core/Cargo.toml, the crate that would host the new pipeline code.

The Assumption That Led Astray

The edit in message 450 added the new dependencies with feature flags. The critical detail is which feature flags were used. Based on the build error that immediately followed in message 451, we can reconstruct what the edit contained:

filecoin-proofs = { workspace = true, features = ["cuda-supraseal"] }
storage-proofs-core = { workspace = true, features = ["cuda-supraseal"] }
storage-proofs-porep = { workspace = true, features = ["cuda-supraseal"] }
storage-proofs-post = { workspace = true, features = ["cuda-supraseal"] }
storage-proofs-update = { workspace = true, features = ["cuda-supraseal"] }
bellperson = { workspace = true, features = ["cuda-supraseal"] }

The assumption was straightforward: since all these crates are part of the Filecoin proof ecosystem and they all support GPU proving via SupraSeal, they should all have a cuda-supraseal feature flag. This is a natural assumption — when you see filecoin-proofs with features = ["cuda-supraseal"] and storage-proofs-core with the same, it's reasonable to expect the pattern holds across the family.

But it didn't. The build error in message 451 revealed the truth:

error: failed to select a version for `storage-proofs-porep`.
the package `cuzk-core` depends on `storage-proofs-porep`, with features: `cuda-supraseal` 
but `storage-proofs-porep` does not have these features.

The Investigation and Fix

Message 451 ran cargo check --workspace --no-default-features and hit the error. The assistant immediately recognized the issue wasn't a missing dependency but a feature flag mismatch. Message 452 launched a diagnostic loop that inspected the [features] sections of all five upstream crates:

Input Knowledge Required

To understand message 450, one needs to know:

Output Knowledge Created

Message 450 itself produced only a modified Cargo.toml file. But the failure it triggered created valuable knowledge:

  1. Feature flag asymmetry in the storage-proofs family: The cuda-supraseal feature only exists on filecoin-proofs and storage-proofs-core. The leaf crates (porep, post, update) only have cuda. This is now documented in the assistant's understanding.
  2. The correct dependency wiring for Phase 2: The final cuzk-core/Cargo.toml must use cuda-supraseal on the two core crates and cuda on the three leaf crates, plus cuda-supraseal on bellperson.
  3. A verification pattern: The assistant learned to run cargo check --workspace --no-default-features immediately after dependency edits, catching feature flag mismatches before they compound with code changes.

The Thinking Process

The assistant's reasoning in message 450 is largely implicit — the message is too short to contain visible deliberation. But the surrounding messages reveal the thinking:

The assistant had just completed the SRS manager (message 447) and was working through the Phase 2 todo list in order. Step 4a was next. The workspace deps had been added in message 449. Message 450 was the natural continuation: "now update cuzk-core's Cargo.toml."

The assumption about feature flags was a reasonable inference from the crate ecosystem's naming conventions. When filecoin-proofs has cuda-supraseal and storage-proofs-core has cuda-supraseal, it's natural to assume the pattern extends to storage-proofs-porep. The mistake wasn't carelessness — it was an understandable generalization from an incomplete sample.

What's notable is the speed of recovery. The build error in message 451 triggered immediate investigation (message 452) without any backtracking or confusion. The diagnostic loop was targeted: check the [features] sections of exactly the crates that failed. The fix in message 453 was precise and minimal. This pattern — make an assumption, test it, discover the mismatch, correct it — is characteristic of experienced systems programming where complex dependency graphs are the norm.

Broader Significance

Message 450 is a microcosm of a common challenge in large Rust projects: dependency feature flag management across crate boundaries. The Filecoin proof ecosystem has a layered architecture where features are not uniformly defined. cuda-supraseal is a "composite" feature that exists at the top layers and expands into simpler cuda features at the leaves. Requesting the composite feature on a leaf crate fails because the leaf doesn't know about the composite.

This asymmetry is intentional — it allows filecoin-proofs to coordinate which GPU backend to use across all its dependencies without requiring every downstream crate to understand the full feature matrix. But it creates a trap for developers who assume feature flags are uniformly distributed across related crates.

The fix in message 453 — using cuda instead of cuda-supraseal on the leaf crates — is correct because cuda-supraseal on filecoin-proofs already propagates cuda down to those crates. The leaf crates don't need to know about SupraSeal specifically; they just need CUDA support enabled. The SupraSeal-specific logic lives in bellperson and storage-proofs-core.

Conclusion

Message 450 is the shortest message in a chain of five (449–453) that collectively wired up the dependency graph for Phase 2 of the cuzk proving engine. Its edit was wrong, but the error it exposed was informative. The five-message sequence — workspace deps, crate deps (with wrong flags), build error, investigation, fix — is a textbook example of iterative dependency management in Rust. The mistake was natural, the diagnosis was swift, and the correction was clean. The pipeline modules could now be written against the correct dependency foundation, and the next messages in the conversation would go on to implement the full synthesis/prove split that defines Phase 2.