vendor_libs, Makefile: record where lib/ and vec/ came from in vendor.json

Problem. make vendor copies transpiled Go from sibling checkouts of modernc.org/libsqlite3 and modernc.org/libsqlite_vec, neither of which is a module dependency, so nothing in the repository says which revisions produced the lib/ and vec/ a release carries. IRP.md's "Which versions?" has no answer for generated code, and a checkout that was dirty or on the wrong commit leaves no trace.

Change. make vendor gets a first and a last step, both in vendor_libs/stamp.go. -preflight runs before anything is touched and refuses a dirty sibling checkout, two checkouts requiring different modernc.org/libc, or a libsqlite_vec whose required libsqlite3 resolves to another commit than ../libsqlite3 is at. Dirty means git status with the local configuration overridden, or any file vendoring reads not matching its committed blob, which also catches ignored, assume-unchanged and skip-worktree files. -stamp runs after the cross-builds, checks that nothing moved during the run, and writes vendor.json: both commits and their tags, what their go.mod files require, the Go toolchain, the undup pin, and a digest of the 502 files make vendor produces. internal/vendorstamp checks the file against go.mod and against the files on disk. vendorstamp_test.go runs that check in the suite, so the builders go red on a dirty or stale stamp, and a new CI job runs it alone in a few seconds. The recipe now runs under GOTOOLCHAIN=local with that toolchain's own gofmt.

Why the toolchain is recorded. Vendoring from v1.14.5 and v0.5.0 reproduces master's lib/ byte for byte, and vec/ only under Go 1.27: gofmt from Go 1.22 through 1.26 drops two lone // comment lines in vec/vec.go that 1.27 keeps. The committed vendor.json comes from a full make vendor under Go 1.27, all 20 targets, which left lib/ and vec/ unchanged. Its digest can be checked without Go: shasum -a 256 lib/sqlite*.go vec/vec*.go LICENSE-SQLITE_VEC | LC_ALL=C sort -k2 | shasum -a 256.

Limits. requires is what a checkout's go.mod declares, not proof of what generated it; libsqlite_vec's generator fetches @latest. A change made to a checkout and undone before the run ends is not seen. Master is checked after the push, so it is the builders that keep a bad stamp out of a tag. A checkout that converts line endings counts as dirty, since vendoring reads raw bytes.

Tested. 38 subtests in internal/vendorstamp: every refusal, the output digest, line-ending conversion, go.mod syntax. Seven refusals of the tool reproduced against scratch worktrees of the siblings: an untracked file, an untracked input hidden by status.showUntrackedFiles=no, an edit under assume-unchanged, a skip-worktree input missing from disk, libsqlite3 at v1.14.5~1 (untagged, same go.mod), different libc versions, and a tag added mid-run. The root test fails after a hand edit of lib/sqlite_linux_amd64.go and passes once it is reverted. Both CI jobs pass in golang:1.27.

Merge request reports

Loading
Loading