# Compatibility: versions and language lines Compatibility in this corpus has three independent dimensions: the package version, the language line the package is written against, and the canon profile that pins a releasable set. This page explains each one and how they combine. Environment: the observed transcript below comes from the public `law-v0.1.1` release run over the [lab bundle](/corpus/lab/#before-you-start). Status letters follow the [legend on the topic index](/corpus/#how-this-topic-marks-confidence). ## Version grammar is wide; selection is narrow Example first. Four version strings and what happens to each: | Version string | Legal? | Selected automatically as "latest"? | |---|---|---| | `0.2.0` | yes | yes: a structured stable number | | `0.3.0-rc.1` | yes | no: a pre-release | | `2026-09` | yes | no: not structured numbering; install it by exact pin | | `-1` | no: a version must start with a letter or digit | — | The lab shows selection at work. After revision `0.2.0` of `labparcels.registry` is published next to `0.1.0`, the currency check over the fees package reports the newer stable version. Verbatim, from the lab's [versions exercise](/corpus/lab/solutions/#versions-exercise): ```text lab ← /tmp/lab-work/registry (--registry) labparcels.iface@0.1.0 [lab]: up to date labparcels.registry@0.1.0 [lab]: published 0.2.0 ``` What this result means: `0.2.0` is the version a dependency command would pick for `labparcels.registry` when no version is named. The pin in the lock still says `0.1.0`, and nothing changes until someone moves it with `law update`. The number alone does not justify the move; the consumer's scenarios do. The rule behind the table: a package version must start with a letter or digit, followed by letters, digits, dots, underscores, pluses, or hyphens. Structured `major.minor.patch` numbers with optional pre-release and build parts are only a selection convenience on top of that grammar. A version outside structured numbering is therefore a legal state, not a manifest error; such a release simply takes no part in automatic latest-version selection. The source comment that states this rule: ```text /// A package version §10 admits a wider shape (`^[0-9A-Za-z][0-9A-Za-z._+-]*$`), /// so "not semver" is a legal state, not a manifest error: such a /// release simply takes no part in automatic latest-version selection. ``` Consequences for upgrades: - A version that is not structured numbering is legal and stays installable by exact pin. It is never auto-selected as "latest". - Pre-releases are excluded from latest-stable selection. - Structured numbering is not a promise of compatible behavior. Exact pins in the manifest and lockfile decide what you get; the number never does. **Available in the public release** (S). The [Versions protocol](/protocols/versions/) is the normative reference for this behavior. ## Language lines: 0.1 versus 0.2 The `0.2` language line is frozen: only additive revisions extend it. A world links exactly one semantics line, and closures that mix lines are refused at resolution time. The lockfile records the line of the linked world, so a later run still evaluates under the same semantics. (S) The semantics line alone replays nothing. Repeating a saved result years later needs three more things beside it: - the saved toolchain: the exact build tools, pinned by hash; - the input artifacts: the release bytes plus the saved evaluations; - the replay mechanism, which re-runs those evaluations and compares the result bytes. Lose any of the four and the outcome is a fresh computation, not a replay. When you record a result, record the full `law version` output with it; the block this page was written against is under [Reproduction details](#reproduction-details). ## Canon profiles pin a releasable set A canon profile (`law.profile/0.1`) pins a named set of packages with exact versions, content hashes, calendars, and the required semantics revision. It is one reviewable unit: a manifest adopts it through its profile slot, and the lockfile then carries it under its resolution hash. The observed top-level fields are: ```text Arxo canon profile 0.1 | schemaVersion, id, version, kind, title, asOf, language, semanticsRevision, packages, calendars, contentHash ``` `calendars` appears only where a calendar is pinned; the remaining fields are present on every observed profile. The `kind` value (`jurisdiction`, `discipline`, `tradition`, or `custom`) is descriptive only. Profiles nest transitively. Registry descriptors carry a signed profile form, so graphs can be checked before any bytes download. (S) A worked example over the lab fixtures (`labparcels.iface`, `labparcels.registry`, `labparcels.fees`, `labparcels.appeals`, `labparcels.case1`) shows how a locked world keeps every member on one line; the [lab tour](/corpus/lab/) walks through it. ## Reproduction details
Toolchain, hashes, and full transcripts The pinned toolchain at the time of writing reports itself as follows (stdout of the version command; build warnings on standard error omitted): ```text $ law version law 0.1.1 semantics: law.core/0.2 std for language 0.2: 0.2.0 lawql: lawql/1 (queryResult 0.1) binary hash: sha256:cfa7c17232f2dc594e665dbbf2ad3c154675797ef4be07ef7d758c9abfb80a28 ``` Quote these five lines when recording what a result was computed with.
## What to read next - [Versions protocol](/protocols/versions/) for the normative rules. - [Schema catalog](/protocols/schemas/) for the lockfile and profile formats. - [Command-line reference](/cli/) for the package and world commands.