# Versioning &amp; Stability

Sandloom follows [Semantic Versioning](<https://semver.org/>). This page defines what "public" means and the compatibility guarantees for each surface.

## What is public

The stable, supported surface is the `sandloom.sdk` namespace ([ADR-0010](<https://sandloom.dev/docs/adr/0010-public-api-1.0/index.md>)) — the only framework code a business module and its tests may import, together with generated contract stubs and contract DTOs:

- `sandloom.sdk` — the beginner names, re-exported from the modules below.
- `sandloom.sdk.module`, `sandloom.sdk.app`, `sandloom.sdk.migrations`, `sandloom.sdk.tooling` — module declaration, the app composition root, migration runners, CLI entry points.
- `sandloom.sdk.web`, `sandloom.sdk.data`, `sandloom.sdk.tenant` — routes, sessions and dependencies; `Base`, `TenantScoped`, `db()` and the read planner; tenant binding.
- `sandloom.sdk.events`, `sandloom.sdk.effects`, `sandloom.sdk.contracts`, `sandloom.sdk.sagas`, `sandloom.sdk.projections` — cross-module communication and effects.
- `sandloom.sdk.authz`, `sandloom.sdk.security`, `sandloom.sdk.infra`, `sandloom.sdk.errors` — authorization, token and session security, capabilities, exceptions.
- `sandloom.sdk.testing` (with `sandloom.sdk.testing.fixtures` and `sandloom.sdk.testing.plugin`) — the test kit.

Each module declares `__all__` and `__beginner__` (the beginner tier is a subset); the [SDK reference](<https://sandloom.dev/docs/reference/sdk/index.md>) is generated from them. `public_api_baseline.json` records every public name and signature, and a change fails `sandloom test` (SANDLOOM-T008) until it is reviewed.

`sandloom.driverkit` is public for driver packages. Its contracts are versioned: a breaking change is a new contract version, and a driver written for another major version is refused at load (SANDLOOM-B022). A contract joins it only with a conformance kit in `sandloom.driverkit.testing`. Calling a capability from a module is the stable promise; implementing one moves with the contract version.

Everything else (`sandloom.core.*`, modules under `sandloom.sdk` whose name starts with an underscore, `sandloom.shared.authz`, `sandloom.shared.guards`) is **internal** and may change in any release without notice. `sandloom check` blocks imports of internals from business modules (SANDLOOM-C002) and their tests (SANDLOOM-C013).

## Compatibility guarantees

Public prereleases (`a`, `b`, `rc`) may change APIs between prerelease versions without a deprecation window. Breaking changes must be listed in release notes and include upgrade instructions. Pin the version used by your application and review these changes before upgrading. This does not relax versioned event or service-contract compatibility checks.

The guarantees below apply to releases without a prerelease suffix.

Within a major version (`0.x` while pre-1.0, `x.y` thereafter):

- **No removal or breaking change** to a public symbol's signature without a major bump. Additive changes (new optional parameters, new helpers) are minor.
- **Deprecation before removal:** a public symbol is marked deprecated for at least one minor release (with a documented replacement) before removal in the next major.
- **Pre-1.0 caveat:** at `0.x`, minor versions may contain breaking changes; they are called out in the [Changelog](<https://sandloom.dev/docs/changelog/index.md>).

## Release line and distributions

The framework, the `sandloom` distribution, has one release line (`0.6.0`, `0.7.0`, …), recorded in the [Changelog](<https://sandloom.dev/docs/changelog/index.md>) with an upgrade guide per breaking release (e.g. [Upgrading to 1.0](<https://sandloom.dev/docs/operate/upgrade-1.0/index.md>)).

The module packages `sandloom-identity`, `sandloom-tenancy` and `sandloom-billing` (see [Publishing](<https://sandloom.dev/docs/contributing/publishing/index.md>)) **version independently**, like any third-party module: each has its own version and changelog. The current published alpha is `0.7.0a6`; each module depends on a compatible framework range, `sandloom>=0.7.0a6,<0.8` (for a `0.x` framework the next minor is the next breaking release). No module package depends on another. A module release that needs a newer framework widens or moves its range; a framework minor release requires each module package to release a version whose range admits it.

Third-party dependencies are ranges too (`>=tested,<next breaking release`); exact versions live only in `uv.lock`. The `sandloom new` generator depends on `sandloom[redis,celery]>=0.7.0a6,<0.8` plus `sandloom-<module>>=0.7.0a6,<0.8` for each `--with` module, since the code it generates uses that release's API.

## Event schema evolution

Event channels are versioned independently of the package, in the channel name (`<module>.<event>.vN`). The compatibility policy is normative and enforced at schema registration time — see [Event Contracts → Evolution policy](<https://sandloom.dev/docs/reference/event-contracts/#4-evolution-policy>).

In short: additive, optional changes are allowed in place within `vN`; any breaking change requires a new `vN+1` channel, and producers may dual-publish during a migration window.

## Service contract evolution

Sync service contracts (`@contract("name.vN")`, called through `Contract(REF)`) carry the same major version in their name. A breaking change to a contract's method signatures is a new `vN+1` contract; the old one is kept until consumers migrate.

## Configuration

Settings (env vars) are part of the public surface. Renaming or removing a setting, or changing its default in a behavior-changing way, is a breaking change and is noted in the [Changelog](<https://sandloom.dev/docs/changelog/index.md>). New settings with safe defaults are additive.

## Database migrations

Each module owns its own migration chain (per-module-per-database). Migrations are forward-only in production; a breaking schema change ships as an additive, backward-compatible migration plus a follow-up cleanup, never an in-place destructive change against live data.
