# Versioning and compatibility

One semantic-version scale applied to five things, including the one you did not choose to version (your source's schema).

## Overview

Four things in Amfelt carry a version you would expect: the data contract, the project, each plugin, and the agent. A fifth carries one you did not ask for: your source's schema, which Amfelt versions on your behalf every time it changes.

All five use the same scale, and it means the same thing each time: **major breaks consumers, minor adds without breaking, patch changes nothing a consumer can see.**

## What carries a version

**Contracts** get a new version per discovery run rather than being edited in place, so the contract a given load ran against is always recoverable.

**The project** carries its own version in the project file, alongside the configuration it describes.

**Plugins** can be pinned per project. For a pinned plugin, the project's Git history shows the version each commit asked for; for an unpinned one, a run's events name the version the agent started.

**The agent** is released independently of the connectors it loads, which is why a dialect fix does not require an agent upgrade.

## Your source schema is versioned too

This is the part that is not obvious. When a source changes (a column appears, a type widens, something is renamed), Amfelt compares the new shape against the contract and scores the difference on the same scale.

| Bump | What changed | What it means for consumers |
| --- | --- | --- |
| Patch | A nullable column added, metadata edited, a physical type widened | Nothing reading the object needs to care |
| Minor | Additive change: a new required column, a loosened constraint | Existing consumers keep working; there is more available |
| Major | A column dropped, renamed, or narrowed; a tightened constraint; a changed key | Something already reading this may stop working |

Where several changes arrive together, the run takes the highest. One dropped column among twenty additions is a major change.

The scoring is about **impact on whatever consumes the object**, not about effort on the source side. A single renamed column is trivial to make and is nonetheless major, because every query naming that column is now wrong.

## Compatibility is judged in the contract, not on the wire

Comparison happens in the contract's own logical vocabulary: the same seven categories and structured dimensions that [type resolution](/docs/concepts/type-resolution/) uses. That is deliberate: consumers contract against the contract, so the contract's vocabulary is where compatibility is actually measured. Arrow is how data travels, and a change is not more or less breaking for having traveled.

The comparison is deterministic. The same two contract versions always produce the same verdict, which is what makes a drift record worth keeping as an audit trail.

## Patch does not mean no work

Worth stating plainly, because it catches people: a patch is a promise about **consumers**, not about your data platform.

Widening `int` to `bigint` breaks nothing that reads the column, so it scores as a patch. The target table still needs its column widened before the wider values fit. Patch means nothing downstream will break; it does not mean nothing has to happen.

## Renames are proposed, never assumed

A rename looks exactly like a drop plus an add. Amfelt infers one when a single dropped column and a single added column share a logical signature, flags it as a candidate, and scores it major.

It is never applied automatically. An inferred rename that is actually a drop and an unrelated add would silently reinterpret a column's meaning, and that is not a mistake worth making quickly. Ambiguous cases stay a drop and an add.

## Policy

A project declares what should happen at each level: at the project level, and overridden per source, with pattern-based overrides for individual objects or columns. The [project file reference](/docs/reference/project/) documents the field.

Automatic enforcement at run time is on the roadmap. Today, classification is what runs: drift is detected, scored, and surfaced against the source in the catalog for you to act on. See [review schema drift](/docs/guides/catalog/review-schema-drift/) for what that looks like in practice.

## Next

- [Review schema drift](/docs/guides/catalog/review-schema-drift/): reading and acting on a classified change
- [Review the data contract](/docs/guides/sources/review-the-data-contract/): correcting the contract a change is scored against
- [Plugins](/docs/concepts/plugins/): how connector versions are pinned
