ci: apidiff API-compatibility gate with golden baselines#127
Merged
Conversation
Make the pre-1.0 stability contract in docs/stability.md mechanical (critic-fix #15). ci-check.sh now diffs each public importable package against a committed golden baseline via golang.org/x/exp/cmd/apidiff and fails closed on any INCOMPATIBLE change; additive changes pass. - Pin apidiff version, install on demand (matching golangci/govulncheck). - Commit golden baselines under api/ for via, h, on, sess, mw. - api/regen.sh rewrites the baselines for intentional public changes. - apidiff exits 0 even on breaks, so the gate greps the "Incompatible changes:" header and fails closed. - Document the regen workflow and the whole-package caveat: the gate is a no-silent-public-break detector; the Core-vs-experimental tier call is made in review against docs/stability.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Finding #15 — make the stability contract mechanical
docs/stability.mddefines the pre-1.0 stable Core vs EXPERIMENTAL surface, but it was review-hope: nothing stopped an accidental incompatible change to the public API from landing. This adds a CI gate that enforces "no silent public break" mechanically.The gate
ci-check.shgains an API compatibility step that, for each committed golden baseline, runsgolang.org/x/exp/cmd/apidiffagainst the current package and fails closed on any INCOMPATIBLE change. Additive (compatible) changes pass.v0.0.0-20260603202125-055de637280b), installed on demand — same pattern as the existing golangci-lint / govulncheck installs.Incompatible changes:header and fails the build if found.Golden baselines
Committed under
api/for the public, importable packages:github.com/go-via/viaand its/h,/on,/sess,/mw.internal/,viashowcase, plugin example dirs, and test-only packages are excluded — not part of the importable surface.The baselines are gob-encoded binary (apidiff's on-disk format), marked
binaryin.gitattributes. They are not caught by the existing "no committed binaries" check (that matches executable mime types, notdata).Regen workflow
./api/regen.shrewrites all baselines. An intentional public change is landed by regenerating + committing the baseline; the source diff is the readable review artifact, and the baseline changing signals the API moved.Whole-package caveat
apidiff works at whole-package granularity — it cannot subset stable-Core from EXPERIMENTAL symbols. So the gate is a no-silent-public-break detector; the Core-vs-experimental tier call is made in review against
docs/stability.md(documented in the new "Enforcing the contract" section).Gate-behavior proofs
Incompatible → FAILS (scratch edit changing
via.Newsignature, then reverted):Additive → PASSES (scratch new exported
func ScratchAdded(), then reverted): API step exit=0.Regen reproduces baselines byte-for-byte (no dirty diff after rerun) and full
./ci-check.shpasses green.