Skip to content
SHC Docs

ADR-0004 — Hermetic default test lane, engine fidelity lane

  • Status: Accepted + landed (2026-06-22, commit ffc21f2c9). Updated after the raft engine moved to an external rqlited process (see the last consequence below).
  • Enforced by: scripts/arch-fitness.sh check no-cgo-sqlite (hard-zero).

make test/unit ran against a real node of the old embedded-raft engine (libdqlite) under CGO, so a contributor could not run the suite without the libdqlite/autotools toolchain. A pure-Go sqlite parity backend already existed (testsupport/dbtestreg/register_sqlite.go) but was never wired to a make target — the default lane stayed cgo-coupled for no reason.

Two lanes:

  • make test/unit (default, hermetic): CGO_ENABLED=0, no engine build tag, no configure prereq. The modernc.org/sqlite parity backend rejects DML+RETURNING exactly as the raft engine does. Runs with a bare go/make, no native toolchain.
  • Fidelity lane: the original embedded-engine + CGO lane, exercising the three real-raft/driver-specific tests the hermetic lane skips.

The one CGO test (migrate_squash_test.go, the only mattn/go-sqlite3 importer) was swapped to pure-Go modernc.org/sqlite (driver "sqlite").

CI should run both lanes (hermetic everywhere for speed; the fidelity lane on a runner that has the engine available) so the fidelity tests keep coverage.

  • go test ./...-style hermetic runs work without cgo.
  • Paths stay enumerated (./cmd/... ./... ./pkg/... ./tests/unit/...), never ./..., to dodge the dh-golang obj-*/ GOPATH tree.
  • Reintroducing mattn/go-sqlite3 fails the build.
  • Post-rqlited update: the raft engine is now an external rqlited process (core/rqlited), so the CGO build split — and with it the fidelity lane as a separate build — is gone. Engine-fidelity coverage now comes from the live-engine tests (rqlited process, cluster join, engine flip), which skip unless a rqlited binary is resolvable (SHC_RQLITED_BIN, or make vendor/rqlite on Linux). The hermetic default lane and the parity backend’s DML+RETURNING rejection survive unchanged: rqlite’s /db/execute returns results, not rows, so the constraint still holds on the cluster engine.