# Resolved at build

Schema versions are chosen **when your app builds**, never when it runs.
Production cannot pick up a schema change without a build.

## The unit is the schema set

A **schema set** is a `.proto` tree that compiles as one — `lime-models`,
`sds-core`, `sds-events`, the juicer set — with a manifest sidecar
mapping config sets to message types. It is versioned by upload. Every
accepted version compiles a binary `FileDescriptorSet` (custom options
intact) and a protobufjs JSON descriptor, passes a breaking-change check
against the previous version, and builds the package each toolchain needs
into [the registry](/consume-a-package): npm, a Maven jar, NuGet, PyPI.

## Two channel heads per set

- **`beta`** advances on every accepted upload.
- **`stable`** moves only by an explicit promotion, with the approver
  recorded.

## Your manifest declares a channel, not a version

[`switchboard.yaml`](/manifest) names the channel you build against, per
set:

```yaml
schemaSets:
  lime-models: stable
  sds-events: stable
```

A dev branch may say `beta`. Nothing in the repository pins a version.

## The resolve step

The [shared publish workflow](/build-and-publish) runs a **resolve step
before your app's build**. For each declared set it asks the registry
what the channel currently points at —

```
GET /registry/schema-sets/{set}/channels/{channel}
```

— and gets back an exact version. The build then installs that exact
package the way your toolchain already does:

| Toolchain | What the resolve step installs |
|---|---|
| Node, protobufjs | `npm install @lime-energy/<set>@2.0.7` |
| Java, the juicer engine | `mvn -Dlime.sds.version=2.0.7` |
| C# | `dotnet add package <set> --version 2.0.7` |
| Python | `uv add lime-<set>==2.0.7` |

Your client code does not change: the same imports, the same generated
classes, the same descriptor blobs on the classpath.

## The resolved versions are recorded

The versions the resolve step chose are written onto the **build row**
beside the artifact. That is the truth about what a build carries — an
environment shows the schema versions of the build deployed there and has
no binding of its own. npm dist-tags `stable` and `beta` are published as
a convenience only.

Promoting a set to `stable` rebuilds nothing. Consumers pick the new head
up on their next build, and the console's Schema service page shows which
consumer builds carry which version.
