# Meridian: Enterprise Unique Identifier (EUID) Specification

[![Version](https://img.shields.io/badge/version-0.2.0pre-blue?style=flat-square)](https://github.com/lsmc-bio/meridian-euid/tags)

## Status of This Document

This document defines the Meridian Enterprise Unique Identifier (EUID) format, canonical representation, and validation rules.

This is a draft public standard. Implementations MAY adopt it, but implementers should expect clarifications and editorial corrections in future revisions.

The normative requirements of this specification use the terms **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, and **MAY** as described in RFC 2119.

## 1. Scope

An EUID is a compact, scan-reliable identifier intended to label and reference physical and logical entities across an enterprise, including use in printed labels and barcodes.

This specification defines:

- Syntax for production and sandbox EUIDs.
- The canonical Crockford Base32 alphabet and character rules.
- Canonicalization and validation rules.
- A single-character MOD 32 checksum and its computation.

This specification does not define:

- How categories are assigned, governed, or interpreted.
- Issuance workflows, storage models, or any database schema (see Section 9 for non-normative guidance).
- Authorization rules beyond the environment segregation described in Section 5.

## 2. Problem Statement

Enterprise systems often need identifiers that are (a) short enough for labels, (b) readable and transcribable by humans, (c) safe to move across common tools (CSV, spreadsheets, tickets), and (d) robust against transcription and scanning errors.

Meridian EUIDs address these constraints by combining:

- A fixed structure suitable for labeling.
- Explicit separation between production and sandbox namespaces.
- A trailing checksum to detect common input errors.
- An explicitly non-semantic design: all meaning is obtained by database lookup.

## 3. Design Goals and Non-Goals

### 3.1 Goals

A conforming Meridian EUID system:

- MUST support printing and scanning on typical laboratory and industrial label sizes.
- MUST be representable as plain ASCII without whitespace.
- MUST provide strong syntactic separation between production and sandbox identifiers.
- MUST include a checksum character that detects common input errors.
- MUST be opaque and immutable once issued.

### 3.2 Non-Goals

- EUIDs are not intended to embed metadata, routing, permissions, or workflow state.
- EUIDs are not intended to replace existing industry identifiers (for example GS1 GTIN) when those are required by external partners or regulators.

## 4. Terminology

- **Canonical form**: The exact string form specified by this document.
- **Production EUID**: An EUID in the production namespace.
- **Sandbox EUID**: An EUID in a sandbox namespace, indicated by a sandbox prefix and delimiter.
- **Issuer**: A software system that generates new EUIDs.
- **Relying system**: Any system that accepts, stores, displays, or transmits EUIDs.

Required identity statement (normative text for repo-wide reuse):

> Meridian does not use UUIDs. Internal identity is sequence-based. External identity is EUID-based.

## 5. Namespaces and Environments

Meridian defines two disjoint top-level namespaces:

- **Production**: For operational entities.
- **Sandbox**: For testing, integration, validation, and rehearsal.

The namespaces are intentionally and unambiguously distinct at the string level.

A relying system:

- MUST reject sandbox EUIDs in production-only contexts.
- MUST reject production EUIDs in sandbox-only contexts.

Within the sandbox namespace, the sandbox prefix identifies a sub-namespace.

A relying system operating within a specific sandbox:

- MUST reject sandbox EUIDs whose sandbox prefix does not match the configured sandbox prefix (or configured allowed set).

## 6. Syntax

### 6.1 Grammar (authoritative)

An EUID has the form:

`[SANDBOX ":"] CATEGORY "-" BODY CHECKSUM`

Where:

- `SANDBOX`: optional, single letter.
- `CATEGORY`: 2–3 letters, canonical alphabet only.
- `BODY`: Crockford Base32 encoding of a sequence-allocated integer.
- `CHECKSUM`: exactly 1 Crockford Base32 character.

Delimiters:

- `-` MUST appear exactly once.
- `:` MAY appear zero or one times.
- If present, `:` MUST precede `-`.

### 6.2 Canonical alphabet and forbidden characters

Canonical alphabet (Crockford Base32):

`0123456789ABCDEFGHJKMNPQRSTVWXYZ`

Forbidden everywhere (must not appear in any EUID, payload, or example):

`I`, `L`, `O`, `U`

### 6.3 Component constraints

Sandbox prefix constraints:

- The letters `A` through `G` (inclusive) are permanently reserved and MUST NOT be used as sandbox prefixes.
- Sandbox prefixes MUST be uppercase letters in the canonical alphabet (and thus also MUST NOT be any forbidden character).
- Available sandbox prefixes: `H`, `J`, `K`, `M`, `N`, `P`, `Q`, `R`, `S`, `T`, `V`, `W`, `X`, `Y`, `Z` (15 letters).

Category constraints:

- Categories MUST be uppercase letters from the canonical alphabet.
- Categories MUST be 2 to 3 characters.

Body constraints:

- BODY MUST be the Crockford Base32 encoding of a positive integer.
- BODY MUST be unpadded and MUST NOT contain leading zeros in its Base32 representation.
  - Therefore, BODY MUST NOT begin with `0`.

### 6.4 Canonical regexes (canonical form)

The following regexes describe the canonical (already-normalized) forms.

Let `ALNUM32 = [0-9A-HJ-KMNP-TV-Z]` (Crockford Base32, excluding forbidden letters).
Let `LETTERS32 = [A-HJ-KMNP-TV-Z]`.
Let `SANDBOX32 = [HJ-KMNP-TV-Z]` (letters32 excluding reserved `A`–`G` and forbidden `I`).

Production EUID (no sandbox prefix):

- `^LETTERS32{2,3}-([1-9A-HJ-KMNP-TV-Z]ALNUM32*)ALNUM32$`

Sandbox EUID:

- `^SANDBOX32:LETTERS32{2,3}-([1-9A-HJ-KMNP-TV-Z]ALNUM32*)ALNUM32$`

Syntax validation MAY be implemented via these canonical regexes or via equivalent structural parsing. Both approaches are conforming.

## 7. Checksum

### 7.1 Purpose

The checksum is intended to detect common errors in manual transcription, copy/paste, OCR, and barcode scanning.

### 7.2 Character-to-value mapping (Crockford Base32)

Each character maps to its index in the canonical alphabet:

`0123456789ABCDEFGHJKMNPQRSTVWXYZ`

So `0 → 0`, `1 → 1`, ..., `9 → 9`, `A → 10`, ..., `Z → 31` (skipping forbidden letters).

Implementations MUST reject any character outside the canonical alphabet.

### 7.3 Checksum payload

Checksum payload is:

`[SANDBOX?] + CATEGORY + BODY`

The delimiters `:` and `-` are excluded from checksum computation.

### 7.4 Checksum type

Meridian uses a single-character MOD 32 checksum aligned to the canonical alphabet.

### 7.5 Luhn-style MOD 32 algorithm (normative)

Given a non-empty checksum payload string `payload` consisting only of characters in the canonical alphabet:

1. Initialize `sum = 0`.
2. Process `payload` from right to left.
3. For the rightmost character of `payload`, use factor `2`, then alternate factors `1, 2, 1, 2, ...` moving left.
4. For each character:
   - Map the character to value `v` in the range 0..31.
   - Compute `p = v * factor`.
   - Add the base-32 digit-sum of `p` to `sum`:
     - `sum += floor(p / 32) + (p mod 32)`
     - (Because `factor` is 1 or 2, this is equivalent to `sum += p` when `p < 32`, else `sum += p - 31`.)
5. Compute `check_value = (32 - (sum mod 32)) mod 32`.
6. Map `check_value` back to a character using the canonical alphabet. This is `CHECKSUM`.

Verification:

- An EUID is checksum-valid if the computed CHECKSUM equals the presented CHECKSUM.

## 8. Canonicalization and Validation

### 8.1 Canonicalization

Issuers MUST output canonical uppercase form.

Validators MUST reject any input containing lowercase ASCII letters. No case normalization is permitted.

Validators MUST NOT apply visual substitutions (for example, MUST NOT rewrite `O` to `0`).

Whitespace (leading, trailing, or internal) MUST NOT be accepted.

Non-ASCII input MUST be rejected.

### 8.2 Validation order

A relying system that accepts EUID input MUST validate in the following order:

1. **Input rejection** — reject non-ASCII, whitespace, and lowercase characters.
2. **Syntax validation** — confirm the string matches the expected structure for the environment (production or sandbox), including delimiter rules and component constraints. This step MAY be implemented via the canonical regexes in Section 6.4 or via equivalent structural parsing.
3. **Checksum verification** — compute the check character per Section 7 and compare to the presented checksum.
4. **Existence and authorization checks**, if applicable to the system.

Failure at any step MUST result in immediate rejection.

## 9. Issuance Model (Non-Normative Guidance)

Meridian does not use UUIDs. Internal identity is sequence-based. External identity is EUID-based.

Implementations SHOULD treat the integer encoded in BODY as an opaque, monotonically increasing identifier allocated by a sequence (for example, a PostgreSQL sequence-backed BIGINT).

EUIDs MUST NOT embed semantics or meaning beyond the category prefix; all meaning MUST be obtained by database lookup.

## 10. Issuance Requirements

Issuers MUST comply with the following:

- Only software systems MAY issue EUIDs.
- Humans MUST NOT create, modify, or assign EUIDs.
- EUIDs MUST be immutable once issued.
- EUIDs MUST NOT be reused.

A deployment MAY use multiple issuers, but then all issuers MUST be engineered to avoid collisions across the full namespace (including production and sandbox prefixes).

### 10.1 Prohibition on embedding external identifiers

EUIDs MUST be opaque. Therefore, an issuer MUST NOT embed, encode, or derive any portion of an EUID from any external identifier system (for example: partner laboratory sample IDs, vendor part numbers, accession numbers, regulatory identifiers, or identifiers from external databases).

This prohibition applies to all components:

- `CATEGORY` MUST NOT be selected to encode an external identifier system, external organization, external site, or any external business semantics.
- `BODY` MUST NOT be computed from, hashed from, or otherwise deterministically derived from any external identifier.
- `CHECKSUM` MUST be computed only as specified in Section 7 and MUST NOT be used as a carrier of additional information.

Rationale: external identifier schemes change over time, can be reassigned, can leak business context, and can create hidden coupling between systems. Keeping EUIDs opaque ensures that issued identifiers remain stable and valid regardless of changes in external identifier systems.

### 10.2 Global uniqueness and authoritative issuance

EUIDs in the production namespace MUST be globally unique across the enterprise, not merely unique within a single site, deployment, or database.

To prevent collisions, an enterprise Meridian deployment MUST designate a single logical **Online Authority** (also called a **Central Registry**) that is authoritative for EUID issuance.

All issuer systems MUST coordinate with the Online Authority for issuance such that no two issuers can issue the same EUID. The Online Authority MUST enforce uniqueness using a mechanism that provides enterprise-wide collision avoidance (for example, transactional allocation with a uniqueness constraint).

Issuance MUST be site-agnostic:

- An EUID issued at one location MUST be valid and recognized at all locations within the enterprise.
- Relying systems MUST NOT require knowledge of the issuance site to interpret or validate an EUID.

### 10.3 External identifiers as observations with provenance

External identifiers (for example: vendor IDs, partner lab IDs, regulatory accession numbers) MUST be treated as mutable observations about an entity identified by an EUID, not as properties of the EUID itself.

Accordingly:

- Relying systems SHOULD store external identifiers as separate attributes linked to an EUID.
- Relying systems MUST be able to update, supersede, or retract external-identifier mappings without changing the EUID.

When a system stores a mapping between an EUID and an external identifier, the mapping record MUST include provenance metadata sufficient to support audit and reconciliation, including:

- Who or what system asserted the mapping
- When the mapping was asserted
- The source system and/or source record from which the external identifier was obtained
- A confidence or verification status appropriate to the domain

### 10.4 Mapping semantics (one-to-many and many-to-one)

Relying systems MUST NOT assume a 1:1 relationship between EUIDs and external identifiers.

In particular:

- A single EUID MAY map to multiple external identifiers (one-to-many), for example when an entity is represented in multiple partner systems.
- Multiple EUIDs MAY map to the same external identifier (many-to-one), for example when multiple aliquots or derived entities are associated with a single upstream vendor identifier.

Non-normative guidance for implementations:

- Database schemas typically model external identifiers as a separate table or collection and represent the relationship as a link table (or repeated field) rather than a unique column on the EUID record.
- APIs typically represent external identifiers as a list of objects (system, value, provenance) rather than a single string field.

## 11. Use on Labels and Barcodes

This section provides interoperability requirements for physical labeling.

- If an EUID is encoded in a barcode, the encoded data MUST include the checksum character.
- A label that is intended to be machine-scanned for identification SHOULD NOT include additional scannable identifiers that could be mistaken for the EUID.

Barcode symbology is out of scope. Common acceptable symbologies include Code 128 and DataMatrix ECC200.

## 12. Operational Role of Structural Components

CATEGORY and SANDBOX exist solely as structural elements for validation and environment segregation. They function as one layer in a swiss-cheese error detection model: their role is limited to triggering rejection of malformed or mis-routed identifiers.

Relying systems and issuers:

- MUST NOT use CATEGORY or SANDBOX for routing, workflow decisions, or metadata inference.
- MUST NOT treat CATEGORY as a classification system, entity type indicator, or organizational identifier.
- MUST NOT treat SANDBOX prefix as anything other than an environment segregation marker.

All operational meaning associated with an EUID MUST be obtained by database lookup against the authoritative registry. The structural components exist to catch errors early, not to carry information.

External identifiers (for example: vendor IDs, partner lab IDs, regulatory accession numbers) MAY be stored as metadata associated with an EUID, but they are not globally unique within the Meridian namespace and MUST NOT be used in lieu of the EUID for identification. Co-printing external identifiers on physical labels alongside the EUID is a labeling concern outside the scope of this specification.

## 13. Prohibited Practices

Relying systems and issuers MUST NOT:

- Infer behavior or metadata from EUID structure.
- Reuse or reassign EUIDs.
- Strip or rewrite sandbox prefixes.
- Auto-correct malformed identifiers.
- Accept sandbox EUIDs in production-only contexts.
- Accept production EUIDs in sandbox-only contexts.

## 14. Change Control

Any change to any of the following MUST be treated as a breaking change and requires a new major version:

- Regexes and component constraints
- Environment segregation rules
- Checksum algorithm or checksum scope
- Canonical alphabet or forbidden-character rules

## 15. Prior Art and Related Standards (Non-Normative)

Meridian EUIDs intentionally reuse known patterns rather than inventing new primitives:

- **ISO/IEC 7064** provides the checksum algorithm family used for error detection.
- **Crockford Base32** provides the encoding alphabet optimized for human readability and scan reliability.
- **GS1 identifier systems** are widely deployed examples of prefix-based identifiers with check digits and operational governance.
- **ISO/IEC 7812** provides precedent for structured identifiers that include issuer-identifying prefixes and check digits.

## 16. Checksum Error Detection Properties (Non-Normative)

The Luhn-style MOD 32 checksum (Section 7.5) provides the following error detection properties:

| Error type | Detection rate | Notes |
|---|---|---|
| Single character substitution | 100% | Any single-character change is always detected |
| Adjacent character transposition | ~96.8% | Undetected only when both swapped characters have the same value (a no-op) |
| Random multi-character corruption | ~96.9% | Checksum behaves as a roughly uniform hash mod 32 |

**False negative rate (valid EUID incorrectly rejected): exactly 0%.** The algorithm is deterministic. A correctly formed EUID will always pass checksum verification.

**False positive rate (corrupted EUID incorrectly accepted): ~3.1% for multi-character errors.** For single-character substitutions, the false positive rate is 0%.

These properties are comparable to Luhn mod 10 (used in credit card numbers) but operate over a larger alphabet (32 vs 10 symbols).

## Appendix A. Examples (Non-Normative)

See `test-vectors/v2.json` for machine-verified examples used by the reference implementations.

## Appendix B. Motivating Implementation Example (Non-Normative)

The `daylily-tapdb` project is an example of a graph database that uses EUIDs as stable node identifiers to support lineage and relationship queries. It is not a dependency of this specification.

## Appendix C. Issuing Authority Governance (Informational)

Enterprises deploying Meridian EUIDs typically need a governance layer that defines which categories exist, which systems are authorized to issue EUIDs for each category, and how issuing authority configurations are discovered by relying systems.

This specification intentionally does not define governance mechanisms (see Section 1, Scope). Category assignment, issuing authority registration, and authority discovery are enterprise deployment concerns that vary by organization and infrastructure.

The [`meridian-euid-governance`](https://github.com/lsmc-bio/meridian-euid-governance) repository provides a **non-normative reference governance profile** that uses S3-based Issuing Authority Directories (IADs) with JSON descriptors. It is not a dependency of this specification and is not required for conformance.
