SDK docs · adr/0002

ADR-0002 — SDK packaging & distribution

Accepted: the verifier SDK ships as versioned platform wheels with the Rust proof engine compiled in and pinned at build time — so a substituted or drifted engine cannot happen through any normal installation path.

Context

Status: Accepted (2026-07-21) · recorded 2026-07-19 · card MINT-161 · spec refs R26, §16

verifier-core is a Python package whose correctness depends on a specific, version-pinned Rust proof engine and on byte-for-byte agreement with chain store layouts, locked by a committed state-proof vector suite. An integrator must receive all of that as one verifiable unit: a mismatched engine or a stale store-layout assumption is a security defect, not an inconvenience. The distribution form had to be decided before the first external integrator existed.

Three spec constraints frame the choice: proof-verification APIs may be offered as paid off-chain services (R26), so packaging must make both embedded and service consumption practical; no API is trusted for returning JSON (§16 rule 6), so the cryptographic checks must not be silently substitutable; and proof verification lives in the pinned Rust engine while Python orchestrates — packaging must preserve the pin.

Options considered

Option A — versioned Python package with the engine compiled in (accepted)

Publish mintid-verifier-sdk as platform wheels, with the Rust engine compiled in as a native extension at a version pinned at build time and recorded in package metadata.

  • Pros: one artifact, one version; standard pip install experience; the engine pin is decided at release time and not overridable by dependency resolution; platform wheels make the Rust toolchain invisible to integrators.
  • Cons: we own a wheel-building matrix (Linux/macOS × architecture) and release engineering before the first integrator; source builds still need the Rust toolchain as fallback.

Option B — git dependency at a tag

Zero release infrastructure and always buildable from source — but every integrator needs the Rust toolchain, the engine pin lives in build configuration where an integrator can patch it, and repository access is a bad long-term distribution channel with no artifact-level integrity story. Retained only as the interim channel for design partners until the first tagged release exists.

Option C — vendored source drop (rejected)

Works in locked-down environments, but has the worst upgrade path, makes pin substitution trivial, and duplicates the build burden onto every integrator.

A: wheelsB: git tagC: vendored
Engine pin enforceableyes (built-in)weakno
Integrator toolchain burdennoneRust + oursRust + ours
Upgrade pathsemver via pipre-pin tagmanual
Works for R26 service operatorsyesyesawkward

Decision & versioning policy

Accepted: Option A, with B as the interim channel for design-partner integrators until the first tagged release exists. Versioning under Option A:

  • Semver on the SDK package: major for any change to the public surface or to accepted-behavior semantics; minor for additive surface; patch otherwise.
  • Package metadata records the engine version pin, the chain store-layout vector version, and the SPEC revision built against. A release is blocked if the store-layout vectors fail against the target chain version.

Consequences

Option A commits us to a wheel-building pipeline and a release checklist — an engine pin bump is a reviewed change, never automatic. In exchange, integrators cannot end up running an unpinned or substituted proof engine through normal installation paths: substituting one becomes a deliberate, visible act outside the supported channel, which is exactly the posture §16 rule 6 asks for.