compat

package
v1.0.0-alpha.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package compat implements publish-side catalog compatibility logic: enhancement 0010 D27's additive-only comparison walk (Check, CheckAtLevel), the D34 contract-level ladder (Level, ParseLevel, CompareAPIVersions), D9 predecessor selection (HighestStable), and the D30 provenance strip (StripProvenance).

The package is pure logic: no I/O, no registry access, no schema-cache dependency, no state. Callers compose it with member enumeration, predecessor pulling, and gate policy. Its consumers are the 0011 publish gate (`opm catalog publish`), `opm catalog registry check --compat` (0011 D7), and library-matching's D34/D30 reads (contract-key ordering, unify-rung strip).

Index

Constants

View Source
const (
	KindFieldRemoved     = "field removed"
	KindFieldAddedStrict = "field added without optional or default"
	KindDefaultChanged   = "default changed"
	KindDefaultRemoved   = "default removed"
	KindDomainNarrowed   = "domain narrowed"
)

The violation kinds. KindDomainNarrowed carries the CUE subsumption diagnostic verbatim in New (no reformatting, consistent with UnifyError); the default kinds carry the rendered defaults in Old/New.

Variables

View Source
var (
	ErrUnparseableAPIVersion = errors.New("unparseable apiVersion")
	ErrNotStruct             = errors.New("operand is not a struct")
)

Sentinel errors for CheckAtLevel's error channel. A gate that cannot classify its input has not found an incompatibility — these are failures, never violations.

Functions

func CompareAPIVersions

func CompareAPIVersions(a, b string) int

CompareAPIVersions is a total, transitive ordering over apiVersion strings, following the Kubernetes kube-aware ordering: level first (alpha < beta < GA), then major, then the alpha/beta number. It returns a negative value if a sorts before b, zero if they tie, positive otherwise.

This exists because SemVer cannot order the ladder — measured against Masterminds v3, a per-pair rule switch makes v1alpha1 < v2, v2 < v10 and v10 < v1alpha1 all true at once (0010 D34). Strings outside the grammar sort before every valid one, lexically among themselves; that branch keeps the ordering total and is not part of the contract.

func HighestStable

func HighestStable(published []string) string

HighestStable returns the highest published stable (non-pre-release) version. published is the registry's `v`-prefixed, SemVer-ascending list. Pre-release tags (e.g. v0.6.0-dev.*) are skipped so selection lands on the latest *released* build. If no stable version exists, the highest overall is returned so a pre-release-only path still resolves. Unparseable entries are skipped.

This is the FLOAT selector — "give me the latest released build" — and it is deliberately NOT the compatibility gate's predecessor selection. An earlier revision of this comment claimed it was; 0011 D23 (amending D9) corrected that: the publish gate's predecessor is found by D9's literal rule — scan published versions strictly below the effective version, same major, prereleases included, newest first — implemented gate-side in the CLI, because a stable-preferring selector coincides with that rule only on a prerelease-only history and would miss breaks that prerelease pinners (0010 D14-blessed) can see. Selection here is pure — enumerating and fetching the candidate are the caller's. Moved verbatim from opm/materialize's since-deleted filterVersions path (0010 D14). Its first true caller is template resolution's version selection (cli-template-modules), which is why it stays.

func StripProvenance

func StripProvenance(v cue.Value) (cue.Value, error)

StripProvenance removes metadata.catalogVersion and metadata.description from v — the D30 strip both the compat gate and library-matching's unify rung apply before comparing values from different catalog builds. Without it every comparison reports a violation, because catalogVersion differs between any two releases by construction.

The mechanism is a syntax round-trip: Syntax(cue.All(), cue.InlineImports(true)) → delete the denylisted fields from every metadata block → rebuild in v's own context. The strip reaches the definition as well as the instance — removing only the instance's field would leave a required `catalogVersion!` nothing satisfies, a shape Validate(cue.Concrete(false)) cannot flag if missed. InlineImports makes the emitted syntax self-contained, so values whose definitions come from imported packages rebuild without their loader. Known cost, accepted by D30: the round-trip discards document positions, so downstream CUE messages on the stripped value lose file/line — the comparator's own violations are path-located by the walk, not by CUE positions.

Types

type Level

type Level int

Level is a contract apiVersion's position on the Kubernetes ladder (enhancement 0010 D34): vNalphaM → vNbetaM → vN. The level decides whether D27's additive-only promise binds — see Level.Enforced.

const (
	LevelAlpha Level = iota
	LevelBeta
	LevelGA
)

func ParseLevel

func ParseLevel(apiVersion string) (major int, l Level, ok bool)

ParseLevel classifies a contract's apiVersion on the D34 ladder and reports its major. ok is false when the string is outside #APIVersionType's grammar ("v1alpha", "V1", "1.2.0"); D34 keys enforcement to the primitive's own apiVersion, never to the catalog's release version, which is an independent axis.

func (Level) Enforced

func (l Level) Enforced() bool

Enforced reports whether D27's additive-only promise binds at this level (D34): beta and GA yes, alpha no — alpha's definition is that it promises nothing, so the publish gate is off there.

func (Level) String

func (l Level) String() string

type Violation

type Violation struct {
	Path string // dotted path from the compared root, "" for top-level
	Kind string // one of the Kind* constants
	Old  string // rendered prior value; "" when not applicable
	New  string // rendered new value; "" when not applicable
}

Violation is one breach of 0010 D27's additive-only rule, located by the dotted path from the compared root. Violations are results, not errors (opm/errors doctrine): the walk reports every breach it finds and never fails. The primitive's name, apiVersion, and predecessor coordinate are caller-attached — the walk does not know them.

func Check

func Check(prev, next cue.Value) []Violation

Check reports every violation of D27's additive-only rule in next relative to prev: fields and options may be added and never removed; a newly added field must be optional or defaulted; an existing field's default is immutable. It is level-blind — see CheckAtLevel — and cannot fail given two valid values.

The comparison is a field-wise walk, deliberately not a single Subsume call in either direction: adding a struct field makes a value more specific while adding a disjunct makes it less specific, and D27 calls both "additive", so the rule spans both directions of the lattice while one subsume call tests one (measured 10/14 and 8/14 against the D27 change classes in enhancements/0011/experiments/03-d27-compat-gate; the walk is 14/14). Structs recurse; leaves get a forward subsume, where it is correct for the value domain; defaults are compared explicitly at every level, because subsume is blind to them in both directions.

Three rules keep the walk from reporting non-changes (measured on catalog_opm PR 51, cli issue 165):

  • 0010 D30's provenance fields are skipped at every depth: catalogVersion and description directly under any field named metadata, so a member reference embedded in another member (appliesTo, composedResources) does not report the referenced member's per-release provenance.
  • Closed lists of equal length are walked element-wise (paths name[i]), so those embedded references reach the rule above; any other list pair is a leaf.
  • A leaf whose emitted syntax is byte-identical on both sides reports nothing: it cannot have narrowed, and the forward subsume false-positives on unchanged leaves carrying matchN or a pending comprehension.

func CheckAtLevel

func CheckAtLevel(apiVersion string, prev, next cue.Value) ([]Violation, error)

CheckAtLevel is the level-aware entry point (0010 D34): the additive-only promise binds at beta and GA only, so an alpha apiVersion returns (nil, nil) without evaluating the operands. The apiVersion is the primitive's own — a catalog's release version is an independent axis and must not be passed here. An apiVersion outside core's #APIVersionType grammar is an error, as are non-struct top-level operands.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL