The Submodule That Wasn't: A Moment of Discovery in the cuzk Upstreaming Plan

Message Overview

In the midst of planning how to upstream a custom GPU-resident SNARK proving engine called cuzk into the Curio Filecoin storage provider codebase, the assistant executed a single command:

git submodule status

The output was deceptively simple — and deeply revealing:

 4b398eadebe521c8c4e4f94e1ded77ccfad139f0 extern/filecoin-ffifatal: no submodule mapping found in .gitmodules for path 'extern/supraseal/deps/sppark'
 (v1.23.4-pre1-107-g4b398ea)

This message, indexed as <msg id=3490>, is a classic example of a discovery probe — a lightweight investigative command whose output exposes a latent infrastructure problem. On its surface, it is a routine check of Git submodule state. In its subtext, it reveals a broken dependency chain that could derail the entire upstreaming effort if left unaddressed.

Context: The Upstreaming Dilemma

To understand why this command was run, we must step back into the broader session. The Curio project had just completed a massive engineering effort — Phase 12 of the cuzk proving engine — which introduced a split GPU proving API, memory backpressure, and integration with three task types (PoRep C2, SnapDeals Prove, and PSProve). The integration was functionally complete, with Go gRPC clients wired into the task orchestrator and all packages passing go vet.

But the code lived on a branch called feat/cuzk. The question posed by the user in <msg id=3483> was: how do we upstream this? The user explicitly ruled out merging changes to upstream repositories like bellman, filecoin-proofs, or supraseal. The goal was a "quick-to-prod" route — get the code into Curio's main branch without waiting for upstream crate releases or negotiating with external maintainers.

This constraint forced a build-system-centric approach. The assistant began exploring the repository's infrastructure: reading the Makefile, inspecting extern/cuzk/Cargo.toml, listing the contents of extern/, and checking git status on the extern directory. Each probe revealed more about the dependency landscape. The Cargo.toml showed that cuzk used [patch.crates-io] to redirect upstream crates like bellperson, bellpepper-core, and supraseal-c2 to local paths in extern/. The Makefile showed existing patterns for building filecoin-ffi, blst, and supraseal. The git status output showed that several vendored crates — bellpepper-core, bellperson, supraseal-c2 — were untracked, meaning they existed on disk but had not been staged for commit.

What git submodule status Actually Reveals

The command git submodule status is a standard Git plumbing command that prints the current state of every registered submodule. Each line shows the commit hash, the path, and optionally a brief description or branch indicator. A clean output means all submodules are properly registered in .gitmodules and checked out at their expected commits.

The output here is anything but clean. The first line appears normal:

 4b398eadebe521c8c4e4f94e1ded77ccfad139f0 extern/filecoin-ffi

This tells us that extern/filecoin-ffi is a properly registered submodule, checked out at commit 4b398eadebe521c8c4e4f94e1ded77ccfad139f0, which corresponds to version v1.23.4-pre1-107-g4b398ea. No issues there.

But then the output collapses into a single error line:

fatal: no submodule mapping found in .gitmodules for path 'extern/supraseal/deps/sppark'

This is a critical diagnostic. Git is telling us that there is a Git submodule directory at extern/supraseal/deps/sppark on disk — it has a .git file or directory, and Git can see it — but there is no corresponding entry in .gitmodules to tell Git how to manage it. This is a classic symptom of one of several scenarios:

  1. A submodule was added manually by cloning a repository directly into the path without using git submodule add, so no entry was created in .gitmodules.
  2. A .gitmodules entry was deleted or the file was corrupted, leaving orphaned submodule directories on disk.
  3. A parent submodule (supraseal) was updated to a version that includes sppark as a dependency, but the top-level repository's .gitmodules was never updated to reflect this.
  4. The supraseal repository itself has sppark as a submodule, and when supraseal was cloned (perhaps via git submodule update --init --recursive), the recursive clone created sppark without registering it at the top level. The last scenario is the most likely here. The supraseal project (located at extern/supraseal/) is itself a Git repository that likely declares deps/sppark as a submodule within its own .gitmodules. When Curio's top-level git submodule update --init --recursive is run, Git descends into extern/supraseal/ and clones sppark there. But the top-level .gitmodules has no mapping for this nested path, so git submodule status at the top level cannot report on it — it can only report the fatal error.

