Dicey Table

Engine compatibility

The manifest's compatibility.engine string (see Manifest reference § compatibility) is checked against the running engine version at scan time by isCompatibleEngineRange() (packages/shared/src/modManifest.ts). Read this page before writing anything more elaborate than ">=X.Y <A.B" — it is not semver, and it fails silently in a specific, surprising way.

The current engine version#

At scan time (apps/server/src/githubScanner.ts), the engine is "0.1.0". This is a hard-coded server constant, not a manifest field.

The actual grammar#

isCompatibleEngineRange(range, engineVersion) does not parse semver ranges, npm-style caret/tilde ranges, or any established range syntax. It looks for exactly two optional, independent regex tokens anywhere in the string:

Token Regex Meaning
Lower bound />=\s*(\d+)\.(\d+)/ Engine's major.minor must be >= this.
Upper bound /<\s*(\d+)\.(\d+)/ Engine's major.minor must be < this (strictly).

Both are optional and independently matched — order in the string doesn't matter, and there's no requirement that both be present.

Patch versions are ignored completely, on both sides. engineVersion.split(".") only reads the first two parts (major, minor); the regexes themselves only ever capture two digit groups, so writing "<1.0.5" captures major=1, minor=0 from the substring 1.0 and silently drops .5.

If neither token is found in the string — no >=X.Y and no <A.B substring anywhere — the function has nothing to check, skips both conditionals, and falls through to return true. It matches the current engine version unconditionally, regardless of what the string actually says.

What parses correctly#

compatibility.engine Behavior against engine 0.1.0
">=0.1 <1.0" Compatible. Requires major.minor in [0.1, 1.0). This is the form every mod in this repo uses (mods/example).
">=0.1" Compatible, and stays compatible forever — no upper bound means a mod declaring this is claiming to work with every future engine version, which is almost never actually true.
"<1.0" Compatible. No lower bound — a mod declaring only this claims to work with engine 0.0.0 too.
">=0.5 <0.9" Incompatible with 0.1.0 (fails the lower bound) — a real, correctly-enforced rejection.

What silently matches everything#

None of the following contain a literal >= or < followed by \d+\.\d+ — so all of them return true for any parseable engine version, which is almost certainly not what the author intended:

  • "^0.1" — caret ranges are not implemented; this string has no >=/< substring at all.
  • "~0.1.0" — tilde ranges are not implemented either.
  • "1.x", "*", "latest", "any" — none match either token.
  • "0.1.0" (a bare version, no comparator) — also matches everything, because there's no >= or < character in it.

This means a mod author who writes "compatibility.engine": "^0.1" — reasonable-looking npm-style shorthand — gets no compatibility check at all, and will not find out until the engine changes in a way that actually breaks their mod. The scanner will happily report compatible for every future engine version.

Always write an explicit, closed range with both bounds:

"compatibility": { "engine": ">=0.1 <1.0" }

This is exactly what DiceyTable's own reference mod (mods/example) declares, and it's the only form that behaves the way it reads: compatible with engine versions from 0.1 (inclusive) up to, but not including, 1.0.

See also#