feat(ir): enforce irVersion and record the compatibility policy - #329
Merged
Conversation
The version rule holds every hand-built document to carrying a stamp, and this branch stamped the fixtures that existed when it was written. #319 landed afterwards with new ones, so nine tests in ir/irverify fail once the two meet: bigval_test.go and kinds_test.go build documents with no irVersion, and the rule reports ir/ir-version-absent on each. Nothing warned. The merge is textually clean and the tree compiles; only running the suite shows it. Resolved by stamping those eight fixtures, for the reason this branch already gives for the ones it stamped: a fixture built to exercise one rule must contribute no violations of its own. The package's other unstamped documents are left alone — their tests assert that a particular violation is present rather than an exact set, so the stamp would change nothing and adding it would be churn.
OmarAlJarrah
force-pushed
the
feat/ir-version-enforcement
branch
from
August 9, 2026 10:43
d9ac3a8 to
d915bca
Compare
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.
Summary
Document.IRVersionwas written by exactly one line in the OpenAPI compiler and read bynothing. A document with an absent, empty, stale or nonsense
irVersionpassedirverifyand
pass.Validatewith zero violations and zero diagnostics, so a compiler that forgot thestamp — or a document written by an older generation of the schema — was indistinguishable
from a current one. This adds the read side and writes the policy down.
ir.CompatibleVersion(v) boolis the compatibility predicate: exact equality with their.IRVersionthe consumer was built against. Every bump this constant has taken changedthe JSON shape (0.2.0 split
Preserved/RawConfig, 0.3.0 renamed it toUnmodeled), sothere is no looser relation to admit — a differing patch, a prerelease suffix and a value
that is not a version at all are equally unreadable.
irverifygained a version rule (ir/irverify/version.go), reportingir/ir-version-absentfor a document carrying no stamp andir/ir-version-incompatiblefor one this build cannot read. Two codes because the failures name different writers:
absence is a producer that forgot, and it is the failure
omitemptyhides best, since adocument without the key is byte-identical to one that never had it.
docs/ir-design.md§2.1 records the policy: what the version names, what moves it,what a bump obliges compilers and emitters to do, what a consumer does on mismatch, and
the fact that every committed golden embeds
irVersionso a bump rewrites the wholesnapshot corpus.
Why a
Violationand not anir.Diagnostic. The two channels are for different authors:ir.Diagnosticreports a problem in someone's source spec,irverify.Violationreports ourown bug. An unstamped document is a producer defect and an incompatible one is a fault in the
toolchain pairing; neither is a spec problem. A
Diagnosticalso lives inside the document,which is the wrong place to record that the document cannot be read.
Where enforcement lives. In
irverify.Verify, which is the gate every consumer runs beforetrusting a document, whether it was just compiled in memory or decoded from JSON. Nothing in
the tree decodes a persisted
Documenttoday, so there is no loader to attach a separate checkto;
ir.CompatibleVersionis the predicate one will call when it is written (#76 is the firstconsumer that will need it), and §2.1 says so.
Out of scope, deliberately: no migration machinery. There is no converter between schema
generations and none is planned — a document written by another generation is re-compiled from
its source spec. That is stated in §2.1 rather than left implicit.
The hand-built fixtures that reach
irverify.Verifynow carry the stamp, for the same reasonthey already carry IDs and names: a fixture built to exercise one rule must contribute no
violations of its own. The five test documents that hard-coded a long-stale
"0.1.0"now useir.IRVersion.Test plan
ir/irverify/version_test.go— absent, and four incompatible spellings (older generation,newer generation, non-version, whitespace-padded), each asserting the single expected code
and the
doc.IRVersionpath; a clean control; and a round-trip case proving invariant 7 isintact, marshalling a valid document, decoding it, verifying it clean, and re-encoding to the
same JSON.
ir/document_test.go—TestCompatibleVersionpins the exact-match policy across eightspellings including a differing patch and a prerelease suffix.
Verifyreddens the versiontests. Separately, deleting the compiler's stamp line reddens
TestVerify_Corpusand theharness corpus sweep — those were green on
mainwith the stamp deleted, which is theacceptance criterion the check exists for.
gofmt,go vet,golangci-lint,go build, coverage at exactly 100%.Closes #70