Why This Matters for the Upstreaming Plan

The broken submodule mapping is not a theoretical concern. It has practical consequences for every aspect of the upstreaming plan:

Reproducibility: If sppark is not properly tracked as a submodule, a fresh clone of the repository will not know to check it out. The supraseal build will fail with missing headers or libraries, and the error message will be opaque — a cryptic C++ compilation failure rather than a clear "submodule not initialized" warning.

CI/CD Integrity: The Curio CI pipeline likely runs git submodule update --init --recursive as a standard step. If sppark is orphaned, the CI environment may or may not reproduce the same state as the development machine. This creates a "works on my machine" class of bug that is notoriously difficult to diagnose remotely.

The Vendor-in-Repo Strategy: The user's directive to avoid upstreaming meant that the team planned to vendor all forked Rust crates directly inside the Curio repository. This strategy — Option B in the session's reasoning — was chosen precisely for its self-contained reproducibility. But a broken submodule mapping undermines that very property. If the vendored supraseal-c2 crate depends on supraseal, which depends on sppark, and sppark is not properly tracked, then the build is not truly self-contained.

Deployment: The cuzk daemon requires CUDA and Rust nightly to build. The Makefile was being extended with make cuzk and make install-cuzk targets. If the build fails due to a missing submodule, the deployment instructions in the documentation (cuzk-proving-daemon.md) would be incomplete — they would need to include a manual fix-up step for sppark.

Assumptions Embedded in This Message

The assistant made several implicit assumptions when running this command:

  1. That submodule state is relevant to the upstreaming plan. This is a non-trivial assumption. The assistant could have focused solely on the Rust crate vendoring and the Go gRPC client, treating the C++/CUDA layer as an opaque binary dependency. Instead, the assistant chose to verify the entire dependency tree, including the Git submodule layer. This reflects a thorough, infrastructure-aware mindset.
  2. That the error is worth surfacing immediately. A less diligent assistant might have glossed over the fatal: prefix, treating it as a pre-existing issue unrelated to the cuzk integration. But the assistant recognized that any build system fragility is relevant to a "quick-to-prod" plan. The error was surfaced in the output, not suppressed or ignored.
  3. That the user would want to know about this. The assistant did not attempt to fix the issue silently. It ran the command, captured the output, and presented it verbatim. This assumes the user is a collaborator who needs full visibility into infrastructure state before making strategic decisions about the upstreaming approach.
  4. That git submodule status is the right diagnostic tool. There are other ways to check submodule state — git config --file .gitmodules --get-regexp path, git ls-tree HEAD, or simply inspecting the filesystem. The assistant chose the standard plumbing command, which suggests familiarity with Git internals and a preference for canonical tools over ad-hoc inspection.

Knowledge Required to Interpret This Message

A reader needs several layers of knowledge to fully understand what this message means:

Git Submodule Mechanics: The reader must understand that .gitmodules is a file that maps submodule paths to remote URLs and that git submodule status reads this file to report on each submodule's state. Without this knowledge, the fatal: error looks like a generic Git failure rather than a specific mapping problem.

Repository Layout: The reader must know that extern/ is the standard location for vendored dependencies in the Curio repository, that extern/filecoin-ffi is a long-standing submodule, and that extern/supraseal/ is a relatively new addition that itself has a complex dependency tree including sppark (a CUDA-accelerated elliptic curve library).

Build System Architecture: The reader must understand that supraseal is a C++/CUDA library for SNARK proving, that supraseal-c2 is a Rust wrapper around it, and that cuzk depends on both. The chain is: cuzk-daemoncuzk-coresupraseal-c2suprasealsppark. A break anywhere in this chain blocks the entire build.

