Version Matching

We have several places in Volity where we'd like to ensure that two subsystems are following "the same protocol", in some sense:

In theory this matching relation is symmetrical: the UI file and the referee have to agree on what RPCs they are flinging back and forth. In practice, we find asymmetries, and I'm okay with exploiting them. So we will say that one party provides a protocol, and the other party requires it.

Guidelines of thumb:

The bit that PROVIDES a protocol:

The bit that REQUIRES a protocol:

This leaves us with the determination that a referee PROVIDES a ruleset version and a UI file REQUIRES it. We have long had the notion that a referee announces a single ruleset version (see the parlor disco information), so we add one more rule:

On purely syntactic matters: we'd like both version numbers and version specs to be representable as simple strings. In fact, we'd like to be able to slap either one onto a URI as a fragment string, so that we can say that a Fluxx referee provides "http://volity.org/games/fluxx#2.0". (Not all version numbers will be versions of a URI, but many will be.)

Therefore, I am proposing the following (very pedantic) formats. Pardon my not-exactly-BNF definitions.

Spec

(Note: not all version numbers in the Volity universe have to follow this format. This is the Volity standard for version numbers that one software component wishes to use to validate its compatibility with another software component. Version numbers intended for human eyes, like Gamut's version number, may use or ignore this format.)

  VERSION-NUMBER: 
      MAJOR
    | MAJOR "." MINOR
    | MAJOR "." MINOR "." RELEASE

  MAJOR: [1-9] [0-9]*    (that is, a plain positive integer)
  MINOR: MAJOR | "0"     (that is, a plain non-negative integer. If not given, "0" is assumed)
  RELEASE: [a-zA-Z0-9_.+-]+  (that is, any nonempty string you like with those characters)

The intent (and the convention that version specs rely on) is that the major version number describes changes that break forwards and backwards compatibility. The minor version number describes changes that break forwards compatibility, but are backwards-compatible. The release number (which can include periods, so it can cover multiple dot-separated "numbers") is provided for the protocol designer's whim; it is ignored by the version-matching rules.

The example: A referee is written which PROVIDES version "2.3" of its ruleset. A UI is then written which REQUIRES that one version number.

If the referee is updated to PROVIDE version "2.4", the UI should continue to work with it. Or rather, the converse is true: a referee change that allows the old UI to continue working should be given a minor version number change.

On the other hand, you would not expect the UI to work with the previous referee "2.2". (The reason that the UI is labelled as REQUIRING version "2.3" is that it needs referee features that did not exist in "2.2".) Similarly, the UI would be presumed not to work with referee version "2", because that version number is equivalent to "2.0", which is an earlier minor version.

The UI would certainly not work with referee "1.0", nor with referee "3.0", because those represent complete protocol breaks.

Despite all the above, a UI could be be compatible with multiple version numbers. Thus we define:

  VERSION-SPECIFICATION:
      ""
    | PATTERN-LIST

  PATTERN-LIST:
      PATTERN
    | PATTERN "," PATTERN-LIST

  PATTERN:
      PATTERN-NUMBER
    | PATTERN-NUMBER "-"
    | "-" PATTERN-NUMBER
    | PATTERN-NUMBER "-" PATTERN-NUMBER
    | MAJOR "." MINOR "."

  PATTERN-NUMBER:
      MAJOR
    | MAJOR "." MINOR

To restate in English: a specification is a comma-separated list of zero or more patterns. If the list is empty, the specification matches all versions. Otherwise, the specification matches any version that matches any pattern in the list.

In accordance with the semantics described above, a pattern like "2" will match any version whose major number is 2. A pattern like "2.3" will match any version whose major number is 2 and whose minor number is 3 or more. (Note that "2" and "2.0" are equivalent.)

The other pattern formats let you bypass the usual semantics, if you really need to. A pattern "1.5-3.2" matches major number 1 (minor number 5 or higher); all versions with major number 2; and major number 3 (minor number 0, 1, or 2). This is equivalent to "1.5,2,3-3.2".

A pattern "2.3-" will match major number 2 (minor number 3 or higher), and all versions with major numbers 3 or higher. (This is an ambitious claim to make!)

The special form "2.3." (with trailing period) matches major number 2 and minor number 3, and no other values. This is equivalent to "2.3-2.3".

A version number's release value is ignored by the matching rules. A version specification never contains a release value.

Sorting

Version numbers have an ordering. (Version specs do not!)

The major and minor values provide the first and second-level sort. (Recalling that "2" implicitly has minor value 0, so is equivalent to "2.0".)

That's all you need to use version specs. However, it may be desirable to sort on the release value also. To do this: