Our synthetic build manifest selects a dependency that needs a newer Rust compiler than the compiler recorded for the optimizer image. The same source builds on a developer machine and fails in the container. Pinning the container alone has not pinned a compatible build.

We construct an independent compatibility fixture around three inputs. They are the source dependency graph and the build toolchain and the target runtime profile. The JavaScript checks compare invented manifests and validate a minimal WebAssembly header. They do not compile Rust or certify a CosmWasm contract artifact.

Capture the dependency graph and the compiler

Cargo.toml expresses dependency requirements while Cargo.lock records the selected dependency graph. A broad requirement can select a release whose minimum Rust version exceeds the compiler bundled into an older optimizer image. The failure can surface while parsing a dependency before the contract itself is compiled.

A Rust edition is another compatibility input. Selecting an edition requires a Cargo and compiler toolchain that understands it. Looking only at the top level package's edition does not establish compatibility for every transitive dependency in the selected graph.

function validateBuild(build) {
  for (const dependency of build.dependencies)
    if (!atLeast(build.compiler, dependency.minimumRust))
      throw new Error("compiler requirement");
  for (const feature of build.wasmFeatures)
    if (!build.runtimeFeatures.includes(feature))
      throw new Error("runtime feature");
  return true;
}

The fixture rejects an incompatible dependency before considering the runtime profile. A compatible compiler is necessary for building the artifact but says nothing about whether the target chain accepts the Wasm that results.

Pinning is an operational policy

An image tag is a convenient name and an image digest identifies particular image content. Recording both helps explain what was intended and what actually ran. The lockfile and enabled Cargo features belong beside that record because changing either can produce a different build from the same contract source.

When a dependency exceeds the selected toolchain there are two ordinary remedies. Upgrade the build environment after validating the target artifact or constrain dependency resolution to a compatible release. Either choice should document why the version boundary exists and how it will be revisited.

We record the optimizer identity alongside the lockfile and feature selection because a reproducible source checkout does not establish a reproducible contract artifact when dependency resolution can change or the container supplies a different compiler or the build enables a host feature that the intended chain runtime does not accept.

A temporary dependency constraint is not a permanent security policy. The build should retain a procedure for reviewing later compatible releases and for testing an upgraded toolchain. Otherwise the successful workaround gradually becomes an unexplained obstacle to maintenance.

Compilation and runtime acceptance differ

A Wasm module can be structurally valid while missing CosmWasm entry points or requiring unavailable imports. A chain runtime can also reject unsupported Wasm features. Host compilation tests and native Rust unit tests do not exercise that exact artifact acceptance path.

The fixture validates the standard eight byte empty Wasm header using the local JavaScript engine. That module has no CosmWasm exports and is intentionally not deployable as a contract. The check demonstrates why a generic Wasm validator supplies a narrower claim than a target chain integration test.

Compatible manifest accepted; compiler and runtime mismatches rejected
8 assertions passed

For a real CosmWasm build we inspect the optimized artifact using the compatible contract validation tooling and then store and instantiate it on the intended local chain version. An artifact checksum ties that integration result to the exact bytes later reviewed for deployment.

Rebuild from a clean input set

Container cache volumes can speed a build without becoming part of its specification. A clean build should resolve the same locked inputs and produce an artifact that can be compared under the project's reproducibility expectations. Matching source revisions alone is insufficient evidence when the optimizer image changed.

The example's tests reject a newer compiler requirement and an unsupported runtime feature independently. They also accept a compatible manifest so the validator does not pass merely by rejecting every input. These checks enforce the declared manifest policy and make no numerical claim about contract size or gas savings.

Two clean workspaces provide a direct check of the build recipe. Use the recorded image digest and lockfile in both and compare the optimized bytes before treating that input description as sufficient to reproduce an artifact.

Sources and examples