The Upstreaming Context: Most importantly, the reader must understand that this command was run as part of a deliberate investigation into build system readiness. It was not a random diagnostic. It was a targeted probe aimed at identifying every potential friction point before committing to a specific upstreaming strategy.

Knowledge Created by This Message

This single command produced several concrete pieces of knowledge that were not available before:

  1. The exact commit hash of filecoin-ffi: 4b398eadebe521c8c4e4f94e1ded77ccfad139f0, tagged as v1.23.4-pre1-107-g4b398ea. This pins the exact version of the FFI dependency, which is useful for reproducing builds and for documenting the dependency baseline in the upstreaming plan.
  2. The existence of an orphaned submodule at extern/supraseal/deps/sppark: This is the critical finding. Before this command, the assistant might have assumed that all submodules were properly registered. Now there is a known issue that must be addressed.
  3. The filecoin-ffi submodule is healthy: The leading space in the output (before the commit hash) indicates that the submodule is checked out at the expected commit. No + prefix (which would indicate a modified checkout) and no - prefix (which would indicate an uninitialized submodule). This is a clean bill of health for the primary FFI dependency.
  4. The error is specific to sppark, not to supraseal itself: The error message names the path extern/supraseal/deps/sppark, not extern/supraseal. This tells us that supraseal itself is likely properly registered (or at least not producing a fatal error), and the problem is one level deeper.
  5. The repository is on a branch (feat/cuzk) with uncommitted submodule state: The git submodule status output, combined with the earlier git status output from <msg id=3489>, paints a picture of a branch that has been actively developed but not yet cleaned up for integration. The untracked vendored crates and the orphaned submodule are both signs of work-in-progress that needs to be resolved before upstreaming.

The Thinking Process Visible in This Message

Although the assistant's reasoning is not explicitly shown in this message (the message contains only the tool call and its output), the thinking process can be inferred from the sequence of commands leading up to it.

In the preceding messages, the assistant had been systematically exploring the build system:

Implications for the Upstreaming Plan

The discovery of the orphaned sppark submodule has direct implications for the "quick-to-prod" route:

Fix Option 1 — Register the submodule properly: Add an entry to .gitmodules for extern/supraseal/deps/sppark pointing to the correct remote URL. This is the canonical fix and ensures that git submodule update --init --recursive works correctly. However, it requires knowing the correct URL and commit hash, and it adds another external dependency to the repository's dependency chain.

Fix Option 2 — Vendor sppark directly: If the goal is maximum self-containment, the team could vendor sppark directly into the Curio repository, similar to how bellpepper-core and supraseal-c2 were vendored. This eliminates the submodule dependency entirely but increases the repository size and maintenance burden.

Fix Option 3 — Document the manual fix: If the team decides that the submodule issue is a pre-existing condition not introduced by the cuzk integration, they could document the required manual steps (e.g., cd extern/supraseal && git submodule update --init) in the build instructions. This is the quickest path but sacrifices reproducibility.

Fix Option 4 — Ignore and hope: The team could choose to ignore the issue, assuming that developers who already have the repository set up will not encounter it. This is risky for CI/CD and for new contributors.

The assistant did not attempt to fix the issue in this message. It simply surfaced the information. The decision of which fix to apply would come later, after discussion with the user.

Conclusion

The git submodule status command in <msg id=3490> is a small probe with large implications. It reveals a broken dependency link in the build chain at a critical moment — when the team is planning how to upstream a complex, multi-language proving engine into a production storage provider codebase. The orphaned sppark submodule is exactly the kind of infrastructure debt that can derail a "quick-to-prod" plan, causing cryptic build failures in CI, frustrating new developers, and undermining the reproducibility that the vendor-in-repo strategy was meant to guarantee.

The message is a testament to the value of thorough infrastructure investigation. Rather than assuming that the build system is healthy, the assistant systematically probed each layer — Rust workspace, filesystem, Git submodules — and surfaced a latent issue that might otherwise have gone unnoticed until the first CI pipeline failure. In doing so, it provided the user with the information needed to make an informed decision about how to proceed with the upstreaming plan.