Skip to content

Change Classification

Every change detected between two versions of a spec is graded by rule: BREAKING (forces a MAJOR bump), ADDITIVE (MINOR), PATCH, or IGNORE. The component’s bump is the most severe grade present, and the library bump is the most severe component bump in the release. The rules live in a data file the CLI ships with, so specs version cut and both reports grade any given change identically.

The organizing principle

The concern split is the semver boundary. A spec’s files divide into contract and presentation, and the grade a change can receive depends entirely on which file it lives in:

Concern fileRolePossible grades
api.yaml — anatomy, props, subcomponentsThe contract consumers program againstMAJOR / MINOR (PATCH for descriptions and annotations)
variants.yaml — default, variantsThe presentation — styling, layout, bindingsPATCH, always
Examples concerns, imagesIllustrations of the contractPATCH, always

Within api.yaml the grades follow one shape. A component’s contract is the set of things code looks up by name or programs against — a part, a property, and the attributes that say what each accepts. Stating one for the first time is MINOR; changing what it says, or withdrawing it, is MAJOR. Everything else a spec carries — titles, descriptions, examples, provenance — describes the contract rather than forming it, and is PATCH.

A change confined to variants.yaml can never exceed PATCH — even a dramatic visual change, like a background token rebound from neutral to brand. The programmatic contract is untouched, so no code breaks. When a visual change deserves louder signaling, use a manual override.

One exception ladder: when a variant references something the API no longer declares (for example a configuration: keyed to a removed enum value), the grade comes from the API change, and the orphaned variant is reported as a defect rather than graded separately.

API rules

<p> is a prop name, <e> an anatomy element, <s> a subcomponent.

Props

ChangeGradeWhy
Prop addedMINORNothing that compiled before stops compiling because a new property exists
Prop removedMAJORAlways breaking
Prop renamed (recorded in renames.yaml)MAJORReported as one rename with a from → to migration line, never as remove + add
type, default, nullable, minItems / maxItems stated for the first timeMINORThe property says more about itself than it did
Any of those changed or withdrawnMAJORWhoever relied on the old value or the old constraint can break
anyOf on a slotIgnored, temporarilyIt is derived by resolving component keys against the fetched file, and those keys do not survive a branch, so the two sides are not comparable
Enum value addedMINORNew option; existing code unaffected
Enum value removedMAJORCode using the value breaks
Enum value renamed (recorded)MAJOROne rename with migration line
Enum reordered onlyPATCHOrder is presentational
description and anything else under a propertyPATCHDescribes the contract, does not form it
examples changedPATCHDocumentation, not contract
$extensions (Figma provenance)PATCHConsumers never see it

Anatomy

ChangeGradeWhy
Element addedMINORAdditive; consumers may ignore it
Element removedMAJORCode targeting the element breaks
type, instanceOf, role or an action stated for the first timeMINORThe part says more about itself than it did
Any of those changed or withdrawnMAJORStructure, binding, and behavior are all things code depends on
detectedIn, $extensions, and anything else under a partPATCHDescribes the part, not the contract

Title, subcomponents, and combinations

ChangeGradeWhy
title changedPATCHThe same component said differently — but it must still be recorded in the rename ledger, because the component name and its spec folder derive from it
title changed as a recorded renameMAJORThe component’s identity moved
Subcomponent addedMINORAdditive surface
Subcomponent removedMAJORAnything referencing it breaks
Invalid prop combinations stated for the first timeMINORThe component says more about itself than it did
Invalid prop combinations changed or no longer statedMAJORWhich combinations are unsupported is something consumers program against

Metadata

Run facts (generator version, schema version, conventions, settings) live once per run in latest.metadata.yaml — see Run Metadata.

ChangeGrade
metadata.lastUpdatedIgnored — always changes, never meaningful
Generator versionPATCH — tooling upgrade, not a component change
Schema version — MAJOR bumpMAJOR + warning — the spec now speaks a different dialect; parsers may break
Schema version — MINOR/PATCH bumpPATCH
source.nodeId changed, title unchangedNo bump — origin update, noted in the ledger (see Renames & Identity)
Conventions or settings valuesNo direct grade — their effects surface as spec diffs and are graded there; grading them directly would double-count

Assets

Generated icons, images, and CSS variables that specs reference by name:

ChangeGrade
Asset addedMINOR — new referenceable content
Asset removed while a spec still references itMAJOR — a broken reference, flagged as a defect
Asset removed, unreferencedPATCH — cleanup
Asset content changed (same name)PATCH — presentation only
CSS variable filesPATCH

Manual overrides

The automatic grade can be overridden when a version is cut, with a required reason that is recorded permanently in the ledger:

Terminal window
specs version cut --force-minor "visual break: brand background sweep"

--force-major, --force-minor, and --force-patch are the only escape hatch — there is no automatic elevation for any style change. The recorded reason keeps the history honest about why a version moved differently than the rules said.

See Also