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 installexperience; 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: wheels | B: git tag | C: vendored | |
|---|---|---|---|
| Engine pin enforceable | yes (built-in) | weak | no |
| Integrator toolchain burden | none | Rust + ours | Rust + ours |
| Upgrade path | semver via pip | re-pin tag | manual |
| Works for R26 service operators | yes | yes | awkward |
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.