sparkles:versions — Scheme Catalogue and Provenance
Audience: contributors using or extending the shipped version schemes. This page is the per-scheme catalogue: it records each scheme's declared capabilities, real-world example strings, ordering rules and edge cases, native-range grammar, and the authoritative source every example was checked against. For the desired-state specification of the traits and generic algorithms, see SPEC.md.
1. Overview
This catalogue documents each shipped scheme: its purl type, real-world example strings, ordering rules and edge cases, native-range grammar, the capabilities it declares, and the authoritative source every example was checked against. For the concepts these schemes conform to (isVersion!T, isVersionScheme!S) and the capability traits, see SPEC.md.
import sparkles.versions.schemes.semver : SemVer;
import sparkles.versions.schemes.pypi : PypiVersion;
import sparkles.versions.schemes.deb : DebianVersion;
auto rust = SemVer .parse("1.78.0").value;
auto python = PypiVersion .parse("3.13.0a1").value;
auto apt = DebianVersion.parse("2:4.13.1-0ubuntu0.16.04.1.1~").value;Eleven schemes ship: semver is the SemVer 2.0.0 reference (it also drives most package managers at the value level); six are D-internal compact encodings; three (pypi, maven, deb) are structural — their ordering cannot be reduced to an integer key; and generic is the opaque baseline.
2. Capability matrix
This is the canonical capability matrix for the shipped schemes; adding a scheme adds a row here. Every scheme provides the required isVersion!T surface (opCmp + toString) and differs only in the optional capabilities below. Each yes/no is read against the traits in SPEC §3.2 (version capabilities) and SPEC §6.2 (scheme capabilities); the rationale behind each cell is in the per-scheme sections (§3).
| Scheme | orderKey | prerelease | components | build | nativeRange | loose |
|---|---|---|---|---|---|---|
semver | yes | yes | yes | yes | yes | yes |
dmd | yes | yes | yes | no | yes | yes |
dmd_compact | yes | yes | yes | no | yes | no |
tiny | yes | no | yes | no | yes | yes |
calver_yymm | yes | no | yes | no | yes | yes |
calver_yyyymmdd | yes | no | yes | no | yes | yes |
vim | yes | no | yes | no | yes | yes |
pypi | no | yes | yes | no | yes | yes |
maven | no | yes | no | no | yes | no |
deb | no | no | no | no | yes | no |
generic | no | no | no | no | no | no |
Two cross-cutting rules explain most of the table:
- The structural schemes (
pypi,maven,deb) omitorderKey— their ordering does not pack into an unsigned integer of any width (see §3.8–§3.10), so theiropCmpdoes the full structural walk. componentsis arity-free; only schemes whose list begins["major","minor","patch"]also satisfyhasSemVerComponentsand get caret^/ tilde~. The calendar schemes declare["year","month","day"]—componentsyes, caret/tilde no.
3. Per-scheme catalogue
Each subsection records: the purl type string, real-world example strings, ordering rules and edge cases, the declared capabilities (and, for structural schemes, why orderKey is omitted), parse modes, the native-range grammar where applicable, and provenance.
3.1 semver — SemVer (Semantic Versioning 2.0.0)
- purl type:
semver. The same value grammar drivesnpm,cargo,gem,composer,golang,hex,conan,nginx,mozilla, andgithub— those purl types map to this scheme via the purl→scheme table while keeping their own native-range dialects. - Examples:
20.13.1(Node.js),1.78.0(Rust),1.30.0(Kubernetes),17.3.0(Angular),18.3.1(React),6.8.9(Linux),2.45.1(Git),8.3.7(PHP),3.3.1(Ruby),1.26.0(Nginx),2.4.59(Apache httpd),7.2.4(Redis),7.0.8(MongoDB),3.45.3(SQLite),8.7.1(cURL),7.0.1(FFmpeg),14.5.1(macOS),26.1.1(Docker). With prerelease/build:1.0.0-rc.1,1.0.0-alpha.1+build.5. - Ordering (SemVer §11): compare
major, thenminor, thenpatchnumerically; a version with a prerelease has lower precedence than the samemajor.minor.patchwithout one (1.0.0-alpha < 1.0.0); prerelease identifiers compare per SemVer §11.4 (numeric identifiers numerically, alphanumeric lexically, numeric < alphanumeric, more fields wins on a shared prefix); build metadata (+…) is ignored in ordering (SemVer §10). - Edge cases:
majordominates everything —2.0.0-alpha > 1.999.999. Leading zeroes in numeric identifiers are rejected in strict mode. - Capabilities:
orderKeyyes — themajor:minor:patch:has-no-prereleaseshape packs into aulongwith the stable-flag at the LSB, so unsigned compare reproduces SemVer precedence up to the prerelease-identifier tiebreak (equal keys fall through to the fullopCmp).prereleaseyes,componentsyes,buildyes.nativeRangeyes (node-semver grammar).looseyes. - Parse modes: strict follows SemVer 2.0.0 exactly. loose additionally accepts a leading
v(v1.2.3) and partial versions (1,1.2), infilling missing components with0— this is how PostgreSQL16.3round-trips. - Native range grammar (node-semver subset): caret
^1.2.0, tilde~1.2.0, wildcard1.2.x/1.*, hyphen1.2.0 - 1.5.0, union||, AND-by-space>=1.2.0 <2.0.0, plain comparators>>=<<==. Prerelease-in-range follows the node-semver rule (a prerelease satisfies a comparator only when some comparator in the same set names a prerelease of the samemajor.minor.patch). - Provenance: semver.org 2.0.0; node-semver grammar at github.com/npm/node-semver. Example strings checked against upstream releases (nodejs/node, rust-lang, kubernetes, git, php, etc.).
3.2 dmd — Dmd (D compiler internal)
- purl type: none (D-internal; not published to a package registry).
- Examples:
2.111.0,2.079.0. The minor field is printed zero-padded to 3 digits (079), while values ≥ 100 print at their natural width (111). - Ordering: standard 3-component numeric compare with SemVer-style prerelease tiebreak; the zero-padding is a formatting property only and does not affect ordering (
2.079.0and a hypothetical2.79.0would compare equal numerically — but the parser only admits the 3-digit form). - Capabilities:
orderKeyyes,prereleaseyes,componentsyes.buildno (DMD releases carry no build metadata).nativeRangeyes — SemVer-shaped, so it inherits the SemVer/npm range grammar.looseyes. - Parse modes: strict requires the 3-digit minor; loose relaxes the leading-
vand partial-version rules as forsemver. - Provenance: dlang.org/changelog (
2.079.0and2.111.0release notes).
3.3 dmd_compact — DmdCompact (4-byte bitfield encoding)
- purl type: none (D-internal compact storage).
- Examples:
2.111.0,2.111.0-beta.2,2.111.0-rc.3. - Encoding: a 4-byte packed integer. The prerelease is encoded as a 2-bit phase (
beta<rc< stable) plus a small number, exploiting the fact that DMD prereleases follow the constrained grammarbeta.N/rc.N. Because the(phase, num)pair sits just below the stable marker in the packed integer, a single unsigned compare yields2.111.0-beta.N < 2.111.0-rc.M < 2.111.0. - Ordering: entirely via the packed integer; the phase encoding is monotone by construction.
- Capabilities:
orderKeyyes — the 4-byte packed integer is the order key, soOrderKeyType!DmdCompactisuint.prereleaseyes,componentsyes.buildno.nativeRangeyes (SemVer-shaped).looseno — the compact encoding admits only the exact canonical forms it can represent, so there is no lenient parse. - Edge cases: the reserved 4th phase code is rejected by the parser; prerelease numbers beyond the encodable range are a parse error rather than a silent truncation.
- Provenance: DMD prerelease tags on github.com/dlang/dmd/releases (
v2.111.0-beta.1,v2.111.0-rc.1, …).
3.4 tiny — Tiny (4-byte, no prerelease)
- purl type: none (internal storage-sensitive use).
- Examples:
7.8.9. - Ordering: three numeric components packed into 4 bytes; plain unsigned compare.
- Capabilities:
orderKeyyes — the three components pack into 4 bytes, soOrderKeyType!Tinyisuint.componentsyes.prereleaseno,buildno.nativeRangeyes (SemVer-shaped grammar over the three components).looseyes (partial versions infill with0). - Provenance: internal; no external ecosystem. The example exercises the no-prerelease, no-build packed path.
3.5 calver_yymm — CalVerYYMM (Ubuntu-style CalVer)
- purl type: none (calendar scheme; Ubuntu does not publish a purl type for the distro version itself).
- Examples:
24.04.1(Ubuntu 24.04.1 LTS). The month is printed zero-padded to 2 digits (04). - Ordering: numeric compare on
(year, month, patch)— chronological because the fields are most-significant-first. - Capabilities:
orderKeyyes.componentsyes — declared honestly as["year","month","patch"], sohasComponentsholds (it gets generic compare andtruncateTo!"month") buthasSemVerComponentsdoes not (a calendar version has no caret/tilde).prereleaseno,buildno.nativeRangeyes.looseyes. - Edge cases: the 2-digit month is a formatting width, not a range constraint —
24.4.1is not accepted in strict mode because the canonical form pads the month. - Provenance: ubuntu.com point-release announcements (24.04.1 LTS, August 2024).
3.6 calver_yyyymmdd — CalVerYYYYMMDD (Arch-style CalVer)
- purl type: none (calendar scheme).
- Examples:
2024.05.01(Arch Linux monthly ISO). Both month and day print zero-padded to 2 digits. - Ordering: numeric compare on
(year, month, day). - Capabilities:
orderKeyyes.componentsyes — declared as["year","month","day"];hasComponentsholds,hasSemVerComponentsdoes not (no caret/tilde for a date version).prereleaseno,buildno.nativeRangeyes.looseyes. - Provenance:archlinux.org/releng/releases (monthly ISO snapshots).
3.7 vim — VimVer (4-digit zero-padded patch)
- purl type: none (Vim's patch scheme is project-specific).
- Examples:
9.1.0400(Vim patch 9.1.0400). The patch field prints zero-padded to 4 digits. - Ordering: numeric compare on
(major, minor, patch). - Capabilities:
orderKeyyes,componentsyes.prereleaseno,buildno.nativeRangeyes.looseyes. - Edge cases: the 4-digit patch is a formatting width; Vim's running patch counter has millennia of headroom in the packed field.
- Provenance: github.com/vim/vim release tags (patch
9.1.0400).
3.8 pypi — PypiVersion (PEP 440) — structural, no orderKey
purl type:
pypi.Examples:
3.13.0a1(alpha),1.0.0.post1(post-release),2.0.0.dev1(dev-release),1.0.0+local(local version label),1!2.0.0(explicit epoch 1).Ordering (PEP 440): compare lexicographically by structured segments in this order:
epoch, thereleasetuple (numeric, zero-padded to equal length), then the pre/post/dev ranking, then the local version. Within a release, the segment classes sort:1.dev0 < 1.0.dev456 < 1.0a1 < 1.0a2.dev456 < 1.0a12 < 1.0b1 < 1.0b2 < 1.0rc1 < 1.0 < 1.0.post456 < 1.0.15 < 1.1.dev1Key facts: a dev release sorts before a pre-release of the same version; a post release sorts after the final release; a local version (
+local) sorts after the same public version, and a numeric local segment outranks a lexicographic one. An explicit epoch dominates everything (1!1.0 > 1.0).Why
orderKeyis omitted: the comparison is genuinely structural. The release tuple is unbounded in length, the pre/post/dev ranking is a small enum crossed with an unbounded number, and the local version is an arbitrary dot-separated mix of numeric and lexicographic segments. There is no fixed-width integer whose unsigned compare reproduces this order, sopypideclares nohasOrderKeyprimitive and itsopCmpwalks the structure. GenericsortandRanges!PypiVersiontherefore use the comparison-based fallback path — exactly the contract the DbI design guarantees.Capabilities:
prereleaseyes (isPrereleasetrue foraN/bN/rcN/.devN),componentsyes (thereleasetuple exposesmajor/minor/patch).buildno — the local version participates in ordering, so it is not SemVer-style build metadata.orderKeyno.nativeRangeyes.looseyes (PEP 440 normalisation: case-folding,v-prefix stripping, separator canonicalisation1.0-a1→1.0a1).Native range grammar (PEP 440 specifier set): comma-separated AND of clauses using
==,!=,<,<=,>,>=,~=(compatible release), and===(arbitrary equality).~=1.4.5means>=1.4.5, ==1.4.*. Trailing.*wildcards are supported on==/!=.Provenance:PEP 440 / packaging.python.org version specifiers (canonical ordering example verified verbatim). Example strings checked against python.org/downloads (CPython
3.13.0a1).
3.9 maven — MavenVersion (ComparableVersion) — structural, no orderKey
purl type:
maven.Examples:
1.0,1.0-SNAPSHOT,1.0-alpha-1,1.0-rc1,1.0-1.Ordering (Maven
ComparableVersion): the string is tokenised at.,-,_, and digit↔letter transitions; trailing "null" tokens (0, empty,final,ga,release) are trimmed so that1.0.0 == 1. Numeric tokens compare numerically; qualifier tokens compare by the fixed rank:alpha < beta < milestone < rc (= cr) < snapshot < ""(= ga = final = release) < spHence
1.0-alpha-1 < 1.0-beta-1 < 1.0-milestone-1 < 1.0-rc1 < 1.0-SNAPSHOT < 1.0 < 1.0-sp1. Comparison is case-insensitive (1.0-RC1 == 1.0-rc1), andalpha/beta/milestonemay be abbreviateda/b/mwhen directly followed by a number.Why
orderKeyis omitted: like PyPI, the order is structural — an unbounded alternation of numeric and qualifier tokens with the "ga beats snapshot beats pre-release" rule and trailing-null trimming. No fixed-width integer key reproduces it, somavendeclares nohasOrderKeyandopCmpcompares token lists.Capabilities:
prereleaseyes (the qualifier rank below the empty/garelease).componentsno —MavenVersiondeclares nocomponentslist because its token model has no fixed ordered set of numeric fields (the token count and kinds vary per value), and the trait is all-or-nothing so a sometimes-available prefix does not qualify.buildno,orderKeyno.nativeRangeyes (interval notation, below).looseno —ComparableVersionalready accepts essentially anything, so there is no separate lenient mode.Native range grammar (Maven version requirements): bracket interval notation —
[1.0](exactly),(,1.0](≤),[1.2,1.3](closed),[1.0,2.0)(half-open),[1.5,)(≥), and unions via comma-separated intervals(,1.0],[1.2,). Caveat preserved from the spec: because2.0-rc1 < 2.0,[1.0,2.0)includes2.0-rc1.Provenance:maven.apache.org POM version order specification and the
maven-artifactComparableVersiontest corpus.
3.10 deb — DebianVersion (dpkg) — structural, no orderKey
- purl type:
deb. - Examples:
1.2.3-4(upstream1.2.3, Debian revision4),2:4.13.1-0ubuntu0.16.04.1.1~(epoch 2, upstream4.13.1, an Ubuntu security revision ending in~). - Structure:
[epoch:]upstream_version[-debian_revision]. The epoch is an optional unsigned integer (default0) compared first; then the upstream version; then the Debian revision. - Ordering (dpkg algorithm): epoch numerically first; then upstream and revision are each compared left-to-right by alternating non-digit and digit runs. In a non-digit run, all letters sort before all non-letters, and the tilde
~sorts before everything — even the end of the string, so1.0~beta1 < 1.0and~~ < ~~a < ~ < "" < a. In a digit run, leading zeroes are ignored and an empty run counts as0. - Why
orderKeyis omitted: the dpkg algorithm is the canonical example of a non-packable order — the~-before-empty rule alone defeats any fixed-width integer key (a shorter string can sort after a longer one that ends in~).debdeclares nohasOrderKey; itsopCmpimplements the dpkg two-phase walk directly. - Capabilities:
nativeRangeyes (dpkg relations).prereleaseno (the~mechanism subsumes it but is not exposed as anisPrereleaseboolean),componentsno (the upstream version is free-form, not a guaranteed triple),buildno,orderKeyno,looseno (dpkg parsing is already permissive; there is no stricter mode to relax from). - Native range grammar (dpkg relations): the comparison relations
>=,<=,<<(strictly less),>>(strictly greater),=, each followed by a version, as used indpkg --compare-versionsandDepends:fields (e.g.>= 2.0,<< 3.0). - Provenance:Debian Policy §5.6.12 (version) and the
dpkg --compare-versionsalgorithm (~-ordering example verified verbatim).
3.11 generic — Generic (void-hook baseline)
- purl type:
generic. - Examples: any opaque string —
"build-2024-05-30","r1234","snapshot-xyz". - Ordering: plain lexicographic (code-point) comparison of the raw string. No structure is parsed.
- Capabilities: none.
orderKeyno,prereleaseno,componentsno,buildno,nativeRangeno,looseno. This is the mandated void-hook baseline: it provides only the requiredisVersion!Tsurface (opCmp+toString) and therefore exercises every generic algorithm's fallback path — comparison-basedsort, comparison-basedRanges!Generic, and the "no native range, exact versions only" branch of the VERS/purl layers. - Parse:
parsealways succeeds (any string is a validGeneric); there is noparseLooseorparseNativeRange. - Provenance: none required — it is a structural baseline, not an ecosystem mapping.
4. Adding a new scheme
A scheme is just a struct conforming to isVersionScheme!S. For the step-by-step recipe — required surface, capability declaration, conformance assertions, registration, and tests — see Add a new scheme.
5. Deferred schemes
These are catalogued for the test corpus but not shipped. The corrected real-world example strings are recorded here so future implementers do not copy the wrong forms (several appeared mangled in the original analyst catalogue).
5.1 Bucket F — hyphenless pseudo-SemVer
Versions whose alphanumeric prerelease segment lacks the SemVer - separator. Supporting them needs a per-scheme custom tokeniser at the numeric→alphanumeric boundary, which is its own design problem.
| Ecosystem | Wrong form (do not use) | Correct real-world form | Note |
|---|---|---|---|
| Go | 1.22.3rc1 | go1.22rc1 or go1.22.3 | go prefix; prerelease glued without a hyphen |
| Python (alt) | 3.12.3a1 | 3.13.0a1 | covered by pypi; listed here as the glued form |
| OpenSSL legacy | — | 1.1.1w | single-letter patch suffix |
| OpenSSH | — | 9.7p1 | pN portable suffix, no hyphen |
| Unity | — | 2023.2.1f1 | fN "final" glue suffix |
5.2 Part-2 heavyweight schemes
Schemes needing wider cores, 4+ components, or pure-alphanumeric fallback. Tracked in the design notes — open questions.
Note — 4-component arity is no longer a design blocker. With the list-based components capability, the 4-part schemes below (.NET, Windows, Chrome) are now directly expressible — each declares ["major","minor","build","revision"] and packs into a ulongorderKey. They remain unshipped only on implementation bandwidth (parser + native-range grammar per ecosystem), not on a missing abstraction. Java's 21.0.1+12 and Android's pure-alphanumeric UP1A.231005.007 still need, respectively, build-metadata-aware parsing and a no-numeric-core fallback.
| Ecosystem | Correct real-world form | Note |
|---|---|---|
| Java (modern) | 21.0.1+12 | 3-part + build; not the 4-part 21.0.1.2 |
| .NET assemblies | 8.0.0.0 | 4-part Major.Minor.Build.Revision |
| Windows | 10.0.19045.3324 | 4-part heavyweight |
| Google Chrome | 125.0.6422.60 | 4-part heavyweight |
| Android builds | UP1A.231005.007 | pure-alphanumeric; bypasses any numeric core |
6. Provenance appendix
Every example string baked into this catalogue was checked against an authoritative source before inclusion. The structural-ordering rules for the three non-packable schemes were verified verbatim against their canonical specifications.
| Scheme | What was verified | Source |
|---|---|---|
semver | 2.0.0 grammar + §11 ordering; npm range grammar | semver.org/spec/v2.0.0; node-semver |
dmd / dmd_compact | 2.079.0, 2.111.0, beta/rc prerelease tags | dlang.org/changelog; dlang/dmd releases |
tiny | packed no-prerelease path | internal |
calver_yymm | Ubuntu 24.04.1 LTS point release | ubuntu.com |
calver_yyyymmdd | Arch 2024.05.01 monthly ISO | archlinux.org/releng/releases |
vim | patch 9.1.0400 | github.com/vim/vim |
pypi | PEP 440 ordering example (verbatim); 3.13.0a1 | packaging.python.org version specifiers; python.org |
maven | qualifier order + interval notation (verbatim) | maven.apache.org POM version order |
deb | dpkg ~-ordering rule (verbatim); epoch/revision | Debian Policy §5.6.12 |
generic | structural baseline; no ecosystem | n/a |
→ SPEC.md — desired-state specification (traits, Ranges!V, VERS, purl) → PLAN.md — delivery milestones