Zillowe FoundationZillowe Documentation

Version Forms

The canonical, contextual, semantic, symbolic and shorthand ZFVM forms.

ZFVM defines one canonical form and several projections of it. Each projection is lossy, and each states what it drops.

Canonical Full Form

[Branch] [Status] [X.Y.Z] [Build]

This is the complete, unambiguous representation, and the only form that round-trips. It is recommended for git tag annotations, changelogs, and release notes.

Because it contains spaces, it is awkward for identifiers that forbid them. Where a machine-readable identifier is required, use a symbolic form alongside it rather than instead of it.

use zfvm::Version;

fn main() -> zfvm::Result<()> {
    assert_eq!(
        Version::parse("Pub Alpha 0.8.0 a7d3c1f")?.to_canonical(),
        "Pub Alpha 0.8.0 a7d3c1f"
    );
    Ok(())
}

Contextual Form

[Status] [X.Y.Z] [Build]

Valid only where the branch is already unambiguous, such as a CI pipeline pinned to one branch. It cannot be parsed back into a complete version, so it must not be used where the branch is otherwise unknown.

Semantic Form

X.Y.Z

A bare SemVer number. It asserts API compatibility and nothing else, carrying no branch or status information.

A bare SemVer string is never interpreted as a ZFVM version. Earlier drafts of the specification gave 1.2.3 a second meaning as shorthand for Prod Release 1.2.3, which made the string ambiguous. To assert a production release compactly, use the shorthand form.

Symbolic Forms

Three symbolic forms exist. All omit the build component.

Form A, acronyms (recommended). D-B-1.2.3. Every token is unambiguous and free of internal hyphens, so this is the right choice for container image tags, file names, and URL slugs.

Form B, long names. Dev-Beta-1.2.3. Mirrors the canonical form directly and is common in release tooling. It cannot be parsed by splitting on -, because Pre-Alpha contains a hyphen.

Form C, indices (deprecated). b2s3-1.2.3. Deprecated in specification version 2.1 because it encodes table positions as data: inserting a status level would silently change every generated string. It remains supported for reading existing tags.

use zfvm::symbolic;
use zfvm::Version;

fn main() -> zfvm::Result<()> {
    let version = Version::parse("Dev Pre-Alpha 0.1.0")?;

    assert_eq!(version.to_symbolic_acronym(), "D-PA-0.1.0");
    assert_eq!(version.to_symbolic_long(), "Dev-Pre-Alpha-0.1.0");
    assert_eq!(version.to_symbolic_index(), "b1s1-0.1.0");

    // Every symbolic form round-trips, though it drops the build.
    let parsed = symbolic::parse_acronym("D-PA-0.1.0")?;
    assert_eq!(parsed, version.with_build(None));

    Ok(())
}

Shorthand Form

For production releases only:

  • v1 implies Prod Release 1.0.0
  • v1.2 implies Prod Release 1.2.0
  • v1.2.3 implies Prod Release 1.2.3
use zfvm::Version;

fn main() -> zfvm::Result<()> {
    assert_eq!(
        Version::parse("Prod Release 1.2.3")?.to_shorthand().as_deref(),
        Some("v1.2.3")
    );

    // The shorthand is defined only for Prod plus Release.
    assert!(Version::parse("Dev Release 1.2.3")?.to_shorthand().is_none());
    assert!(Version::parse("Prod RC 1.2.3")?.to_shorthand().is_none());

    Ok(())
}

The v is notation rather than part of the value, matching the SemVer convention that v1.2.3 is a tag name. The ZFVM shorthand v1.2.3 and a git tag named v1.2.3 are different things that happen to look alike.

Reading Release Tags

Release tooling should use the symbolic module rather than splitting a tag on -:

use zfvm::symbolic;

fn main() -> zfvm::Result<()> {
    // A positional split of this tag yields status `pre` and core `Alpha`,
    // neither of which is valid. Vocabulary matching handles the hyphen.
    let (branch, status, core) = symbolic::parse_tag("Prod-Pre-Alpha-0.1.0")?;

    assert_eq!(branch.as_str(), "Prod");
    assert_eq!(status.as_str(), "Pre-Alpha");
    assert_eq!(core.to_string(), "0.1.0");

    Ok(())
}

For the branch prefix alone, parse_tag_branch returns just the branch, which is what a lookup by release channel needs:

use zfvm::symbolic;

fn main() -> zfvm::Result<()> {
    assert_eq!(
        symbolic::parse_tag_branch("Pub-RC-2.0.0")?.as_str(),
        "Pub"
    );
    Ok(())
}

Projection Table

The canonical form and its projections, for reference:

CanonicalContextualSemanticSymbol ASymbol BSymbol CSemVerShorthand
Prod Release 2.0.0Release 2.0.02.0.0P-R-2.0.0Prod-Release-2.0.0b1s5-2.0.02.0.0v2
Dev Beta 1.2.3 456Beta 1.2.3 4561.2.3D-B-1.2.3Dev-Beta-1.2.3b2s3-1.2.31.2.3-2+456none
Dev Pre-Alpha 0.1.0Pre-Alpha 0.1.00.1.0D-PA-0.1.0Dev-Pre-Alpha-0.1.0b2s1-0.1.00.1.0-0none
Pub Alpha 0.8.0 a7d3c1fAlpha 0.8.0 a7d3c1f0.8.0Pb-A-0.8.0Pub-Alpha-0.8.0b4s2-0.8.00.8.0-1+a7d3c1fnone

A software organization

2026 © All Rights Reserved.

  • All the content is available under CC BY-SA 4.0, expect where otherwise stated.

Last updated on