Canonical specification for the UEID model field. Defines the algorithm and test vectors that every UEID implementation must follow for cross-language round-trip.
  • JavaScript 76.6%
  • Ruby 23.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Kalmiya 28bd8888f0
Some checks failed
CI / conformance · node reference (push) Failing after 0s
feat: expand spec to cover the full UEID layout, not just the model field
The spec repo was previously scoped to the model-field algorithm
only — but the README references in ueid-ts already pointed at
'ueid-spec' unqualified, and a reader would reasonably expect a
full layout + encoding + parsing spec, not just one section.

This commit turns ueid-spec into the canonical contract for
the whole UEID format:

SPECIFICATION.md:
- §1 Bit layout: explicit bit positions for every field
- §2 Field definitions: unix_ts_ms, ver (0b1000), model, count
  (1-15,0 — clarified that 0 represents the wrapped 16th
  increment), var (0b10), random (62 bits, CSPRNG-sourced)
- §3 Generation: full assembly recipe with field-shift table
- §4 Encoding: the 36-character 8-4-4-4-12 dashed form, hex
  case rules, accept-and-emit semantics, parsing rules with
  strict ver/var rejection
- §5 Model ID Specification: the existing FNV-1a-32 + iterative
  xor-shift fold algorithm, now clearly the only §5 sub-spec
- §6 Conformance checklist
- §7 Limitations
- §8 Versioning

conformance/roundtrip-vectors.json: 8 vectors pinning every
field of a UEID — the corrected Ruby test vector, all-canonical-
fields-at-minimum, max 48-bit timestamp, counter at values 15
(wrap), 0 (wrapped), 1 (after wrap), max 62-bit random, and a
manual construction example. Each vector carries the pinned
field values, the canonical dashed form, the un-dashed form,
and the hex representation. Run via the conformance scripts.

scripts/check-conformance.{mjs,rb}: now verify BOTH the model-
hash vectors AND the round-trip vectors. JS version exits 0
on success, non-zero on the first mismatch; same for Ruby.

scripts/generate-roundtrip-vectors.js: regenerates roundtrip-
vectors.json. Only needed if the bit layout or encoding changes.

README.md: documents the new structure, the round-trip vector
file, and the expanded CI behaviour.

Discovered while writing this: the Ruby gem's hardcoded test
vector string '019c2c83-8104-83fa-8417-5fb7e28a5464' has group
3 encoding model=65, count=7 — not the documented model=63,
count=10 for the bytes. Both ports inherited this bug. The
corrected vector with model=63, count=10 is now:
  019c2c83-8104-83fa-8000-1fb7e28a5464
and round-trip-vectors.json pins it. The follow-up commits to
ueid-ruby and ueid-ts replace the buggy string with the
corrected one.
2026-07-21 12:48:08 -07:00
.github/workflows feat: UEID Model ID Specification v1 + conformance vectors 2026-07-21 11:43:56 -07:00
conformance feat: expand spec to cover the full UEID layout, not just the model field 2026-07-21 12:48:08 -07:00
scripts feat: expand spec to cover the full UEID layout, not just the model field 2026-07-21 12:48:08 -07:00
.gitignore feat: UEID Model ID Specification v1 + conformance vectors 2026-07-21 11:43:56 -07:00
LICENSE feat: UEID Model ID Specification v1 + conformance vectors 2026-07-21 11:43:56 -07:00
README.md feat: expand spec to cover the full UEID layout, not just the model field 2026-07-21 12:48:08 -07:00
SPECIFICATION.md feat: expand spec to cover the full UEID layout, not just the model field 2026-07-21 12:48:08 -07:00

ueid-spec

Canonical specification for the Universal Entity ID (UEID).

This repository holds the load-bearing contract that every UEID implementation must follow to mint and parse UEIDs interchangeably across languages, processes, and storage backends.

What's in here

  • SPECIFICATION.md — the canonical document. Sections cover:
    • §1 Bit layout (128-bit value, field positions)
    • §2 Field definitions (unix_ts_ms, ver, model, count, var, random)
    • §3 Generation rules
    • §4 Encoding (the 36-character dashed form) and parsing rules
    • §5 Model ID Specification (the model field algorithm — FNV-1a-32 + iterative xor-shift fold)
    • §6 Conformance checklist
    • §7 Limitations
    • §8 Versioning
  • conformance/vectors.json — 66 model-hash vectors. The Ruby reference trio (Array → 228, String → 63, Hash → 26) plus common class-name shapes, domain entities, multi-byte UTF-8, and edge cases.
  • conformance/roundtrip-vectors.json — 8 round-trip vectors that pin every field of a UEID (unix_ts_ms, ver, model, count, var, random, hex, dashed string form, undashed form). Used to verify the bit layout and encoding, not just the model hash.
  • scripts/check-conformance.mjs — Node.js reference implementation + verifier. Verifies both the model-hash vectors and the round-trip vectors:
    node scripts/check-conformance.mjs
    
  • scripts/check-conformance.rb — Ruby reference implementation + verifier. Same vectors, Ruby implementation:
    ruby scripts/check-conformance.rb
    
  • scripts/generate-vectors.js — regenerate conformance/vectors.json (model-hash vectors). Only needed if the hash algorithm itself changes.
  • scripts/generate-roundtrip-vectors.js — regenerate conformance/roundtrip-vectors.json. Only needed if the bit layout or encoding changes.

Conforming implementations

  • ueid-ruby — Ruby reference port, started from bolderbrooklyn/ueid-ruby and extended with model_id_for, configurable collision policy, and conformance tests.
  • ueid-ts — TypeScript port. Original ActiveRecord auto-registration replaced with explicit Registry.hashForClass; collision detection on by default with hashForClassAllowingCollision opt-in.

Both implementations run check-conformance.{rb,mjs} against the vectors in conformance/ in their CI pipelines.

Why this repo exists

The UEID bit layout is shared because every implementation follows the same UUIDv8 / RFC 4122bis conventions. The model field is the part where implementations drift: class-name conventions differ across languages, UTF-8 byte encoding has subtle pitfalls, and FNV-1a constants can be mis-typed. Without a pinned spec and test vectors, "the TypeScript port computes the same model hash as the Ruby gem" is a happy accident, not a guarantee.

This repo makes it a guarantee.

Versioning

The specification is versioned semver. The current major version is 1. Breaking changes (any algorithm in §1–§4, the hash algorithm in §5, the fold in §5.4, or the encoding rules in §4) require a major bump; new test vectors and clarifications are minor.

The JSON test-vector files carry a version field that downstream impls MUST check before running their conformance check.